The number '0' not working how I expect in Verilog - verilog

I had some strange behavior when synthesizing some code with the expression:
logic [7:0] x;
//...
if ((~x) == 0)
In a situation where x is 8'hff), the above boolean evaluates to false. I saw this behavior in synthesized hardware and double-checked it in simulation.
Of course, changing the expression to
if ((~x) == '0)
Gives me the behavior I expect; It evaluates to true when x is 8'hff.
My question:
Why does adding the tick mark fix this problem? 0 by itself should give me an unsigned integer with width 32, and (~x) should give me an 8-bit unsigned number. Whether or not I specify the width of my 0, the result ought to be the same.
I assume that I'm missing something about signedness or type promotion in the Verilog spec.
Example code:
You can see this behavior across all Commercial simulators at this EDA playground link.
In case you have trouble accessing it, the code at the link is
module tb;
logic [7:0] x;
logic [7:0] y;
initial begin
x <= 8'hff;
y <= 8'h00;
#1;
$display("((~x) == 0) evaluates to %b", (~x) == 0); #1;
$display("((~x) == '0) evaluates to %b", (~x) == '0); #1;
$display("((y) == 0) evaluates to %b", (y) == 0); #1;
$display("((y) == 0) evaluates to %b", (y) == '0); #1;
$display("((~y) == ~0) evaluates to %b", (~y) == ~0); #1;
$finish;
end
endmodule

This is because operands get extended before apply any operations within the same context.
Since the width of the unsized decimal literal 0 is 32, the equality operator extends the width of the smaller operand to the width of the larger operand. So 8'hFF becomes 32'h0000_00FF. Then the bitwise-negation operator ~ gets applied.
The width of fill literal '0 depends on its context. When self-determined, its width is 1 bit. However, when in the context of the equality operator, its width gets extended to the width of x, which is 8-bits.
You can get the behavior you want by using the fill literal, or making sure there is no operand extension either by:
if ((~x) == 8'b0) // No extension -- both sides are 8-bits
or use a concatenation:
if ({~x} == 8'b0)
The concatenation works because each operand of a concatenation is self-determined. Only the result of the concatenation is the context of the equality expression.

Related

Clean way to truncate result of addition or subtraction

When I do addition or subtraction in Verilog, some compilers emit warning.
// code example
logic [9 : 0] a, b, c;
always_ff #(posedge clk) begin
b <= a + 1;
c <= a - 1;
end
// warning example
Warning (13469): Verilog HDL assignment warning at xxx.sv(xxx): truncated value with size 11 to match size of target (10) File: xxx.sv Line: xxx
Warning (13469): Verilog HDL assignment warning at xxx.sv(xxx): truncated value with size 32 to match size of target (10) File: xxx.sv Line: xxx
I want to find clean way to remove these warnings. I tried two methods:
// method 1
b <= (a + 1)[9 : 0];
// method 2
logic [10 : 0] d;
d <= a + 1;
b <= d[9 : 0];
I thought the first method would compile, but it was invalid syntax in verilog.
Second method works, but it is too verbose and dirty.
Is there any other clean ways?
From IEEE Std 1364-2001.
Page 73:
Table 29—Bit lengths resulting from self-determined expressions:
Unsized constant number = Same as integer
Page 45:
NOTE Implementations may limit the maximum size of an integer variable, but they shall at least be 32 bits.
So the warnings you see come from trying to operate one unsized numeric constant (32 bits at least) with a sized variable (10 bits), so the synthesizer warns about the result may overflow.
So, just make sure all your operands have the same size:
Instead of:
// code example
logic [9 : 0] a, b, c;
always_ff #(posedge clk) begin
b <= a + 1;
c <= a - 1;
end
Do:
// code example
logic [9 : 0] a, b, c;
always_ff #(posedge clk) begin
b <= a + 10'd1;
c <= a - 10'd1;
end
1 id a 32-bit value. As a result the width of the expression is 32.
The way around is to use a sized value of '1', i.e.
b <= a + 1'b1;
c <= b - 1'b1;
This can potentially give you an 11-bit result. Carryon bit will be lost. At this point you can do some other tricks. I guess this is the most common one. Use a carry on bit.
logic con;
logic[9:0] a,b;
...
{con, a} <= b + 1'b1;
You can use a temp variable, as in your example.
In general, verilog standard does allow free truncation or extension of operand widths and no warning is required. Definitely in this case you can ignore the warning or turn it off. I have not seen simulators which would warn about it. Just certain rule in linting tools.
Use curley concatination braces
b <= {a + 1}[9 : 0];
or change the constant size (which defaults to 32-bits)
b <= a + 10'd1;

Verilog : Variable index is not supported in signal

I get an error saying 'Index is not supported in signal'. From what I can see the error is on the left hand side of the non-blocking assignment. Why does the code below give an error and is there a way to work around it?
...
parameter width = 32;
parameter size = 3;
input clk, reset;
input [width*size-1:0] A;
input [width*size-1:0] B;
output [width*size-1:0] result;
reg signed [width*size-1:0] partials;
reg signed [width-1:0] temp;
reg signed [width-1:0] currenta;
reg signed [width-1:0] currentb;
wire signed [width-1:0] temp1wire;
...
integer k = 0;
always # (posedge clk)
begin
currenta[width-1:0] <= A[width*k +: width];
k = k+1
currentb[width-1:0] <= B[width*k +: width];
partials[width*k +: width] <= temp1wire;
end
Add Add1(clk, temp1wire, currenta, currentb);
...
This code is part of a sequential block that does vector addition and saves the result at partials[width*k +: width].
I found this on the Xilinx forum:
"XST works fine with the indexed part-select operator "+:" if it is on the right-hand side (RHS) of the assignment. It also works fine when it is on the left-hand side (LHS) AND the starting index is a constant. Your case uses a variable as the starting index on the LHS and that what XST doesn't like although it's legal."
k needs to be clamped or wrapped around after reaching size-1.
Wrapping around can be done with the mod operator (%); example:k = (k+1)%size. % may not synthesize optimally (check your synthesizer), so a if-statement is a functional alternative if(k==SIZE-1) k = 0; else k=k+1;
Suggestions:
It is generally recommenced to keep parameters as uppercase, this way you can easily identity parameters form signal names. Putting a blocking assignment inside a sequential block is legal, but most design rules recommend separating combinational logic from sequential assignments. I would prefer writing your code like the following:
// $clog is IEEE1364-2005 § 17.11, some synthesizers support it, others don't
reg [$clog2(SIZE):0] k=0, next_k;
always #* begin
if (k==SIZE-1) begin
next_k = 0; // wrap around
// next_k = k; // clamp
end
else begin
next_k = k+1;
end
end
always # (posedge clk)
begin
currenta[WIDTH-1:0] <= A[WIDTH*k +: WIDTH];
currentb[WIDTH-1:0] <= A[WIDTH*next_k +: WIDTH];
partials[WIDTH*next_k +: WIDTH] <= temp1wire;
k <= next_k;
end

systemverilog arithmetic operation returns negative value

I have a part of code of my design as follows.
parameter n=256;
input [n-1:0] x;
output y;
initial begin
x = 0;
if(0 >= unsigned'(x-9))
y = 1;
end
My expectation is, the unsigned subtraction operation should return decimal 247 but in actual it returns -9. Is anyone having better way of coding to achieve this?
My actual requirement is, even if I subtract a smaller value from larger, the value should rollover w.r.t. parameter width (As if 0-1 should yield 255). My question may be wrong but this requirement is necessary from my project.
247 and -9 are the same bit pattern so the arithmetic is correct. Signed vs unsigned is an interpretation of the bit pattern.
NB: 0-1 is only 255 with 8 bit numbers you have defined them as 256 bit numbers.
The following example should help clarify, We use $signed and $unsigned keywords which alters how the decimal representation is displayed but the underlying binary form does not change.
module tb;
parameter n=8;
logic [n-1:0] x;
logic y;
initial begin
x = 0;
$display("%1d", x-9);
$display("%1b", x-9);
$display("");
$display("%1d", $unsigned(x-9) );
$display("%1b", $unsigned(x-9) );
$display("");
$display("%1d", $signed(x-9) );
$display("%1b", $signed(x-9) );
$display("");
$finish;
end
endmodule
Which Outputs:
4294967287
11111111111111111111111111110111
4294967287
11111111111111111111111111110111
-9
11111111111111111111111111110111
For your example you just need to use $unsigned:
module tb;
parameter n=8;
logic [n-1:0] x;
logic y;
initial begin
x = 0;
if(0 >= $unsigned(x-9)) begin
y = 1;
end
else begin
y = 0;
end
$display("y: %b", y);
$finish;
end
endmodule

Verilog Signed Multiplication "loses" the Signed Bit

I am writing a code which uses a multiplier module which returns weird answers when one of the inputs is a negative number. I am guessing this has to do with how Verilog treats signed numbers and the module is not storing the result properly in the 'reg signed out' decleration. All my input/output/wire/reg declarations are signed, so I am not sure what I am missing and what else I need to do to tell Verilog to take care of this. Sorry for the beginner question!
For example,
When X[0] is 1610 and Theta1[1] is -123, the result I am getting from the multiplier module is:
6914897148530
Here are the relevant parts of my code:
module mult(in1, in2, out, mult_start); // multiplication module
input signed [32-1:0] in1, in2;
input mult_start;
output signed [64-1:0] out;
reg signed [64-1:0] out;
always #(in1 or in2 or mult_start)
begin
if (mult_start)
begin
out <= (in1 * in2) & {64{1'b1}};
end
else
out <= out;
end
endmodule
module child_one (clk, rst_b, sig_start, Input_X, Input_Theta1)
// Internal Variables Memory
reg signed [`REG_LENGTH-1:0] Theta1 [0:217-1];
reg signed [`REG_LENGTH-1:0] X [0:216-1];
wire signed [`OUT_LENGTH-1:0] prod_1 [0:217-1];
reg signed [`OUT_LENGTH-1:0] prod_sum;
wire signed [`OUT_LENGTH-1:0] sig_result;
mult mult_001 (X[0], Theta1[1], prod_1[1], mult_start);
mult mult_002 (X[1], Theta1[2], prod_1[2], mult_start);
mult mult_003 (X[2], Theta1[3], prod_1[3], mult_start);
mult mult_004 (X[3], Theta1[4], prod_1[4], mult_start);
always #(posedge clk or negedge rst_b)
begin
if (sig_start == 1)
begin
if (state == 4'b0000)
begin
state <= 4'b0001; // initialize state variable to zero
k <= 0;
result_done <= 0;
index <= 0;
end
else if (state == 4'b0001) // Start Multiplication Operation
begin
k <= result_done ? 0 : k + 1;
result_done <= result_done ? 1 : (k == 10);
state <= result_done ? 4'b0010 : 4'b0001;
mult_start <= result_done ? 1'b1 : 1'b0;
//mult_start <= 1'b1;
//state <= 4'b0010;
end
else if (state == 4'b0010) // Stop Multiplication Operation
begin
k <= 0;
result_done <= 0;
mult_start <= 0;
state <= 4'b0011;
end
end
end
endmodule
Thanks,
Faisal.
Thanks for all the help and suggestions. Writing a separate testbench for the mult module helped arrive at a solution.
My issue was in the mult module. Since my inputs are 32 bits long, the mult output would be 32*2+1 = 65 bits long. My output port 'out' was only assigned to be 64 bits long which resulted in a sign issue when the answer was a negative number. Assigning it to be 65 bits long took care of my problem.
The issue is the & {64{1'b1}} part in the mult module. {64{1'b1}} is an unsigned subexpression. This causes in1 and in2 and to be treated as unsigned regardless of their declaration, and causes unsigned multiplication to be performed. The resulting bits assigned to out are then interpreted as signed again because of its declaration, but by then it's too late.
As you alluded to, the general Verilog signedness rule is that if any operand in a simple expression is unsigned, all operands in the expression are interpreted as unsigned, and thus the operators perform unsigned math. (There are many other nuances to the rules (e.g. relational operators), but they aren't applicable here.)
Note that you can't make {64{1'b1}} signed by changing it to {64{1'sb1}} because the result of the replication operator is always unsigned regardless of its operand. But you could wrap it in the $signed() system function, making the rest of the expression (the * and & steps) fully signed. Thus this would work correctly:
out <= (in1 * in2) & $signed({64{1'b1}});
But you really don't need to mask the result with that &. Regardless of the width of the inputs and the result of the multiplication, Verilog rules state that the final value of the RHS of the assignment will simply be truncated (discarding some MSBs) to the width of the LHS, if the RHS were wider. Thus masking with 64 ones is completely redundant.
To address the currently-accepted answer... It is not true that 65 bits are needed for 32x32 signed->signed multiplication. Only 64 bits are needed to handle even the most-extreme cases:
minimum result: -(2^31) * ((2^31) - 1) = -4611686016279904256 > -(2^63)
maximum result: ((2^31) - 1) * ((2^31) - 1) = 4611686014132420609 < (2^63) - 1
In general, for fully-signed multiplication of N bits by M bits, you only need N+M bits for the product (and N+M-1 would suffice if not for the single most-negative times most-negative case). This is also true for fully-unsigned multiplication. But if you were mixing signed and unsigned multiplicands/product (and using $signed() as needed to get Verilog to behave as desired), you would need an extra result bit in some cases (e.g. unsigned*unsigned->signed).

How do I convert a number to two's complement in verilog?

I am trying to design a 4-bit adder subtracter in verilog. This is only the second thing I have ever written in verilog, and I don't know all the correct syntax yet. This is the module I have so far:
module Question3(carryin, X, Y, Z, S, carryout, overflow);
parameter n = 4;
input carryin, Z;
input [n-1:0]X, Y;
output reg [n-1:0]S;
output reg carryout, overflow;
if(Z==0)
begin
Y = not(y) + 4'b0001;
end
always #(X, Y, carryin)
begin
{carryout, S} = X + Y + carryin;
overflow = carryout ^ X[n-1]^Y[n-1]^S[n-1];
end
endmodule
My compiler (xilinx 10.1), keeps saying "Syntax error near if." I have tried many different ways of doing the conversion, including just using a Case that takes Y as an argument, then checks all the possible 4-bit combinations, and converts them to two's complement.
Z is what determines if the adder does subtraction or addition. If it's 0, it means subtraction, and I want to convert y to two's complement, then just do regular addition. I'm sure the rest of the adder is correct, I just do not know what is wrong with the part where I'm trying to convert.
reg [n-1:0] Y_compl;
always #( Z, Y, X, carryin ) begin
Y_ = ( ~Y + 4'b0001 );
if ( Z == 1'b0 ) begin
{carryout, S} = X + Y_compl + carryin;
overflow = carryout ^ X[n-1] ^ Y_compl[n-1] ^ S[n-1];
end
else begin
{carryout, S} = X + Y + carryin;
overflow = carryout ^ X[n-1] ^ Y[n-1] ^ S[n-1];
end
end
A couple of important points.
Put the if statement inside the always block. Do not use two always blocks, you'll create a race condition in the simulator.
I created a new variable, Y_ because using Y, which is an input, remember, on the left hand side of an assignment will probably infer latches or do something else nasty when you synthesize.
I suggest using the bitwise inversion operator '~' to invert Y instead if the 'not'
primitive. The synthesis tool has more freedom to optimize your code this way.
Double check for correct results, it's been awhile since I built an adder.
You are using a lower case "y" in "Y = not(y) + 4'b0001;"
Also, you're using more additions than you need to. X-Y is the same thing as NOT(NOT(X)+Y).
put the if statement within an initial block
http://www.asic-world.com/verilog/vbehave1.html

Resources