From e4715812227160743d4c4ac08bc6f56e0e37cbc9 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Dec 2025 19:12:03 +1100 Subject: [PATCH] FPU: Do result processing on denorm short-circuit results when FPSCR[UE] is set Results that are tiny (i.e., in the denorm range) need special processing when underflow exceptions are enabled, including in the cases where the result is just one of the input operands, such as for a fmadd with A or C equal to zero. To make sure this gets done, go to FINISH state rather than returning the relevant input operand as the result. The same logic is now used when the result needs to be rounded to single precision. Signed-off-by: Paul Mackerras --- fpu.vhdl | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/fpu.vhdl b/fpu.vhdl index 2b5d556..84cec59 100644 --- a/fpu.vhdl +++ b/fpu.vhdl @@ -98,6 +98,7 @@ architecture behaviour of fpu is zero_divide : std_ulogic; new_fpscr : std_ulogic_vector(31 downto 0); immed_result : std_ulogic; -- result is an input, zero, infinity or NaN + need_finish : std_ulogic; -- result needs further processing qnan_result : std_ulogic; result_sel : std_ulogic_vector(2 downto 0); result_class : fp_number_class; @@ -833,6 +834,7 @@ begin e.zero_divide := '0'; e.new_fpscr := (others => '0'); e.immed_result := '0'; + e.need_finish := '0'; e.qnan_result := '0'; e.result_sel := AIN_ZERO; e.result_class := FINITE; @@ -912,6 +914,10 @@ begin e.result_sel := AIN_B; e.result_class := r.b.class; -- r.result_sign is already correct + if r.b.class = FINITE and r.int_result = '0' and + (r.single_prec = '1' or (r.fpscr(FPSCR_UE) = '1' and r.b.denorm = '1')) then + e.need_finish := '1'; + end if; else e.result_class := ZERO; end if; @@ -926,6 +932,10 @@ begin e.immed_result := '1'; e.result_sel := AIN_B; e.result_class := r.b.class; + if r.b.class = FINITE and r.int_result = '0' and + (r.single_prec = '1' or (r.fpscr(FPSCR_UE) = '1' and r.b.denorm = '1')) then + e.need_finish := '1'; + end if; elsif r.use_b = '1' and r.b.class = ZERO and r.is_multiply = '0' then -- B is zero, other operands are finite @@ -939,6 +949,10 @@ begin -- fadd, result is A e.result_sel := AIN_A; e.rsgn_op := RSGN_SEL; + if r.a.class = FINITE and r.int_result = '0' and + (r.single_prec = '1' or (r.fpscr(FPSCR_UE) = '1' and r.a.denorm = '1')) then + e.need_finish := '1'; + end if; else -- other things, result is zero e.result_class := ZERO; @@ -3108,9 +3122,9 @@ begin arith_done := '1'; else misc_sel <= "111"; - if r.single_prec = '1' and scinfo.result_class = FINITE and r.int_result = '0' then - -- we have to do the equivalent of frsp on the result - v.state := DO_FRSP_2; + if scinfo.need_finish = '1' then + -- we have to do rounding or underflow exception processing on the result + v.state := FINISH; else arith_done := '1'; end if;