Fix long division.
On a 64-bit machine the following module shows incorrect division
results:
`define X {4'b 1000, `N'b 0}
`define Y {1'b 1, `N'b 0}
module b;
reg [`N:0] y = `Y;
reg [3:0] z1, z2;
initial begin
z1 = `X / `Y;
z2 = `X / y;
$display("%3d %b %b", `N, z1, z2);
end
endmodule // b
$ for N in {60..65}; do /usr/bin/iverilog -DN=$N -oa b.v && /usr/bin/vvp a; done
60 1000 1000
61 1000 1000
62 1000 0111
63 1000 0101
64 1000 1000
65 1000 1000
The first chunk of the patch (result -> tmp_result) fixes this:
$ for N in {60..65}; do iverilog -DN=$N -oa b.v && vvp a; done
60 1000 1000
61 1000 1000
62 1000 1000
63 1000 1000
64 1000 1000
65 1000 1000
The second chunk fixes
`define X 264'h 800000000000000000000000000000000000000000000000000000000000000000
`define Y 192'h c6df998d06b97b0db1f056638484d609c0895e8112153524
module c;
reg [191:0] y = `Y;
reg [72:0] z1, z2;
initial begin
z1 = `X / `Y;
z2 = `X / y;
$display("%x %x %b", z1, z2, z1 == z2);
end
endmodule // c
$ /usr/bin/iverilog -oa c.v && /usr/bin/vvp a
0a4c4a2c1dacd76220c 0809033397ca3427927 0
$ iverilog -oa c.v && vvp a
0a4c4a2c1dacd76220c 0a4c4a2c1dacd76220c 1
(cherry picked from commit 766bf45dcf)
This commit is contained in:
parent
354abcc9bd
commit
5c6c8deba3
|
|
@ -1956,7 +1956,7 @@ static unsigned long divide2words(unsigned long a, unsigned long b,
|
|||
remain += 1;
|
||||
if (remain >= b) {
|
||||
remain -= b;
|
||||
result += 1;
|
||||
tmp_result += 1;
|
||||
}
|
||||
|
||||
// Now 0x1_0...0 = b*tmp_result + remain
|
||||
|
|
@ -1972,7 +1972,9 @@ static unsigned long divide2words(unsigned long a, unsigned long b,
|
|||
|
||||
// The new iteration starts with high*remain + a.
|
||||
remain = multiply_with_carry(high, remain, high);
|
||||
a = add_with_carry(a, remain, high);
|
||||
a += remain;
|
||||
if(a < remain)
|
||||
high += 1;
|
||||
|
||||
// Now result*b + {high,a} == the input {high,a}. It is
|
||||
// possible that the new high >= 1. If so, it will
|
||||
|
|
|
|||
Loading…
Reference in New Issue