From 51954671f34536d1f315c5296058bae6c978237c Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 7 Feb 2024 20:01:49 +1100 Subject: [PATCH] FPU: Fix behaviour of fdiv with denormalized divisor Renormalization of the divisor for fdiv[s] was adjusting the result exponent in the wrong direction, making the result smaller in magnitude than it should be by a power of 2. Fix this by negating r.shift in the RENORM_B2 state and then subtracting it in the LOOKUP cycle. Signed-off-by: Paul Mackerras --- fpu.vhdl | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/fpu.vhdl b/fpu.vhdl index 6fbc979..afac4c0 100644 --- a/fpu.vhdl +++ b/fpu.vhdl @@ -1817,8 +1817,17 @@ begin when RENORM_B2 => set_b := '1'; - re_sel2 <= REXP2_NE; - re_set_result <= '1'; + -- For fdiv, we need to increase result_exp by shift rather + -- than decreasing it as for fre/frsqrte and fsqrt. + -- We do that by negating r.shift in this cycle and then + -- setting result_exp to new_exp in the next cycle + if r.use_a = '1' then + rs_sel1 <= RSH1_S; + rs_neg1 <= '1'; + else + re_sel2 <= REXP2_NE; + re_set_result <= '1'; + end if; v.opsel_a := AIN_B; v.state := LOOKUP; @@ -2038,6 +2047,12 @@ begin when LOOKUP => -- r.opsel_a = AIN_B -- wait one cycle for inverse_table[B] lookup + -- if this is a division, compute exponent + -- (see comment on RENORM_B2 above) + if r.use_a = '1' then + re_sel2 <= REXP2_NE; + re_set_result <= '1'; + end if; v.first := '1'; if r.insn(4) = '0' then if r.insn(3) = '0' then