I am using a generate loop to instantiate a paramaterizable number of modules, and I want to assign some of the inputs to the module based on the loop iteration. Unfortunately I'm running into issues with synthesis where design compiler says there's an error because the port width doesn't match. Here's what I'm trying to do:
genvar k;
generate
for(k = 0; k < `NUM/2; ++k) begin
cmp2 cmps(
.a (arr[k]),
.b (arr[k+1]),
.a_idx (k), //gives errors about port width mismatch
.b_idx (k+1), //but I can't get it to work any other way
.data_out(data[k]),
.idx_out (idx[k])
);
end
endgenerate
I've also tried using localparams in the loop and assigning a_idx and b_idx to the localparam but I still get the same error under synthesis.
I've tried something like .a_idx((k)[bit_width-1:0]), but that doesn't work either.
Any ideas?
k and k+1 are 32-bit wide, which causes the width mismatch.
Depending on what your synthesis tool supports, you might want to try the following:
Bit slicing:
.a_idx (k[0 +: bit_width])
Cast to bit_width-wide logic:
typedef logic[bit_width-1:0] logicN_t;
// .... //
.a_idx (logicN_t'(k)),
.b_idx (logicN_t'(k+1)),
// .... //
Related
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.
Is there a way to do explict resize to LEN of an expression?
The reason I want this, is to make the code explicitly describe the intention, and also to avoid the warnings for implicit resize that some tools generate.
The code below works in some tools, but fails in other:
localparam EXPR = 12;
localparam LEN = 7;
assign res = LEN'(EXPR);
Based on reading the Verilog-2001 standard, it looks like lengty by LEN'... can only be used for literals, e.g. 7'd12, and not for general expressions.
So, is there a way to do explicit resize of general expressions in Verilog-2001?
The syntax you are looking for is already in SystemVerilog. You need to make sure you turn it on or use the proper .sv file extension so your tools recognize it.
assign res = LEN'(EXPR);
However, there is no way to dynamically calculate the length of a type - it needs to be a constant expression.
But you can dynamically apply a mask that truncates your value to desired length
assign res = EXPR & ((64'b10<<LEN)-1);
How about
localparam LEN = 7;
localparam [LEN-1:0] EXPR = 12;
assign res = EXPR;
or if you need to use EXPR for some other purpose
localparam LEN = 7;
localparam [LEN-1:0] EXPR7 = 12;
localparam EXPR = 12;
assign res = EXPR7
System Verilog has a $bits() system call. It returns the number of bits required for an expression. Thus:
wire [11:0] res;
$bits(res) // <= will return 12
You have to check if you simulator/compiler supports it. Also I don't know if you can use it as:
$bits(res)'d7
The only thing I should warn off is not to sacrifice your code readability to suppress superfluous warnings. Good readability prevents more errors than anything else.
I have a [systemverilog] macro I use for resizing:
// Drive a signal with a constant, automatically resize constant to signal value
`define assign_const(SIGNAL,VALUE) assign SIGNAL = ($bits(SIGNAL))'(VALUE)
The ($bits(SIGNAL))'(VALUE) is the critical part. It uses $bits to determine the signal length and recasts the value accordingly.
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
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.
When I was config pll_reconfig module in Quartus II, the generate for statement in design have to specify different string parameter (filenames) to different instances.
I have tried these code:
genvar i;
generate
for (i=0; i<2; i=i+1) begin:u
rom #($sformatf("mif%d.mif",i)) U(
//signals connected.
);
end
endgenerate
It is said that the code is not synthesizable.
How can I specify variable string parameter in generate for block?
I had a similar problem but on a system that did not support $sformatf. My solution is a little dirty but may help others:
genvar i;
generate
for (i=0; i<10; i=i+1)
begin
mymodule #(.NAME("NAME0" + i) instance(.RESET(mreset) ... );
end
endgenerate
This works, I believe, by treating the string "NAME0" as a number (a 40-bit number). By adding i, you just increase the value by i and the result is the last ASCII char changes. Luckily '0' + i gives you '1', '2', '3' etc
The obvious flaw is this only works for 0-9, however there is a simple extension using divide and modulo arithmatic:
mymodule #(.NAME("NAME00" + (256 * (i / 10)) + (i % 10) ) ) ...
As a side note, I ran into issues using string concatenation {"NAME", i} because Verilog was treating i as 32-bit value so the string ends up as:
NAME 1
due to the extra 'unwanted' 24 bits which equate to 3 null characters