How to do explicit resize? - verilog

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.

Related

Symbol ";" at the end of `define statement

With some simulators(for ex. VCS) the following code is passing and with some of them it brings to compilation error( for ex. Xcelium):
For example:
`define MAX_SIZE 8;
Who knows what is the reason that some simulators passing with ";" symbol at the end?
Best Regards,
The reason has to do with whether to tool is interpreting the code as Verilog or SystemVerilog. Verilog does not have the concept of a null statement, while SystemVerilog does:
module top;
;
endmodule
When you put a ; at the end of a macro and put one at the end of the statement that uses the macro, you wind up with a null statement.
`defne MAX_SIZE 8;
A = `MAX_SIZE;
This gets intrpreted as
A = 8; ;
So it depends on whether that null statement makes sense in the context where it appears.
begin
; // allowed here
case (expr)
1: A = 8;
2: A = 16; ; // null statement not allowed here
endcase
B = 8; ; // allowed here
end
Verilog text macros are used for text substitutions. In your case ; is a part of the macro definition. It will be placed in the text as is, for example:
`define MAX_SIZE 8;
...
assign abc = `MAX_SIZE
The last statement does not contain explicit semicolon. It is supplied by the macro when its text gets substituted there and will look like assign abc = 8;
answering the comment
It is not a good practice to use the ; in macro definition. Verilog is very strict about semicolons ad there are other issues as well. For example, if one puts a semicolon after a such macro, as in the comment, compilation will fail because of the double ;;
`assign abc = `MAX_SIZE;
The other example of failing compilation is declaration:
reg[`MAX_SIZE-1:0] ctrl;
Now, the semicolon from the MAX_SIZE would stay in the way.
The best way to avoid issues in verilog with macros: do not use semicolon in macro definition, in particular when you define constants:
`define MAX_SIZE 8
However, even a better way to define constants is to use parameters. parameter MAX_SIZE = 8;

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();

verilog generate loop assign to iterator width mismatch

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)),
// .... //

Declaring an array of constant with Verilog

first i want to apologize for my ignorance,this question may be stupid for many of you..but i am a newbie in the domain of Hw dev
I am trying to turn a software function into a hardware accelerator...
in the C code we use an array of integer to calculate a certain value as shown here
uint k[64] = {
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
};
as you see here am gonna use it to calculate t1
$ t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
however am not certain how to declare this array without using registers, i have a verilog file in whitch it uses localparam to declare a constant. so i wonder could i use it with this vector as below ?
localparam [31:0] k[63:0] =
{0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
};
Yes you can. However, 0x is not verilog syntax, use 32'h (or just 'h if you want it less strongly typed) instead.
localparam logic [31:0] k[63:0] =
{
32'h428a2f98,32'h71374491,32'hb5c0fbcf,32'he9b5dba5,32'h3956c25b,32'h59f111f1,32'h923f82a4,32'hab1c5ed5,
32'hd807aa98,32'h12835b01,32'h243185be,32'h550c7dc3,32'h72be5d74,32'h80deb1fe,32'h9bdc06a7,32'hc19bf174,
32'he49b69c1,32'hefbe4786,32'h0fc19dc6,32'h240ca1cc,32'h2de92c6f,32'h4a7484aa,32'h5cb0a9dc,32'h76f988da,
32'h983e5152,32'ha831c66d,32'hb00327c8,32'hbf597fc7,32'hc6e00bf3,32'hd5a79147,32'h06ca6351,32'h14292967,
32'h27b70a85,32'h2e1b2138,32'h4d2c6dfc,32'h53380d13,32'h650a7354,32'h766a0abb,32'h81c2c92e,32'h92722c85,
32'ha2bfe8a1,32'ha81a664b,32'hc24b8b70,32'hc76c51a3,32'hd192e819,32'hd6990624,32'hf40e3585,32'h106aa070,
32'h19a4c116,32'h1e376c08,32'h2748774c,32'h34b0bcb5,32'h391c0cb3,32'h4ed8aa4a,32'h5b9cca4f,32'h682e6ff3,
32'h748f82ee,32'h78a5636f,32'h84c87814,32'h8cc70208,32'h90befffa,32'ha4506ceb,32'hbef9a3f7,32'hc67178f2
};
You might be better off going with an integer type rather than localparam. Logic types are 4-state, which is more expensive on the simulator and since you are using it as a constant value (I assume), you should be fine with integer.
integer k[64] = {
32'h428a2f98,32'h71374491,32'hb5c0fbcf,32'he9b5dba5,32'h3956c25b,32'h59f111f1,32'h923f82a4,32'hab1c5ed5,
32'hd807aa98,32'h12835b01,32'h243185be,32'h550c7dc3,32'h72be5d74,32'h80deb1fe,32'h9bdc06a7,32'hc19bf174,
32'he49b69c1,32'hefbe4786,32'h0fc19dc6,32'h240ca1cc,32'h2de92c6f,32'h4a7484aa,32'h5cb0a9dc,32'h76f988da,
32'h983e5152,32'ha831c66d,32'hb00327c8,32'hbf597fc7,32'hc6e00bf3,32'hd5a79147,32'h06ca6351,32'h14292967,
32'h27b70a85,32'h2e1b2138,32'h4d2c6dfc,32'h53380d13,32'h650a7354,32'h766a0abb,32'h81c2c92e,32'h92722c85,
32'ha2bfe8a1,32'ha81a664b,32'hc24b8b70,32'hc76c51a3,32'hd192e819,32'hd6990624,32'hf40e3585,32'h106aa070,
32'h19a4c116,32'h1e376c08,32'h2748774c,32'h34b0bcb5,32'h391c0cb3,32'h4ed8aa4a,32'h5b9cca4f,32'h682e6ff3,
32'h748f82ee,32'h78a5636f,32'h84c87814,32'h8cc70208,32'h90befffa,32'ha4506ceb,32'hbef9a3f7,32'hc67178f2
};

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.

Resources