Passing a struct as a parameter in System Verilog - system-verilog

The following code works fine under Modelsim when the unused localparam is removed. It produces the error below if it is left in. If it is possible to use a struct to pass parameters to a module, what am I doing wrong? Many thanks.
typedef bit [7:0] myarr[2];
typedef struct { int a; myarr bytes; } mystruct;
module printer #(mystruct ms)();
// works fine if this is removed
localparam myarr extracted = ms.bytes;
initial
$display("Got %d and %p", ms.a, ms.bytes);
endmodule
parameter mystruct ms = '{ a:123, bytes:'{5, 6}};
module top;
printer #(.ms(ms)) DUT ();
endmodule
Here is the error. Compilation using vlog -sv -sv12compat produces no errors or warnings.
$ vsim -c -do "run -all; quit" top
Model Technology ModelSim - Intel FPGA Edition vlog 10.5c Compiler 2017.01 Jan 23 2017
(.......)
# ** Error: (vsim-8348) An override for an untyped parameter ('#dummyparam#0') must be integral or real.

I think the problem here is that you are assigning a whole unpacked array in one statement, which is not allowed. Try changing the myarr typedef to a packed array instead.

My workaround was to use a packed array. I didn't need to pack the whole struct.
I would happily upvote/accept someone else's answer if one appears. In particular, it would be helpful to confirm whether this is really a bug in Modelsim, or just an instance of a correct compilation error that could be made more helpful by including the location and parameter name.

Related

Connect different port width

Suppose my module has a 8-bit input and 8-bit output
module MyModule (input logic [7:0] in, output logic [7:0] out);
...
endmodule : MyModule
If I want to connect a 1-bit input in and leave the other bits as zero, the following works:
MyModule (.in({7'b0, a}), .out(b))
How can I do the same if I want a 1-bit output, ignoring the other bits? Something like this
MyModule (.in(a), .out({7'b0, b}))
vcs says its invalid, and connecting b directly gives a warning. I'd ideally like a solution that doesn't throw warnings.
Here's what I've thought of:
Use .out(b) and use b[0] for bit
Create unused logic variable unused and use .out({unused, b}) which does work
Use assign statment (I'd like to avoid this)
Any solution better than these?
You could use the streaming operator:
MyModule M (.in(a), .out({<<{b}}));
But I think your first idea is the most straightforward.
You might also use parameterized modules:
module MyModule #(IN_WDT = 8, OUT_WDT = 8)
(input logic[IN_WDT-1:0] in, output logic [OUT_WDT -1 : 0] out);
...
MyModule #(8,1) M1(a8, b1);
or
MyModule #(.OUT_WDT(1)) M1(.in(a8), .out(b1));

How do I sign extend in SystemVerilog?

Below is the code I have for my module:
module sext(input in[3:0], output out[7:0]);
always_comb
begin
if(in[3]==1'b0)
assign out = {4'b0000,in};
else
assign out = {4'b1111,in};
end
endmodule
For some reason this is not working. Instead of sign extending it is zero extending. Any ideas to why this might be the case?
I'm going to assume you meant (input [3:0] in, output [7:0] out). If that is true, then all you needed to write is
module sext(input signed [3:0] in, output signed [7:0] out);
assign out = in;
endmodule
You could also write
module sext(input [3:0] in, output [7:0] out);
assign out = 8'(signed'(in));
endmodule
And perhaps you don't even need to write this as a separate module.
Few things you need to take care is,
you haven't declared a data type for in and out, so by default they are wire and wire can't be used at LHS inside procedural block. Refer Section 6.5 Nets and variables (SV LRM 1800-2012). So either use a continuous assignment or declare it as a variable (i.e. reg/logic etc.).
The assignment of unpacked array is illegal in your example, so either use packed array or follow the instructions given in Section 10.10 Unpacked array concatenation (SV LRM 1800-2012)
It is not illegal syntax but assign used inside an always block probably does not do what you think it does. Use assign for wires and do not use it inside initial or always.
You have defined your port ranges after the name, this results in 4 and 8 1-bit arrays rather than a 4 and 8 bit value.
You have used {} for concatination, but they can also be used for replication ie {4{1'b1}}.
module sext(
input [3:0] in,
output reg [7:0] out ); //ranged defined before name
//No assign in always
//concatenation with replication
always_comb begin
out = { {4{in[3]}}, in};
end
endmodule
Or :
module sext(
input [3:0] in,
output [7:0] out ); //out left as wire
assign out = { {4{in[3]}}, in};
endmodule
I have seen your code.
There are some mistake in your code that you have to take care whiling writing the code.
You have use unpacked array so your targeted elements and actual elements are not match.
ERROR : Number of elements in target expression does not match the number of
elements in source expression.
This error can solve by using packed array.So, your targeted elements and actual elements are matched.
Here is link from where you will get better understanding regarding packed and unpacked array.
LINK : [http://www.testbench.in/SV_09_ARRAYS.html][1]
2.Another thing that you have to take care is you are storing some value in out signal(variable) like assign out = {4'b0000,in};
So you have to use reg data type to sore the value.
ERROR : Non reg type is not valid on the left hand side of this assignment
When you use reg data type then you can store value in out data type.
So, your problem is solved.
Here I also provide code which will run fine.
module sext(input [3:0]in, output reg [7:0]out);
always_comb
begin
if(in[3]==1'b0)
assign out = {4'b0000,in};
else
assign out = {4'b1111,in};
end
endmodule

How to pass a class between two modules?

I have two modules and a class and I would like to move that class from one module to the other. Something like this:
class foo;
int x;
int y;
endclass
module mod_A(output foo foo_inst, output event trig);
initial begin
foo my_foo = new;
my_foo.x = 1;
my_foo.y = 2;
foo_inst = my_foo;
->trig;
end
endmodule
module mod_B(input foo foo_inst, input event trig);
always #(trig) begin
$display("%d%d, is a funky number.", foo_inst.x, foo_inst.y);
end
endmodule
module top();
event trig;
foo foo_inst;
mod_A mod_A(.trig, .foo_inst);
mod_B mod_B(.trig, .foo_inst);
endmodule
Of course there're also some functions defined in the class which are used in each module.
The issue with this setup is that I'm seeing errors for each ports of mod_B:
Error-[RIPLIP] Register in low conn of input port
Non-net variable 'foo_inst' cannot be an input or inout port.
Non-net variable 'trig' cannot be an input or inout port.
EDAplayground does not support class objects as module ports and 1800-2012 only mentions interface declarations, events, arrays structures or unions in Port declarations (23.2.2) so my questions are:
Is it even legal to pass classes through ports? If not, what is an elegant
method of accomplishing this?
What does "Register in low conn of
input port" mean? I'm aware that this might be a compiler specific
error and nothing indicative but if I knew what it was trying to tell me I might be a step closer to fixing this.
A variable of any type can be an input or output port. You might have to write for your compiler
input var foo foo_inst,
But it would be better to use a ref when a port is really a handle.
module mod_A(ref foo foo_inst, ref event trig);
Note that you have a typo with foo_o or foo_inst and a race condition between a trigger ->trig and an event control #(trig).

C programming error when building and running

Im following a youtube tutorial by Bucky in C programming. Every time i use scanf and enter the input i get an error pop up. i typed these exact same codes from the video tutorial but mine does not work.
HERE'S THE CODE:
int main()
{
int age;
printf("How old are you?\n");
scanf("%d, &age");
if (age>= 18){
printf("You may enter this website!");
}
if(age<18){
printf("nothing to see here!");
}
return 0;
}
It only works after compiling and running. But after i input the age, an error window pops up and says "A problem caused the program to stop working correctly. Windows will close the program and notify you if a solution is available."
I'm sure the codes are correct but What is causing this? Help me please so i can move forward.
You placed quote in incorrect place in scanf:
scanf("%d, &age");
should be:
scanf("%d", &age);
C language is limited in a ways to implement functions with variable numbers of arguments (which scanf is, since it's can read variable number of variables from terminal), so this is why such errors are possible.
Modern compilers will warn you about incorrect scanf usage, e.g. GCC will give a warning:
1.c: In function ‘main’:
1.c:8:1: warning: format ‘%d’ expects a matching ‘int *’ argument [-Wformat=]
scanf("%d, &age");
^
By the way, your example misses
#include <stdio.h>

how to get 18 bit code address from symbol defined in linker command file

In Code Composer, you can define new symbols in the linker command file simply:
_Addr_start = 0x5C00;
_AppLength = 0x4C000;
before the memory map and section assignment. This is done in the bootloader example from TI.
You can then refer to the address (as integers) in your c-code as this
extern uint32_t _Addr_start; // note that uint32_t is fake.
extern uint32_t _AppLength; // there is no uint32_t object allocated
printf("start = %X len= %X\r\n", (uint32_t)&_Addr_start, (uint32_t)&_AppLength);
The problem is that if you use the 'small' memory model, the latter symbol (at 0x45C00) gives linker warning, because it tries to cast it to a 16-bit pointer.
"C:/lakata/hardware-platform/CommonSW/otap.c", line 78: warning #17003-D:
relocation from function "OtapGetExternal_CRC_Calc" to symbol "_AppLength"
overflowed; the 18-bit relocated address 0x3f7fc is too large to encode in
the 16-bit field (type = 'R_MSP_REL16' (161), file = "./otap.obj", offset =
0x00000002, section = ".text:OtapGetExternal_CRC_Calc")
I tried using explicit far pointers, but code composer doesn't understand the keyword far. I tried to make the dummy symbol a function pointer, to trick the compiler into thinking that dereferencing it would.... The pointer points to code space, and the code space model is "large" while the data space model is "small".
I figured it out before I finished entering the question!
Instead of declaring the symbol as
extern uint32_t _AppLength; // pretend it is a dummy data
declare it as
void _AppLength(void); // pretend it is a dummy function
Then the pointer conversion works properly, because &_AppLength is assumed to be far now. (When it declared as an integer, &_AppLength is assumed to be near and the linker fails.)