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:
Alexander Klimov 2011-09-15 00:33:12 +03:00 committed by Stephen Williams
parent 354abcc9bd
commit 5c6c8deba3
1 changed files with 4 additions and 2 deletions

View File

@ -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