01-10-2014 04:12 PM
The following test case is synthesized to a constant zero output by Vivado:
module issue_004(a, b, y); input a, b; output signed [1:0] y; // for some reason vivado thinks this is constant 0. // this is obviously not true for a=1 and b=0. assign y = $signed(a >>> b); endmodule
Interestingly the bug goes away when y is not declared signed, even though the signedness of the left hand side of a verilog assign statement should have no effect on the statement at all (see Sec. 5.5.3 of IEEE Std 1364-2005).
This is with Vivado 2013.4 and the following TCL script:
read_verilog issue_004.v synth_design -part xc7k70t -top issue_004 write_verilog -force issue_004_netlist.v
Note: This is a bug report. I don't need support.
01-10-2014 07:09 PM - edited 01-10-2014 07:26 PM
You haven't given us all the information... What is the code that does work? Is it
module issue_004(a, b, y); input a, b; output [1:0] y; // for some reason vivado thinks this is constant 0. // this is obviously not true for a=1 and b=0. assign y = a >>> b; endmodule
If so, then this is not a bug...
In Verilog, each operation has a size. The size of the operation is determined by
- the size of the operands and
- the size of the left-hand side (sometimes)
For the >>> operator, the right hand operand is "self determined", so the size of b doesn't matter. So, based on the operands alone, the size of the operation is 1 bit (since a is one bit).
However, if you go
y = a >>> b;
the size of the left hand side is 2 bits, so the operation becomes 2 bits. Since the operation is 2 bits unsigned, it can definitely hold your two possible output values (which are 1 for a=1, b=0, and 0 for all other combinations of a and b), which is then assigned to y.
However, when you go
y = $signed(a >>> b)
you actually have two operations
- the a >>> b is one
- the $signed system function is another
So, in this case, the inner operation (the a >>> b) doesn't SEE the left hand side, since it is obscured by the outer operation (the $signed system function). So the >>> operation is one bit wide and the result of the operation is one bit.
When you cast that to a signed quantity, it is cast to a one bit signed quantity; see clause 5.5 of Std 1364-2005 - the $signed system function shall ".... return a value with the same size and value of the input expression..."; since the inner expression is one bit, the $signed function returns a one bit signed value. A one bit signed quantity can only hold the values 0 and -1. For a=1, b=0, your result is 1, so it can't be represented in a one bit signed quantity. This is why it is always 0.
If you do
assign y = $signed({1'b0,a}) >>> b;
This should work, 'a' will be converted to a TWO bit signed value, which will then be arithmatically shifted right by the number of bits specified by b. For most expressions, b would also have to be signed, but since the right operand of the shift operation is self determined, it doesn't need to be in this case.
Avrum
01-10-2014 08:59 PM
Your analysis is correct except for your final point:
[...] A one bit signed quantity can only hold the values 0 and -1. For a=1, b=0, your result is 1, so it can't be represented in a one bit signed quantity. This is why it is always 0.
For sign extension the Verilog standard does not care about semantics, only about the bit pattern. When the MSB is set then all added padding bits should also be set. So the result should be sign extended to 2'b11.
Or in other words, a=1 should just be treated as a=-1 for a 1-bit a and then sign extended accordingly.
Also if your argument would be right then..
1. There would be a vivado bug when y is declared as output [1:0] y; without the signed. Because in this case Vivado does perform the sign extension to 2'b11 and the signdness of the left-hand side should not have any effect here.
2. There would be bugs in XST 14.7, Modelsim 10.1d, Isim 14.7 and Quartus 13.1 becasue they all do the sign extension. (Which is a bit of a weak empirical argument, but it adds to the other things..)
Also consider the following test case:
module issue_004(y); wire a = 1, b = 0; output signed [1:0] y; assign y = $signed(a >>> b); endmodule
It is the same as above, only that a and b are now set to constant 1 and 0 respectively. In this case Vivado shows the imo correct behavior and sets y to constant 2'b11. So there even would be a bug in Vivado if 2'b00 would be the correct result.
I hope this all together is convincing that this actually is a bug in Vivado.
Just on a side note because I enjoy discussing the Verilog standard:
For most expressions, b would also have to be signed, but since the right operand of the shift operation is self determined, it doesn't need to be in this case.
Not only is the right operand of a shift operation self determined, it also is always treated as unsigned and explicitely has no effect on the signdness of the result. See sec. 5.1.12 of the standard:
[...] The right operand is always treated as an unsigned number and has no effect on the signedness of
the result. [...]
Just being self determined would not automatically imply that it would not effect the signdness of the result. The right operand of the power operator ** is also self-determined but influences the signedness of the result.
01-11-2014 11:59 AM
You are right. The examples in the LRM show that $signed(1'b1) should return the one bit signed value -1. This would then be sign extended when assigned to Y, so would be 2'sd11.
So, I agree - this appears to be a bug in Vivado synthesis.
Avrum
05-14-2014 03:53 AM
Hi Clifford,
first of all, my sincere apologies that so far nobody took the responsibility to investigate and file a CR.
Please do keep your bug reports coming!
We highly appreciate such clear-cut cases with small testcases. That makes filing a CR much easier for us & for development to better understand the issue and resolve it.
I ran an equivalence check against the generated verilog netlist of 2014.1, 2014.2 RC and 2014.3 alpha.
In all cases the behaviour was the same and the netlist does not match the RTL code.
I filed CR799204 to get this fixed in our tools. Unfortunately I can't promise that it will make 2014.2 as we are getting relative close to release data, but I'm pretty confident it will make 2014.3.
Best regards
Dries
06-20-2014 02:51 AM
Hi Clifford,
I'm happy to inform you that this bug has been fixed in an early build of 2014.3.
Release is scheduled in the October timeframe.
Best regards
Dries