FPU: Set FPRF correctly on multiply result that underflows

rcls_op being set to RCLS_TZERO was not detecting a zero result after
rounding for a multiply result that underflows, because S still had
low bits of the product.  To fix this, remove the 's_nz = 0' from the
RCLS_TZERO test.  We can't then use this test in the FMADD_6 state,
but we really shouldn't be testing for zero there, before rounding,
so remove that.  Also simplify FMADD_6 state by not setting rs_norm
and going always to FINISH state rather than going to NORMALIZE state.

Add a test for this case (actually a fmadd with B=0).

While here, remove a pointless assignment to f_to_multiply.valid in
MULT_1 state, since r.first is never set here.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/457/head
Paul Mackerras 2 weeks ago
parent b122577a4e
commit f631dcd700

@ -1931,7 +1931,6 @@ begin
v.instr_done := '1'; v.instr_done := '1';


when MULT_1 => when MULT_1 =>
f_to_multiply.valid <= r.first;
opsel_r <= RES_MULT; opsel_r <= RES_MULT;
set_r := '1'; set_r := '1';
opsel_s <= S_MULT; opsel_s <= S_MULT;
@ -2022,25 +2021,18 @@ begin
v.state := FMADD_6; v.state := FMADD_6;


when FMADD_6 => when FMADD_6 =>
-- r.shift = UNIT_BIT (or 0, but only if r is now nonzero) -- r.shift = UNIT_BIT
set_r := '0'; set_r := '0';
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
rs_norm <= '1';
rcls_op <= RCLS_TZERO;
if (r.r(UNIT_BIT + 2) or r_hi_nz or r_lo_nz or (or (r.r(DP_LSB - 1 downto 0)))) = '0' then if (r.r(UNIT_BIT + 2) or r_hi_nz or r_lo_nz or (or (r.r(DP_LSB - 1 downto 0)))) = '0' then
-- S = 0 case is handled by RCLS_TZERO logic, otherwise... -- R is all zeroes but there may be non-zero bits in S
-- R is all zeroes but there are non-zero bits in S
-- so shift them into R and set S to 0 -- so shift them into R and set S to 0
set_r := '1'; set_r := '1';
re_set_result <= '1'; re_set_result <= '1';
set_s := '1'; set_s := '1';
v.state := FINISH;
elsif r.r(UNIT_BIT + 2 downto UNIT_BIT) = "001" then
v.state := FINISH;
else
v.state := NORMALIZE;
end if; end if;
v.state := FINISH;


when DIV_2 => when DIV_2 =>
-- compute Y = inverse_table[B] (when count=0); P = 2 - B * Y -- compute Y = inverse_table[B] (when count=0); P = 2 - B * Y
@ -3197,7 +3189,7 @@ begin
when others => when others =>
end case; end case;
when RCLS_TZERO => when RCLS_TZERO =>
if or (r.r(UNIT_BIT + 2 downto 0)) = '0' and s_nz = '0' then if or (r.r(UNIT_BIT + 2 downto 0)) = '0' then
v.result_class := ZERO; v.result_class := ZERO;
arith_done := '1'; arith_done := '1';
end if; end if;

@ -1618,6 +1618,8 @@ struct fmavals {
/* from random exec tests */ /* from random exec tests */
{ 0x43eff79000000000, 0x00000000000000ff, 0x0000000000000081, FPS_RN_CEIL, { 0x43eff79000000000, 0x00000000000000ff, 0x0000000000000081, FPS_RN_CEIL,
0x014fd79870000001, 0x014fd79870000000, 0x814fd79870000001, 0x814fd79870000000 }, 0x014fd79870000001, 0x014fd79870000000, 0x814fd79870000001, 0x814fd79870000000 },
{ 0x00000000ffffffff, 0x1fc771af627f62ab, 0x8000000000000000, FPS_RN_ZERO,
0x0000000000000000, 0x0000000000000000, 0x8000000000000000, 0x8000000000000000 },
}; };


int test23(long arg) int test23(long arg)

Binary file not shown.
Loading…
Cancel
Save