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 <paulus@ozlabs.org>
pull/457/head
Paul Mackerras 2 weeks ago
parent 0478fe41dd
commit e471581222

@ -98,6 +98,7 @@ architecture behaviour of fpu is
zero_divide : std_ulogic; zero_divide : std_ulogic;
new_fpscr : std_ulogic_vector(31 downto 0); new_fpscr : std_ulogic_vector(31 downto 0);
immed_result : std_ulogic; -- result is an input, zero, infinity or NaN immed_result : std_ulogic; -- result is an input, zero, infinity or NaN
need_finish : std_ulogic; -- result needs further processing
qnan_result : std_ulogic; qnan_result : std_ulogic;
result_sel : std_ulogic_vector(2 downto 0); result_sel : std_ulogic_vector(2 downto 0);
result_class : fp_number_class; result_class : fp_number_class;
@ -833,6 +834,7 @@ begin
e.zero_divide := '0'; e.zero_divide := '0';
e.new_fpscr := (others => '0'); e.new_fpscr := (others => '0');
e.immed_result := '0'; e.immed_result := '0';
e.need_finish := '0';
e.qnan_result := '0'; e.qnan_result := '0';
e.result_sel := AIN_ZERO; e.result_sel := AIN_ZERO;
e.result_class := FINITE; e.result_class := FINITE;
@ -912,6 +914,10 @@ begin
e.result_sel := AIN_B; e.result_sel := AIN_B;
e.result_class := r.b.class; e.result_class := r.b.class;
-- r.result_sign is already correct -- 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 else
e.result_class := ZERO; e.result_class := ZERO;
end if; end if;
@ -926,6 +932,10 @@ begin
e.immed_result := '1'; e.immed_result := '1';
e.result_sel := AIN_B; e.result_sel := AIN_B;
e.result_class := r.b.class; 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 elsif r.use_b = '1' and r.b.class = ZERO and r.is_multiply = '0' then
-- B is zero, other operands are finite -- B is zero, other operands are finite
@ -939,6 +949,10 @@ begin
-- fadd, result is A -- fadd, result is A
e.result_sel := AIN_A; e.result_sel := AIN_A;
e.rsgn_op := RSGN_SEL; 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 else
-- other things, result is zero -- other things, result is zero
e.result_class := ZERO; e.result_class := ZERO;
@ -3108,9 +3122,9 @@ begin
arith_done := '1'; arith_done := '1';
else else
misc_sel <= "111"; misc_sel <= "111";
if r.single_prec = '1' and scinfo.result_class = FINITE and r.int_result = '0' then if scinfo.need_finish = '1' then
-- we have to do the equivalent of frsp on the result -- we have to do rounding or underflow exception processing on the result
v.state := DO_FRSP_2; v.state := FINISH;
else else
arith_done := '1'; arith_done := '1';
end if; end if;

Loading…
Cancel
Save