Synthesis error on a CASE statement in Verilog - verilog

I m new in Verilog and I would like to know your opinion about an error I get when trying to synthesize the part of my code cited below:
input [31:0] A;
reg [31:0] X,Y;
reg [15:0] width;
input action;
always#*
begin
width= A [31:16];
if (action==1)
begin
case (width)
16'b0: X=0;
default:
begin
for (i=32; i>=width+1 ; i=i-1)
X[i]=0;
for (i=width; i>=0; i=i-1)
X[i]=1;
end
endcase
Y=X >> 1;
end
end
I m using Cadence synthesis tool and the error that i get is in this part of my code saying :
Index 'X[-1]' is not within the valid range of the declaration [31:0]
which i don't understand because even if width=0 i have a special case that should not involve the for loop. i also tried increasing the limits to width +2,width +1 and then shift the quantity X by 2 ..but also got the same error.
Thank you in advance!

I don't see how i could be -1, but it is possible for it to be greater than 31 which is out of range. There are couple of synthesis issues:
i=32 is already out of range for X[31:0]. Its MSB is 31.
i will go out of range when width > 31. width is a 16-bit unsigned value, meaning its maximum value is 65535 (i.e. 216-1) and its minimum is 0.
Synthesis requires loops to static unroll. This means the number of loops must be constant. Variables such as width cannot be in the loops condition.
A synthesis-able for loop will look as follows:
for (i=31; i>=0; i=i-1)
X[i] = (width>=i);
I'm assuming the width= A [31:16]; above the always block is a copy past typo as it is illegal syntax. I'm also assuming there are no additional assignments on width, X, Y, or i outside of the always block. Otherwise there are additional errors.

It's unclear exactly why you're hitting the -1 condition, but it looks like you are trying to create a mask of width "width", which would be more easily accomplished as:
always #*
begin
X = ((1 << width[4:0]) - 1)
end
Edit: Added width specifier to shift, this may reduce synthesis area

Related

How to prevent inferred latch and latch unsafe behavior in Verilog?

I am having trouble with a specific part of my program, here in the always block:
module compare_block (clk, reset_n, result, led);
parameter data_width = 8; //width of data input including sign bit
parameter size = 1024;
input clk, reset_n;
input [(data_width+2):0] result; //from filter -- DOUBLE CHECK WIDTH
logic [(data_width):0] data_from_rom; //precalculated 1 Hz sine wave
logic [10:0] addr_to_rom;
output reg led;
reg [(data_width + 2):0] ans_sig [size-1:0];
integer i, iii, jj, j, ii;
reg ans_sig_done, filt_sig_done, comp_sig_done;
reg [(data_width+2):0] sum;
reg [data_width:0] max_val, error_val;
initial max_val='b000000000;
...
always #* begin
sum = 0;
if (ans_sig_done) begin
for (j=4; j<(size-1); j=j+2) begin
sum = sum + ans_sig[j];
if (ans_sig[j] > max_val) begin
max_val = ans_sig[j];
end else begin
max_val = max_val;
end//else
end //for
end//if
end//always
...
endmodule
Essentially, ans_sig is an array, 1024 bytes long that I want to sum into one number (sum) and eventual (not here) take the average of. While I am traversing the ans_sig array, I also want to identify the maximum value within the array (max_val), which is what the nested if-statement is doing. However I get the following severe warnings when I'm compiling in Quartus:
"Inferred latch for "max_val[8]" at compare_block.sv"
"13012 Latch compare_block:compare|max_val[8] has unsafe behavior"
"13013 Ports D and ENA on the latch are fed by the same signal compare_block: compare|LessThan473~synth" (for max_val[8])
I get all of these errors for max_val [0] through max_val [8].
this code represents a null-statement and actually signifies a latch rather than eliminating it:
end else begin
max_val = max_val; <<< null statement
It does not make much sense in using such statement unless you want to show that this has a latch behavior.
You initialized the max_val only once in the initial block. There for the latch behavior is an expected one: you keep max_val between multiple invocations of the sum for loop.
If this is not the case, and you need to re-calculate the max_val every time, you should initialize it in the always block same way as you do sum.
always #* begin
sum = 0;
max_val = 0;
if (ans_sig_done) begin
for (j=4; j<(size-1); j=j+2) begin
sum = sum + ans_sig[j];
if (ans_sig[j] > max_val) begin
max_val = ans_sig[j];
end
end//else
end //for
end//if
end//always
this way you will get rid of the latch.
If this module is for simulation purposes, perhaps you don't need to care about the warnings (I'm not pretty sure. Correct me if I'm wrong). However if it's for implementation, you'll need to use sequential logic to generate sum and max_val with ans_sig_done being the enable signal. You have 1024 11-bit long data, don't ever think about doing such a calculation with zero time consumption. Let's talk about the warnings you got. Since the always block is combinational, what do you expect when ans_sig_done is false. Combinational logic with missing branches results in latch behavior. By the way, you have a sum with the same bit width as each data inside the ans_sig array which will lead to potential data loss during calculation, and a max_val with even narrower bit width.

Is there a mandate for the variable to be of data type "integer" for arithmetic operations "+" and "-"?

Following is the code for finding factorial of a number. If I declare "i" as "register", the output (z) remains 1, irrespective of the input. If it is declared as "integer", I get the proper result. Why is it so? Please explain.
module Factorial_calc(n, z);
input [5:0] n;
output reg [64:0] z;
reg i;
// integer i;
always #(n)
begin
i=0;
z=1;
while(i<n)
begin
i=i+1;
z=i*z;
end
end
endmodule
Because your integer is 32 bits wide and your reg is only one bit wide. Your simulation should not finish for most values of n, let alone produce a result.
HDL is not like any other programming language. Beware that even if your code simulates it does not mean it will work in hardware. In your case it will not synthesize. You value of n is undefined at compile time.
Last be not least do NOT use x or z for variables, They are too easily confused with 'x or 'z.

How to use the input's values in "always" definiton in Verilog

I got the problem with using the input's value in Verilog.
I write:
module reg_vector (INPUT, ICLK, IENBL, NR, OUT);
parameter k = 6;
parameter n = 3;
input [(8*k)-1:0] INPUT;
input ICLK;
input IENBL;
input [n-1:0] NR;
reg [n-1:0] temp;
output reg [7:0] OUT;
always# (temp, posedge ICLK)
begin
if (IENBL)
begin
OUT = INPUT[temp*8 : temp*8+8];
end
end
endmodule
But got the error:
Error (10734): Verilog HDL error at reg_vector.v(25): temp is not a
constant
How should I fix it?
Thank you)
INPUT[temp*8 : temp*8+8] does not work because the : range syntax requires both sides to be a constant.
What you want is to use the +: array slicing: INPUT[temp*8 +: 8]
The left hand side of +: allows variables and represents the starting index. The right hand side is the width and must be a constant. For more on +: see Indexing vectors and arrays with +:
Other issues:
Remove temp from the sensitivity list.
temp needs to be assigned to something
OUT should be assigned with non-blocking (<=) not blocking (=) since it is sequential logic.
always #(posedge ICLK) // no temp in sensitivity list
begin
if (IENBL)
begin
OUT <= INPUT[temp*8 +: 8]; // non-blocking and +:
end
end
Even if your vector is always 1 byte wide, the tool understands it as a variable size and it does not know how to deal with it. (you also inverted the indexes temp*8 and temp*8+8 in the vector selection)
Another way to do it is to use the shift operator
OUT = INPUT >> (temp*8);
This should work as OUT will take the lower 8bits of the shifting by 8*temp of INPUT

Displaying numbers in 7 Seg Decoder using Verilog

This code should display number 0 -15. I am trying to make this code to work, but I tried everything and nothing works...
reg number;
number[3] = Qd;
number[2] = Qc;
number[1] = Qb;
number[0] = Qa;
wire circuitB;
reg[3:0] tenth;
comparator cm (circuitB,number);
always#(circuitB)
if(circuitB)begin
number[3] = 0;
number[2] = 0;
number[1] = number[3]&number[2]&number[1];
number[0] = ~(number[1]^number[0]);
tenth[0] = 1;
end
Dec7SegDisp big (HEX0,number);
Dec7SegDisp big1 (HEX1,tenth);
Qa,Qb,Qc,Qd are output from a counter.
So, things I tried :
using number and tenth as wire - I will get errors such as left hand assignment must have a variable data type etc.
using numer and tenth as reg - I get errors saying that assigng Qa,Qb,Qc and Qd to them are illegal, as Error (10170): Verilog HDL syntax error at partII.v(22) near text "="; expecting ".", or an identifier
And I don't know what else I can do. Thanks for reading.
Here are a few things you need to fix:
you define number as a single scalar variable, but use it as an array. It should be either reg [3:0] number or wire [3:0] number.
You should either use continuous assignments to number: assign number[3] = Qd; or only assign to it in an always block. The way you have it now at the beginning of the code is wrong. Why not putting all assignments to number in one single always block?
You can't assign to number twice. Currently, you are assigning to it both at the beginning and also in the always block.
You don't show all of your code and the description of the comparator and QA,..,QD. Perhaps you can post a more complete code here: http://www.edaplayground.com/

"<signal> is not a constant" error in if-statement

I am trying to write a simple module to output a 14-bit number based on the value of four input signals. My attempt is shown below.
module select_size(
input a,
input b,
input c,
input d,
output [13:0] size
);
if (a) begin
assign size = 14'h2222;
end
else begin
if (b) begin
assign size = 14'h1111;
end
else begin
if (c) begin
assign size = 14'h0777;
end
else begin
assign size = 14'h0333;
end
end
end
endmodule
Upon compilation, I receive the following error:
ERROR:HDLCompiler:44 - Line 67: c is not a constant
I don't understand why that particular if-statement isn't working if the other two preceding it are. I have tried changing the condition to
if (c == 1) begin
but to no avail.
Does anybody know how to solve this error? Thank you!
Two problems:
1) You need to put if statements inside an always block.
If you use verilog-2001, you can use
always #*
if ....
end
end
Otherwise specify all the inputs in the sensitivity list:
always #(a or b or c or d)
if ....
end
end
2) Constant assignments are not allowed inside if statements.
Remove the assign keyword from any statements inside the if block:
if (a) begin
size = 14'h2222;
end
You will also have to declare size as a reg type.
However my preference would be to rewrite the entire module with conditional operator, I find it much preferrable to read. This following module achieves the same result:
module select_size(
input a,
input b,
input c,
input d,
output [13:0] size
);
assign size = a ? 14'h2222 :
b ? 14'h1111 :
c ? 14'h0777 :
14'h0333 ;
endmodule
As #Tim has already answered, using reg types inside always blocks or wire with assign.
#Tim has also described the nested ternary assignments, while in the example are written very well, they are generally seen as bad practice. They imply a very long combinatorial path and can be hard to maintain. The combinatorial path may be optimised by synthesis which should imply a mux with optimised selection logic.
Easier to maintain code will have a lower cost of ownership, and as long as it does not lead to a larger synthesised design it is normally preferred.
My implementation would be to use a casez, (? are don't cares). I find the precedence of each value easier to see/debug.
module select_size(
input a,
input b,
input c,
input d,
output logic [13:0] size //logic (SystemVerilog) or reg type
);
always #* begin
casez ({a,b,c})
3'b1?? : size = 14'h2222 ;
3'b01? : size = 14'h1111 ;
3'b001 : size = 14'h0777 ;
3'b000 : size = 14'h0333 ;
default: size = 'bx ;
endcase
end
endmodule

Resources