Pass 2D real array to a function in System Verilog - verilog

I am trying to pass 2D real array to an SV function and return the same but I'm not able to execute this task successfully. Here is a simple reproducible code:
module Two_d_array_pass();
real x[2][2]='{'{1.0,2.0},'{3.0,4.0}};
real y[2][2]='{'{2.0,2.0},'{2.0,2.0}};
real z[2][2];
int i,j;
initial begin
foreach(x[i,j]) $display("x[%0d][%0d]=%0f",i,j,x[i][j]);
foreach(y[i,j]) $display("y[%0d][%0d]=%0f",i,j,y[i][j]);
z=mult(x,y);
end
function real mult(x,y);
real c[2][2];
int i,j;
foreach(c[i,j])
c[i][j]=x[i][j]*y[i][j];
return c;
endfunction
endmodule
and here is the error I get:
file: Two_d_array_pass.sv
c[i][j]=x[i][j]*y[i][j];
|
xmvlog: *E,DIMERR (Two_d_array_pass.sv,18|10): Bit-select or part-select dimensions do not match declaration.
c[i][j]=x[i][j]*y[i][j];
|
xmvlog: *E,DIMERR (Two_d_array_pass.sv,18|18): Bit-select or part-select dimensions do not match declaration.
Can anyone correct the code to achieve this task?

You need to change the arguments to be 2x2 dimensional as well.
function real mult(real x[2][2],y[2][2]);
But you also need to do it for the return type, but because of syntax limitations, unpacked array need a typedef for the return type.
typedef real real2x2[2][2];
function real2x2 mult(real x[2][2],y[2][2]);
Then you might as well use the typedef everywhere
module Two_d_array_pass();
typedef real real2x2[2][2];
real2x2 x='{'{1.0,2.0},'{3.0,4.0}};
real2x2 y='{'{2.0,2.0},'{2.0,2.0}};
real2x2 z;
initial begin
foreach(x[i,j]) $display("x[%0d][%0d]=%0f",i,j,x[i][j]);
foreach(y[i,j]) $display("y[%0d][%0d]=%0f",i,j,y[i][j]);
z=mult(x,y);
end
function real2x2 mult(real2x2 x,y);
foreach(x[i,j])
mult[i][j]=x[i][j]*y[i][j];
endfunction
endmodule
P.S. you do not declare the iterating variables i and j separately, they are implicit and local to the scope of the foreach statement. If you declare them separately, they become extra variables unused by the foreach loop.

Related

How do I generate parameters dependent onf previous parameters in systemverilog

I recently switched from VHDL to SystemVerilog and I am converting some of my codes. I want to generate an array of local parameters based on 3 parameters SZ,L,max.
module test #(
parameter int SZ = 1024,
parameter int L = 35,
parameter int MAX = 4
)()
//...
localparam int n[MAX:0] = ;//...
for(genvar i = 0; i < max; i++) begin: gg
//n[i] and n[i+1] will be used here
//There is a second generate loop here that uses n[i+1] and therefore n[i+1] has to be parameter.
end
I tried using a function to generate localparams but I get an error that element assignment in function is not constant. I never had this issue in VHDL.
The only other option I can think of is to create the params inside the for generate but how would I reference the initial value? Is there any other solution?
The simulator I am using is Verilator but I also want the design to work in Xilinx Vivado.
Edit: I do not want to generate the parameters from an external script because I lose the ability to use Vivado's ability to run multiple synthesis/implementation in the same project with different parameters. That was what I used to do in VHDL.
You can use a function to initialize a parameter, you just have to have the output of the entire array as the result of the function. To do that, you need a typedef
typedef int array_type[MAX:0];
function array_type f();
f[0]=SZ;
for(int i=0;i<MAX;i++)
f[i+1]=f[i]-((2*i)+1)*L)/2;
endfunction
localparam array_type n = f();
I got it working by using packed array of 32-bits. Verilator doesn't support unpacked int with constants. Packed int is also not supported so I had to change the type to pack of 32-bits.
typedef [MAX:0][31:0] array_type;
function array_type f();
f[0]=SZ;
for(int i=0;i<MAX;i++)
f[i+1]=f[i]-((2*i)+1)*L)/2;
endfunction
localparam array_type n = f();

How to vary a struct going through a port in system verilog - generate doesnt work

module testy
#(
parameter W = 10,
parameter C = 2
)
(
aa
);
generate
if (W == 8)
begin:W8
if(C == 1)
begin:W8C1
typedef struct {
logic [8:0] so;
}my_struct;
end
if(C == 2)
begin:W8C2
typedef struct {
logic [10:0] so;
}my_struct;
end
end
endgenerate
input my_struct aa;
endmodule
I get this error:
irun(64): 14.20-p001: (c) Copyright 1995-2015 Cadence Design Systems, Inc.
file: testy.v
input my_struct aa;
|
ncvlog: *E,SVNOTY (testy.v,30|14): Syntactically this identifier appears to begin a datatype but it does not refer to a visible datatype in the current scope.
module worklib.testy:v
errors: 1, warnings: 0
ncvlog: *F,NOTOPL: no top-level unit found, must have recursive instances.
irun: *E,VLGERR: An error occurred during parsing. Review the log file for errors with the code *E and fix those identified problems to proceed. Exiting with code (status 2).
I thought generates were statically determined but I have problems compiling it - since parameters cant be overridden in packages and couldn't think of a way to do this in design which needs to be synthesized and didn't want to add interfaces or classes. Is there a bettwe way to do this. My struct has over 100 entries if I include all the combinations and use only what I want but I thought using generates I could trim it to what I want based on a set of parameters.
Thanks
Your problem is the scope of the typedef is local to the blocks inside your generate statements. If all you need to do is change the size of a data type, you can use a constant function call, with is statically determined. But then you run into another problem with your unpacked struct declaration - it is still local to the module and you will not be able to connect another struct to it with a matching data type. An interface would be a better solution and is synthesizable.
Another possibility is passing down a type parameter.

Using an array of parameters to generate modules

I have a module which stores a bitmap of different characters, that I am planning on using to display text on a matrix. Currently, the bitmap is populated with a memory initialization file, and this file is passed in as a parameter (I have confirmed this working in Quartus and ModelSim).
In order to actually have a lookup table for all the characters, I wanted to make a separate module which has instantiations of the all bitmaps, and selects the correct one based on a character code. These bitmap instantiations are created in a generate block, and they take the correct filename from an array. However, ModelSim doesn't like this. My code is as follows:
module mem_char_disp_lib(
output logic pixel,
input logic [4:0] x,
input logic [5:0] y,
input logic [6:0] code,
input logic clk
);
localparam CHAR_NUM = 26;
logic [CHAR_NUM-1:0] alphabet;
const var [CHAR_NUM-1:0] BITMAPS = {
"/mem/char/A.hex",
"/mem/char/B.hex",
"/mem/char/C.hex",
// ... a lot more declarations here...
"/mem/char/X.hex",
"/mem/char/Y.hex",
"/mem/char/Z.hex"
};
genvar i;
generate
for (i=0; i<CHAR_NUM; i=i+1) begin : mem_char_disp_blocks
mem_char_disp #(.BITMAP(BITMAPS[i])) block (
.pixel(alphabet[i]),
.x, .y, .clk,
.code(i),
.data(1'b0),
.write_en(1'b0)
);
end
endgenerate
always_comb
pixel = alphabet[code];
endmodule
The error ModelSim is giving me is:
The expression for a parameter actual associated with the parameter name ('BITMAP') for the module instance ('block') must be constant.
(referring to the line inside the for loop)
I am not sure why this doesn't work. On a hardware level, it seems like I'm just making a lot of copies of a module, and slightly tweaking each one with a constant parameter known at compile-time. Is there some basic syntax that I'm missing?
Edit: I have also tried the following code, which seems to give a runtime error:
for (i=0; i<CHAR_NUM; i=i+1) begin : mem_char_disp_blocks
parameter [CHAR_NUM-1:0] BITMAPS = {
"/mem/char/A.hex",
// more elements...
"/mem/char/Z.hex"
};
mem_char_disp #(.BITMAP(BITMAPS[i])) block (
.pixel(alphabet[i]),
.x, .y, .clk,
.code(i),
.data(1'b0),
.write_en(1'b0) );
end
The error is Module parameter 'BITMAP' not found for override. (One of these errors for each of the generated modules; CHAR_NUM total.) This doesn't make sense to me, since instantiating a single one directly works just fine (e.g. mem_char_disp #(.BITMAP("/mem/char/A.hex") block /* ... */).
A const variable is not a constant - it is a write-once variable that gets initialized at runtime when the variable gets allocated. You need to us a parameter or localparam to assign to another parameter as you discovered in your update. You also need to fix the dimensions of the array
parameter bit [1:15*8] BITMAPS[26] = {
"/mem/char/A.hex", // 15 8-bit chars
// more elements...
"/mem/char/Z.hex" // 26 elements
};
Can't help you with your last error without seeing the declaration of the module mem_char_disp

verilog set bus equal to array of struct bits

I'm trying to set a bus equal to a bit of a struct, for an array of structs (s.t. the array size == bus size). My struct looks like
typedef struct {
//other stuff
logic valid;
} BFRAME_OUTPUT;
And I've declared the array of structs and bus like
BFRAME_OUTPUT bframe_outs[`BSTACK_SIZE-1:0];
logic [`BSTACK_SIZE-1:0] valid;
I want to do something like either of these to simply make the valid bus equal to the valid bits for the array of structs.
assign valid[`BSTACK_SIZE-1:0] = bframe_outs[`BSTACK_SIZE-1:0].valid;
//
// or
//
for(int i = 0; i < `BSTACK_SIZE; ++i) begin
assign[i] = bframe_outs[i].valid;
end
However I get errors when trying to simulate with vcs:
Error-[XMRE] Cross-module reference resolution error
/modules/branch_stack.sv, 87
Error found while trying to resolve cross-module reference.
token 'bframe_outs'. Originating module 'branch_stack'.
Source info: assign valid[(16 - 1):0] = bframe_outs[(16 - 1):0].valid;
More importantly, there is another error which you have not shown:
Error-[PSNA] Part Select Not Allowed testbench.sv, 14 Part selects
are not allowed on arrays of classes. Source info: assign valid[(5 -
1):0] = bframe_outs[(5 - 1):0].valid; Convert the part select to
refer to each element individually.
As the error points out, you need to convert the assignment to part selection. Here, you can use one of the two ways. Either use logic as reg and use it in always block, or use logic as wire and do some other stuff.
While using it as reg, you need to extract the value in some procedural block. So, just remove the assign statement and use alway_comb. Since you have used logic here, no need to change its datatype.
always_comb
begin
for(int i = 0; i < `BSTACK_SIZE; ++i)
valid[i] = bframe_outs[i].valid;
end
Alternatively, there is a generate block to perform certain things multiple times. Note that by using generate block, you are providing continuous assignments and using logic as wire. Here, you need to provide each bit signal to the wire individually. Here, use generate as follows:
genvar i;
generate
for(i = 0; i < `BSTACK_SIZE; ++i) begin
assign valid[i] = bframe_outs[i].valid;
end
endgenerate
Refer to SystemVerilog IEEE 1800-2012 section 7.2 for structures and this link for generate blocks. I have created a working example at EDAPlayground link.

Is there a way to embed a constant in a struct in SystemVerilog?

In a perfect world, I would be able to scope a localparam to the inside of a struct:
typedef struct {
logic [10:0] mantissa;
localparam exponent = -10;
} my_fixed_point_type;
But alas, this is not legal SystemVerilog. I've investigated using const ints (illegal), enums (not scoped to the struct, and requires "storage").
I might consider just embedding an int into the struct, and trust the synthesis tool to notice the values are only ever initialized, and strip them away, but some synthesis tools are just as likely to ignore initialization.
The only approach I've found so far that actually words is this abomination:
typedef struct {
logic [10:0] mantissa;
logic [25:0] _hidden;
} my_fixed_point_type;
`define FP_EXPONENT(var) $bits(var._hidden)
Since _hidden is never read from, I have high confidence that it will get stripped out at elaboration time, while the bit width of _hidden can be used to hide an (unsigned) integer constant. Ugly!
Surely there must be a better way to scope a constant to a struct in a way that is preserved in synthesis, but doesn't take up any actual bits. Or, do I have to take this up with the SystemVerilog 2016 committee?
There are a number of things you could do, but without knowing why you are trying to do this, it is difficult to recommend a good solution. Here are a few suggestions:
You can define an initial value to a typedef
typedef struct {
logic [10:0] mantissa;
int exponent = -10;
} my_fixed_point_type;
or use an anonymous enumerated type to prevent any other value ever being assigned to it
typedef struct {
logic [10:0] mantissa;
enum {value=-10} exponent = value;
} my_fixed_point_type;
or us a continuous assignment to the variable declared with this type
typedef struct {
logic [10:0] mantissa;
int exponent;
} my_fixed_point_type;
my_fixed_point_type fpv;
assign fpv.exponent = -10;
_hidden can be made signed with logic signed [25:0] _hidden;
It can be made a semi-constant with always_comb var._hidden = -10;
assign could also work but unlike always_comb simulators are not required to give errors with multiple drivers.
An alternative is to use use an interface instead of a struct, where you can use const or parameters (even functions).
I'm not sure how well a synthesizer will optimize either; you'll need to experiment. My guess is an interface with parameters will strip away the unused signals better then with a struct.
I just started to build a fixed point library as well and wanted to use a structure to hold the [full, integer and fractional] width of signals. I'm not even trying to do anything fancy, I just wanted to collect the parameters in a structure so it's easy to have access to them. Unfortunately no matter what I do the tools complain cause they think the structure content aren't constant - even if I only ever assign once.
For example:
typedef struct { int w, i, q; } fxpt;
fxpt dw = '{16, 1, 15};
wire signed [dw.w-1:0] din;
Or even if I would accept to have different structures for each signal so it's obvious everything is constant:
typedef struct { int w=18, i=1, q=17; } dw_constant;
dw_constant dw;
wire signed [dw.w-1:0] din;
I'm now reverting back to just having parameters directly in the code, such as:
parameter integer dw[0:2] = '{16, 1, 15};
wire signed [dw[0]-1:0] din;
Note that I haven't accessed the .i and .q parameter in the code snippet so it might look a bit useless, but when doing multiplication/addition those fields are important to have.

Resources