Signed arithmetic behavior in Icarus 0.8.1/0.8.2
doesn't match other Verilog simulators.
A test file that demonstrates the issues is attached.
The Icarus output is:
$ vvp a.out
p= 15659 s= -24 d=1
The output from cver is:
$ cver test.v
GPLCVER_2.11a of 07/05/05 (Linux-elf).
p= -725 s= 40 d=0
To find out which was correct, I have posted the test
file earlier on comp.lang.verilog. It was found that
the cver output matches the output from other
simulators such as modelsim, Cadence ncsim, and
Synopsys vcs.
signed arithmetic test case
Logged In: YES
user_id=97566
It appears that Icarus Verilog is indeed doing the wrong
thing here. I've also verified that this bug persists in the
devel branch. It is not doing sign extension properly.
I've switched the report to the devel group because that's
where I will fix it. I've also increased its priority
slightly because it is giving wrong results without an error
message.
Logged In: YES
user_id=97566
I've added pr1380261.v to the ivtest suite. This is a
slightly modified version of this program to facilitate
automatic testing.
Logged In: YES
user_id=1406727
I am adding an additional testcase that appears related to
this issue. In this case, I'm comparing the behavior *,/
and % when used inside of $signed(), but not on a register
declared signed. I don't think this is necessarily a smart
thing to do, but the behavior does seem inconsistent between
the operators, so I am filing the report.
As I understand the output of the test program, it looks
like * inside of $signed is treated as an unsigned multiply
(I thought that was correct, but NC and VCS disagree), while
/ and % inside of $signed are treated as signed operations.
Logged In: YES
user_id=1406727
module bug();
reg CLK, RST_N;
initial
begin
RST_N = 1'b0;
#1
CLK = 1'b1;
#1
RST_N = 1'b1;
end
always
begin
#5
CLK = 1'b0;
#5
CLK = 1'b1;
end
reg [31:0] idx1;
reg [31:0] idx2;
always@(posedge CLK)
begin
if (!RST_N)
begin
idx1 = 32'd0;
idx2 = 32'd0;
end
else
begin
if (idx1 == 30)
begin
idx1 = 0;
idx2 = idx2 + 1;
end
else
begin
idx1 = idx1 + 1;
end
end
end
reg [31:0] x;
reg [31:0] y;
always@(negedge CLK)
begin
if (RST_N)
begin
if (idx2 > 30)
$finish(32'd0);
else
begin
x = idx1 - 15;
y = idx2 - 15;
// For negative numbers, there is a consistency problem
// between *,/ and %. It appears that * is performed as
// an unsigned multiply inside $signed(), but / and
% are
// performed as signed operations inside $signed().
/* */
// result of unsigned operations are converted to signed
$display("%x * %x == %x", $signed(x), $signed(y),
$signed(x * y));
$display("%x / %x == %x", $signed(x), $signed(y),
$signed(x / y));
$display("%x %% %x == %x", $signed(x), $signed(y),
$signed(x % y));
/*
// result of unsigned operations used raw
$display("%x * %x == %x", x, y, x * y);
$display("%x / %x == %x", x, y, x / y);
$display("%x %% %x == %x", x, y, x % y);
/* */
end
end
end
endmodule
Logged In: YES
user_id=97566
This bug is fixed in the main devel trunk of CVS (as of 22 Dec 2005). The
problem was improper padding of multiplication operands and results.
Logged In: NO
the code:
....
wire signed [3:0] a;
wire signed [3:0] b;
wire signed [4:0] c;
assign a=4'b1001; //-7
assign b=4'b0011; //+3
assign c=a+b;
....
gives 01100 for c, namely +12 which is wrong, since the answer should be 11100, namely -4.
Sergio
Logged In: NO
signal processing is impractical with such a bug. I would give this issue a higher priority.
Sergio