mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-04-28 13:08:01 +00:00
FPU: Fix comparison of remainder in square root code
The square root procedure needs to compare B - R^2 with 2R + 1 to decide whether to increment the square root estimate R by 1. It currently does this by putting 2R + 1 in B and using the pcmpb_lt and pcmpb_eq signals. This is not correct because the comparisons that generate those signals have a 2-bit shift embedded into them. Instead, put 2R + 1 into C and use pcmpc_lt/eq, which don't have the 2-bit shift. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
16
fpu.vhdl
16
fpu.vhdl
@@ -1303,6 +1303,9 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
|
|
||||||
-- Compare P with zero and with B
|
-- Compare P with zero and with B
|
||||||
|
-- This has a 2-bit shift in it (p(59..4) compared to b(57..2))
|
||||||
|
-- because it's used in the FP division code to determine whether
|
||||||
|
-- to increment the quotient at bit 2 (DP_RBIT).
|
||||||
px_nz := or (r.p(UNIT_BIT + 1 downto 4));
|
px_nz := or (r.p(UNIT_BIT + 1 downto 4));
|
||||||
pcmpb_eq := '0';
|
pcmpb_eq := '0';
|
||||||
if r.p(59 downto 4) = r.b.mantissa(UNIT_BIT + 1 downto DP_RBIT) then
|
if r.p(59 downto 4) = r.b.mantissa(UNIT_BIT + 1 downto DP_RBIT) then
|
||||||
@@ -1314,6 +1317,9 @@ begin
|
|||||||
elsif unsigned(r.p(59 downto 4)) < unsigned(r.b.mantissa(UNIT_BIT + 1 downto DP_RBIT)) then
|
elsif unsigned(r.p(59 downto 4)) < unsigned(r.b.mantissa(UNIT_BIT + 1 downto DP_RBIT)) then
|
||||||
pcmpb_lt := '1';
|
pcmpb_lt := '1';
|
||||||
end if;
|
end if;
|
||||||
|
-- Compare P with zero and with C
|
||||||
|
-- This is used in the square root and integer division code
|
||||||
|
-- to decide whether to increment the result by 1
|
||||||
pcmpc_eq := '0';
|
pcmpc_eq := '0';
|
||||||
if r.p = r.c.mantissa then
|
if r.p = r.c.mantissa then
|
||||||
pcmpc_eq := '1';
|
pcmpc_eq := '1';
|
||||||
@@ -2271,29 +2277,29 @@ begin
|
|||||||
|
|
||||||
when SQRT_11 =>
|
when SQRT_11 =>
|
||||||
-- compute P = A - R * R (remainder)
|
-- compute P = A - R * R (remainder)
|
||||||
-- also put 2 * R + 1 into B for comparison with P
|
-- also put 2 * R + 1 into C for comparison with P
|
||||||
msel_1 <= MUL1_R;
|
msel_1 <= MUL1_R;
|
||||||
msel_2 <= MUL2_R;
|
msel_2 <= MUL2_R;
|
||||||
msel_add <= MULADD_A;
|
msel_add <= MULADD_A;
|
||||||
msel_inv <= '1';
|
msel_inv <= '1';
|
||||||
f_to_multiply.valid <= r.first;
|
f_to_multiply.valid <= r.first;
|
||||||
shiftin := '1';
|
shiftin := '1';
|
||||||
set_b := r.first;
|
set_c := r.first;
|
||||||
if multiply_to_f.valid = '1' then
|
if multiply_to_f.valid = '1' then
|
||||||
v.state := SQRT_12;
|
v.state := SQRT_12;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
when SQRT_12 =>
|
when SQRT_12 =>
|
||||||
-- test if remainder is 0 or >= B = 2*R + 1
|
-- test if remainder is 0 or >= C = 2*R + 1
|
||||||
set_r := '0';
|
set_r := '0';
|
||||||
opsel_c <= CIN_INC;
|
opsel_c <= CIN_INC;
|
||||||
if pcmpb_lt = '1' then
|
if pcmpc_lt = '1' then
|
||||||
-- square root is correct, set X if remainder non-zero
|
-- square root is correct, set X if remainder non-zero
|
||||||
v.x := r.p(UNIT_BIT + 2) or px_nz;
|
v.x := r.p(UNIT_BIT + 2) or px_nz;
|
||||||
else
|
else
|
||||||
-- square root needs to be incremented by 1
|
-- square root needs to be incremented by 1
|
||||||
set_r := '1';
|
set_r := '1';
|
||||||
v.x := not pcmpb_eq;
|
v.x := not pcmpc_eq;
|
||||||
end if;
|
end if;
|
||||||
v.state := FINISH;
|
v.state := FINISH;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user