Verilog bit shift by constant, how is it implemented? - verilog

I have a line of code like
parameter [8:0] param1=8'd05, param2 = 8'd20;
A <= cond ? (1 << param1) : (1 << param2);
Will the compiler recognize 1 << param is a constant and replace that expression with a constant or will it try to implement some sort of bit shifter?

Parameters are evaluated at compile time and must be constants.
From IEEE Std 1364-2001:
3.11 Parameters Verilog HDL parameters do not belong to either the variable or the net group. Parameters are not variables, they are
constants.
So it is really up to the Synthesis tool how it will decide to implement a shift by that constant, but any reasonable implementation will simply select the correct wires out of the vector.
In addition, since your examples are constants shifted by a constant, the whole expression reduces to a constant and the code will be equivalent to:
A <= cond ? 32'h20 : 32'h100000;

Related

If use 'function' to calculate 'parameter' will lead to logic resource occupation in Verilog HDL

I want to achieve some complicated calculation in parameter statement, but this will make my code hard to read. I know that some other FPGA engineers use 'function' to do that. The code is like what showed below:
function integer calc_head_len;
input [11:0] DFF;
begin
calc_head_len=0;
if(DFF[11]) calc_head_len=calc_head_len + 16;
if(DFF[10]) calc_head_len=calc_head_len + SFL_WIDTH;
if(DFF[9]) calc_head_len=calc_head_len + FDSTI_WIDTH_PORT;
if(DFF[8]) calc_head_len=calc_head_len + FDSSI_WIDTH_PORT;
if(DFF[7]) calc_head_len=calc_head_len + BN_WIDTH;
end
endfunction
localparam FRAME_HEAD_LEN=calc_head_len(DFF);
The question is, firstly, as i know, 'parameter' assignment should only use constant expression, but 'function' could calculate variables, so why that is ok?
Secondly, 'parameter' will not occupy logic resources because they can be calculated during synthesis stage, but will 'function' be calculated in the same time? or it will occupy extra resources?
thanks for help!
If a function’s arguments are only constants or parameters, and return value of the function is solely dependent on those arguments, then the tool will propagate the return value as another constant. So it won’t take up any extra resources.

Proper way to use a bus in a for loop in SystemVerilog?

I'm trying to make a module in SystemVerilog that can find the dot product between two vectors with up to 8 8-bit values. I'm trying to make it flexible for vectors of different length, so I have an input called EN that's 3 bits and determines the number of multiplications to perform.
So, if EN == 3'b101, the first five values of each vector will be multiplied and added together, then output as a 32-bit value. Right now, I'm trying to do that like:
int acc = 0;
always_comb
begin
for(int i = 0; i < EN; i++) begin
acc += A[i] * B[i];
end
end
assign OUT = acc;
Where A and B are the two input vectors. However, SystemVerilog is telling me there's an illegal comparison being performed between i and EN.
So my questions are:
1) Is this the proper way to have a variable vector "length" in SystemVerilog?
2) If so, what's the proper way to iterate n times where n is the value on a bus?
Thank you!
I have to guess here, but I'm assuming it's a synthesizer complaining about that code. The synthesizer I use accepts your code with minor modifications, but maybe not all do since the loop can't be unrolled statically (notice I have input logic [2:0] EN, maybe input int EN does not work due to having too big a max number of cycles). Your loop per se (question #2) is fine.
int acc;
always_comb
begin
// If acc is not reset always_comb tries to update on its old value and puts
// it in sensitivity list, halting simulation... also no initialization to variable
// used in always_comb is allowed.
acc = 0;
...
This is a somewhat decent reason to complain about your otherwise perfectly good code, and the tool does not make the assumption that it is "reasonable" to generate all possible loops in this specific case (if EN was an unsigned integer your chip would be stupidly huge after all): you can force the tool to infer all possibilities with something that looks like the following:
module test (
input int A[8],
input int B[8],
input logic [2:0] EN,
output int OUT
);
int acc[8]; // 8 accumulators
always_comb begin
acc[0] = A[0] * B[0]; // acc[-1] does not exist, different formula!
for (int i = 1; i < 8; i++) begin
// Each partial sum builds on previous one.
acc[i] = acc[i-1] + (A[i] * B[i]);
end
end
assign OUT = acc[EN]; // EN used as selector for a multiplexer on partial sums
endmodule: test
The above module is an explicit description of the "parallel loop" my synthesizer infers.
Regarding your question #1, the answer is "it depends". In hardware there is no variable length, so unless you fix the number of iterations as a parameter as opposed to an input you either have a maximum size and ignore some values or you iterate over multiple cycles using pointers to some memory. If you want to have a variable vector length in a test (not going to silicon) then you can declare a "dynamic array" that you can resize at will (IEEE 1800-2017, 7.5: Dynamic arrays):
int dyn_vec[];
As a final side note, int bad integer good for everything that is not testbench in order to catch X values and avoid RTL-synthesis mismatch.

== operator in assign statement (Verilog)

I am trying to understand some of the System Verilog syntax. I was struggling to finish an assignment and I came across this solution, but I do not understand why it works.
localparam int lo = w;
uwire [n:0] lo_bits, hi_bits;
assign answer = lo_bits == nlo ? lo_bits + hi_bits : lo_bits;
This is not exactly what I have in my code, but my question is the following: Why can't I rewrite this to a simple if-else block as such?
if (lo == lo_bits)
assign answer = lo_bits + hi_bits;
else
assign answer = lo_bits;
Verilog complains that lo_bits is a uwire and I cannot compare it with lo, but then why is it allowed in the example above? Aren't these two assignments equivalent?
Thank you very much for your help!
The difference is structural/declarative context versus procedural context. When you use an if clause in a declarative context (in this case it is at the same top level where you declare your wires and variables), it is considered a conditional generate construct (See Section 27.5 in the 1800-2017 LRM). This means the condition gets evaluated before simulation starts and must contain only constant expressions and no signals that can change during simulation. lo is a constant parameter, but not lo_bits.
If you want to use a procedural if, it needs to be inside a procedural block of code instantiated by always/initial blocks.
logic [n:0] answer;
always_comb
if (lo == lo_bits)
answer = lo_bits + hi_bits;
else
answer = lo_bits;

Is there a ifx-elsex statement in Verilog/SV like casex?

Say I have a scenario in which I need to compare only a few bits of a register and I don't care about other bits. eq, I need to check the first and last bits of a 3 bit register (A[2:0]) and I don't care about the middle bit, say compare vector is 3'b1X0 (Parameter).
Simplest way to do this is choose all the bits I care about, AND them and I have generated a control signal:
if ((A[2]==1) & ((A[0]==0)) Here the condition inside if statement is my control signal.
Another way is to use a casex statement: casex(A) begin 3'b1?0: ... , ... endcase.
Is there anything like ifx-elsex statement or something that can be used to do this kind of operation without using the 1st and 2nd method?
Thanks!
if (A[2:0] inside {3'b1?0} )
SystemVerilog keyword inside. It has been supported since at least Accellera's SystemVerilog 3.1 (before SystemVerilog was a part of IEEE). IEEE Std 1800-2012 11.4.13 has examples of use. inside is synthesizable.
There is also if ( A[2:0] ==? 3'b1?0 ) (IEEE Std 1800-2012 11.4.6). The only reference I have on hand (a book published 2004) says it is not supported for synthesis yet. You are welcome to try it.
(A[2]==1) is a logical expression the & is a bitwise operator, although either works it would be better semantics to use the && logical and operator. This is slightly different to most other languages where the && is a short-circuit operator.
Logically what you want is if ((A[2]==1) && ((A[0]==0)) but it could be reduced to a bitwise expression :
if ( ~A[0] & A[2] )
NB: Try to avoid using casex, the unknown parts will match x's in simulation. Try to use casez instead, ? can still be used to match don't cares.
Update comparing inside to casez
Case statements a clean control structure used in most languages to avoid large if elsif else chains. the inside operation will match x's to the do not care '?' values. this makes it usage similar to the casex which is considered to be bad practise to use as it can hide simulation fails.
casez(sel)
4'b1??? a= 3'd4;
4'b01?? a= 3'd3;
4'b001? a= 3'd2;
4'b0001 a= 3'd1;
4'b0000 a= 3'd0;
endcase
vs
if (sel inside {4'b1???})
a= 3'd4;
else if (sel inside {4'b01??})
a= 3'd3;
else if (sel inside {4'b001?})
a= 3'd2;
...
The above is actually equal to the casex (but more verbose) I believe that instead of casex you could also use :
case(sel) inside
4'b1??? a= 3'd4;
4'b01?? a= 3'd3;
4'b001? a= 3'd2;
4'b0001 a= 3'd1;
4'b0000 a= 3'd0;
endcase
but then I would never use a casex.
There's no operator I'm aware of that allows you to use '?' or 'x' inside an equality comparison to have them ignored.
Another alternative that you didn't mention would be to use a bitmask to select the bits you only care about. If you have a lot of bits this can be more compact than testing each bit individually.
If you only care about A == 3'b1?0, then it can be written as such:
if((A & 3'b101) == 3'b100)

Verilog net to reg assignment

I have an input port from_LS(511:0). This is declared as wire in my module. I am assigning this to a set of 32 registers ilb(0:31), each of which are 1 nits long. I was trying to use the for loop to do this.
integer i;
genvar j;
initial
begin
count1 = 0;
count2=0;
flush_ctrl=0;
buffer_bit=0;
a=(hmic_ctrl[1]) + (hmic_ctrl[2]*2) + (hmic_ctrl[3]*4);
//assigning data from LS to ilb
for (i=0;i<=31;i=i+1)
ilb[i]=from_LS[511-(16*i) : 511-(16*(i-1))];
ilb[0]= from_LS[511:496];
ilb[1]= from_LS[495:480];
ilb[2]= from_LS[479:464];
ilb[3]= from_LS[463:448];
ilb[4]= from_LS[447:432];
ilb[5]= from_LS[431:416];
ilb[6]= from_LS[415:400];
ilb[7]= from_LS[399:384];
ilb[8]= from_LS[383:368];
ilb[9]= from_LS[367:352];
ilb[10]= from_LS[351:336];
ilb[11]= from_LS[335:320];
ilb[12]= from_LS[319:304];
ilb[13]= from_LS[303:288];
ilb[14]= from_LS[287:272];
ilb[15]= from_LS[271:256];
ilb[16]= from_LS[255:240];
ilb[17]= from_LS[239:224];
ilb[18]= from_LS[223:208];
ilb[19]= from_LS[207:192];
ilb[20]= from_LS[191:176];
ilb[21]= from_LS[175:160];
ilb[22]= from_LS[159:144];
ilb[23]= from_LS[143:128];
ilb[24]= from_LS[127:112];
ilb[25]= from_LS[111:96];
ilb[26]= from_LS[95:80];
ilb[27]= from_LS[79:64];
ilb[28]= from_LS[63:48];
ilb[29]= from_LS[47:32];
ilb[30]= from_LS[31:16];
ilb[31]= from_LS[15:0];
pctr(
.clk(clk),
.reset(0),
.offset(branch_ctrl[13:1]),
.mux_select(branch_ctrl[0]),
.pc1(pc)
);
end
I was getting the error that I should not use a variable index. The error is :
# ** Error: C:/Modeltech_pe_edu_10.0/examples/COMP ARC/inst_line_buf.v(55): Range must be bounded by constant expressions.
So i wrote down the following:
ilb[0]= from_LS[511:496];
ilb[1]= from_LS[495:480];
ilb[2]= from_LS[479:464];
....
ilb[31]= from_LS[15:0];
But i guess there must be a better way to do this. Could anyone tell me how?
The orginal verilog doesnt allow this kind of expression as it wanted to assure that the width is always right (it is, but in earlier times compilers werent as good :-).
Verilog 2001 offers some solution with +: you can specify the width
e.g. from_LS[ 511-(16*i) +:16 ] in your loop.
EDIT: Another solution would be to put another loop inside, which copies 16 bits bit by bit.
You should include more code (at least up to the always block containing that loop for the sensitivity list) and the exact error you're getting.
Does it work if you change integer i to genvar i and wrap the for in generate and endgenerate?

Resources