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

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

Related

how to implement verilog code with small modules

(Verilog) The following is a 32-bit Arithmetic Logic Unit (ALU) [see slides]. It has two 2-1 and one 3-1 MUX, a 32-bit Adder, a 32-bit subtractor, and a 16-bit multiplier. The function table shows different functions this ALU performs for different values of F (a 3-bit control signal). Notice the interconnect among different modules inside the ALU.
Please describe this ALU using Verilog. Your implementation should start with the smaller blocks showing in the ALU, and then using those smaller blocks to build the whole ALU. In other words, your implementation should promote reusability of smaller modules (i.e., modular). Optimize your implementation if possible.
function table in the image
module adding(r,a,b);
input[31:0] a;
input[31:0] b;
output[31:0] r;
assign r=a+b;
endmodule
module ALU(F,A,B,R);
input[2:0] F;
input[31:0] A;
input[31:0] B;
output[31:0] R;
reg R;
always #(F)
begin
if ( F == 3'b000 ) adding ad(R,A,B);
else if ( F == 3'b001 ) R = A+1;
else if ( F == 3'b010 ) R = A-B;
else if ( F == 3'b011 ) R = A-1;
else if ( F == 3'b10x ) R = A*B;
end
endmodule
this what I did so far but I got errors!! I will continue with the other statement as I know how to make the first small module
Notice some basic verilog syntax issues.
bit width mismatch in declaration of R.
sensitivity list not complete for the always block.
module instantiation is not allowed under a structural if.
I don't know if the undefined branches for F is intended, it is leading to behavior perhaps your don't want.
Since you are mainly working on module partition, it's related to the point 3. You will need to instantiate the basic (reusable) modules separately, and then select the outputs via F.
wire [31:0] adder_b;
wire [31:0] adder_result;
assign adder_b = F[0] ? 32'h1 : B; // select input outside 'adding'
adding ad (adder_result, A, ader_b);
always#(*)begin
if(F2:1] == 2'b00) R = adder_result;
...
end
There are many ways to write simple code in verilog.it depends on requirement some time here I presented different ways to write this code.
first by assign keyword and the second by case statements.
assign result = (opcode==3'b000) ? A+B :
((opcode==3'b001)? A+1 :
((opcode==3'b010)? A-B :
((opcode==3'b011)? A-1 : A*B)));
always #(*) begin
casex(opcode)
3'b000: result=A+B;
3'b001: result=A+1;
3'b010: result=A-B;
3'b011: result=A-1;
3'b1xx: result=A*B;
endcase
end

When I compile my Verilog code I get this message. Anybody know what is the reason?

When I compile my code I get these error msg for following lines. can someone explain it.
This is verilog code for a processor
assign Imm = instruction[7:0];
assign OUT1addr = instruction[2:0];
assign OUT2addr = instruction[10:8];
assign INaddr = instruction[18:16];
assign address = instruction[23:16];
assign address = instruction[7:0];
The following message comes for ABOVE LINES
tgt-vvp sorry: procedural continuous assignments are not yet fully supp
orted. The RHS of this assignment will only be evaluated once, at the time the assignment statement is executed.
You did not do what I asked which is show me where that code is.
From the error message I very much suspect that code is inside an always block:
always #( ...)
...
assign Imm = instruction[7:0];
This is called "a procedural continuous assignment".
The alternative is:
always #( ...)
...
Imm = instruction[7:0];
This is a standard assignment.
There is a significant difference between the two. You would normally not use the first form (unless you really, really know what you are doing.)
Thus the solution is to remove all the 'assign' keywords if they are inside an always block.
Outside an always you need the assign:
always #( * )
begin
...
x = y ^ z;
end
assign write = valid & select;
The short answer is you should probably remove the assign keyword.
The assign keyword has two different meanings depending on context you do not show.
When used at the top level of a module, the assign keyword is a permanent process sensitive to RHS changes and assigns it to the LHS wire. The assign statement has equivalent functionality to the always block below
module mod;
...
assign Awire = B + C;
always #(B or C) begin
Areg = B + C;
end
endmodule
When used inside a procedural process, it is a temporary process that assigns the LHS variable every time the RHS changes. The two always blocks below have the same functionality
module top;
...
always #(sel)
begin
if (sel)
assign Areg = B;
else
assign Areg = C;
end
always #(sel or B or C) // #*
begin
if (sel)
Areg = B;
else
Areg = C;
end
endmodule
Unfortunately, almost all synthesis tools require you to write your code with a complete sensitivity list as in the latter always block. Thus this eliminates allowing the use of assign inside a procedural block.

Bit by bit comparison between two variables in Verilog

Currently, I am beginning to write the firmware by Verilog for one idea. It is comparing bit by bit between two variables and then using one binary counter to count the number of different bits.
For example:
I have two variables in verilog
A : 8'b00100001;
B : 8'b01000000;
Then I give the condition to compare bit by bit between two variables. If there is difference between 1 bit of A and 1 bit of B at same bit position, binary counter will count.
This is my verilog code:
module BERT_test(
input CLK,
input RST,
input [7:0] SIG_IN,
input [7:0] SIG_OUT,
output [7:0] NUM_ERR
);
integer i;
reg[7:0] sign_in;
reg[7:0] sign_out;
always #(posedge CLK) begin
sign_in[7:0] <= SIG_IN[7:0];
sign_out[7:0] <= SIG_OUT[7:0];
end
reg [15:0] bit_err;
// Combinational Logic
always #* begin
bit_err = 8'b0;
for (i=0;i<8;i=i+1) begin
if (sign_in[i] == sign_out[i]) begin
bit_err = bit_err + 8'b0;
end else begin
bit_err = bit_err + 8'b1;
end
end
assign NUM_ERR = bit_err;
end
endmodule
Then I had a mistake
Reference to vector wire 'NUM_ERR' is not a legal reg or variable lvalue
I do not know how to solve this problem. Are there any solutions for this problem or how I need to modify my firmware, please suggest me.
You are driving NUM_ERR (a net) from an always block. It is not permitted to drive nets from always blocks (or initial blocks). You need to move this line:
assign NUM_ERR = bit_err;
outside the always block.
You should not use an assign statement inside an always block. This is legal but is deprecated and means something weird. If you have included this line inside the always block by mistake, then indenting you code properly would have shown it up.
You have an assign WITHIN an always block. Move it outside.
Adding zero to bit error if the bits are the same is superfluous.
if (sign_in[i] != sign_out[i])
bit_err = bit_err + 8'b1;
Also bit error is 16 bits so it is not wrong to add 8'b1 but misleading.

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

Getting strange error in verilog (vcs) when trying to use if/else blocks

I am trying to write an "inverter" function for a 2's compliment adder. My instructor wants me to use if/else statements in order to implement it. The module is supposed to take an 8 bit number and flip the bits (so zero to ones/ones to zeros). I wrote this module:
module inverter(b, bnot);
input [7:0] b;
output [7:0]bnot;
if (b[0] == 0) begin
assign bnot[0] = 1;
end else begin
assign bnot[0] = 0;
end
//repeat for bits 1-7
When I try and compile and compile it using this command I got the following errors:
vcs +v2k inverter.v
Error-[V2005S] Verilog 2005 IEEE 1364-2005 syntax used.
inverter.v, 16
Please compile with -sverilog or -v2005 to support this construct: generate
blocks without generate/endgenerate keywords.
So I added the -v2005 argument and then I get this error:
vcs +v2k -v2005 inverter.v
Elaboration time unknown or bad value encountered for generate if-statement
condition expression.
Please make sure it is elaboration time constant.
Someone mind explaining to me what I am doing wrong? Very new to all of this, and very confused :). Thanks!
assign statements like this declare combinatorial hardware which drive the assigned wire. Since you have put if/else around it it looks like you are generating hardware on the fly as required, which you can not do. Generate statements are away of paramertising code with variable instance based on constant parameters which is why in this situation you get that quite confusing error.
Two solutions:
Use a ternary operator to select the value.
assign bnot[0] = b[0] ? 1'b0 : 1'b1;
Which is the same as assign bnot[0] = ~b[0].
Or use a combinatorial always block, output must be declared as reg.
module inverter(
input [7:0] b,
output reg [7:0] bnot
);
always #* begin
if (b[0] == 0) begin
bnot[0] = 1;
end else begin
bnot[0] = 0;
end
end
Note in the above example the output is declared as reg not wire, we wrap code with an always #* and we do not use assign keyword.
Verliog reg vs wire is a simulator optimisation and you just need to use the correct one, further answers which elaborate on this are Verilog Input Output types, SystemVerilog datatypes.

Resources