FPU: Fix setting of FPRF

The sign recorded in FPRF was sometimes wrong because we weren't doing
the modifications that were done in pack_dp when setting FPRF (FPSCR
field).  These modifications are: set sign for zero result of
subtraction based on rounding mode; negate result for fnmadd/sub;
but don't modify sign of NaNs.

Instead we now do these modifications in the main state machine code
and put the result in an 'rsign' variable that is used to set
v.res_sign, then r.res_sign is used in the next cycle both for setting
FPRF and in the pack_dp functions.  That simplifies pack_dp and lets
us get rid of r.res_negate, r.res_subtract and r.res_rmode.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/425/head
Paul Mackerras 3 months ago
parent 9a4f0c18e1
commit eecf1ca399

@ -169,9 +169,7 @@ architecture behaviour of fpu is
oe : std_ulogic;
xerc : xer_common_t;
xerc_result : xer_common_t;
res_negate : std_ulogic;
res_subtract : std_ulogic;
res_rmode : std_ulogic_vector(2 downto 0);
res_sign : std_ulogic;
end record;

type lookup_table is array(0 to 1023) of std_ulogic_vector(17 downto 0);
@ -609,20 +607,13 @@ architecture behaviour of fpu is

-- Construct a DP floating-point result from components
function pack_dp(negative: std_ulogic; class: fp_number_class; exp: signed(EXP_BITS-1 downto 0);
mantissa: std_ulogic_vector; single_prec: std_ulogic; quieten_nan: std_ulogic;
negate: std_ulogic; is_subtract: std_ulogic; round_mode: std_ulogic_vector)
mantissa: std_ulogic_vector; single_prec: std_ulogic; quieten_nan: std_ulogic)
return std_ulogic_vector is
variable dp_result : std_ulogic_vector(63 downto 0);
variable sign : std_ulogic;
begin
dp_result := (others => '0');
sign := negative;
case class is
when ZERO =>
if is_subtract = '1' then
-- set result sign depending on rounding mode
sign := round_mode(0) and round_mode(1);
end if;
when FINITE =>
if mantissa(UNIT_BIT) = '1' then
-- normalized number
@ -642,7 +633,7 @@ architecture behaviour of fpu is
dp_result(28 downto 0) := mantissa(SP_LSB - 1 downto DP_LSB);
end if;
end case;
dp_result(63) := sign xor negate;
dp_result(63) := negative;
return dp_result;
end;

@ -860,6 +851,7 @@ begin
variable opcbits : std_ulogic_vector(4 downto 0);
variable int_result : std_ulogic;
variable illegal : std_ulogic;
variable rsign : std_ulogic;
begin
v := r;
v.complete := '0';
@ -2590,7 +2582,6 @@ begin
arith_done := '1';

when NAN_RESULT =>
v.negate := '0';
if (r.use_a = '1' and r.a.class = NAN and r.a.mantissa(QNAN_BIT) = '0') or
(r.use_b = '1' and r.b.class = NAN and r.b.mantissa(QNAN_BIT) = '0') or
(r.use_c = '1' and r.c.class = NAN and r.c.mantissa(QNAN_BIT) = '0') then
@ -3158,14 +3149,14 @@ begin

end case;

rsign := v.result_sign;
if zero_divide = '1' then
v.fpscr(FPSCR_ZX) := '1';
end if;
if qnan_result = '1' then
invalid := '1';
v.result_class := NAN;
v.result_sign := '0';
v.negate := '0';
rsign := '0';
misc_sel <= "0001";
opsel_r <= RES_MISC;
arith_done := '1';
@ -3181,6 +3172,12 @@ begin
v.writing_fpr := '1';
v.update_fprf := '1';
end if;
if v.is_subtract = '1' and v.result_class = ZERO then
rsign := r.round_mode(0) and r.round_mode(1);
end if;
if v.negate = '1' and v.result_class /= NAN then
rsign := not rsign;
end if;
v.instr_done := '1';
update_fx := '1';
end if;
@ -3516,7 +3513,7 @@ begin
end if;

if r.update_fprf = '1' then
v.fpscr(FPSCR_C downto FPSCR_FU) := result_flags(r.result_sign, r.result_class,
v.fpscr(FPSCR_C downto FPSCR_FU) := result_flags(r.res_sign, r.result_class,
r.r(UNIT_BIT) and not r.denorm);
end if;

@ -3541,9 +3538,7 @@ begin
v.int_result := int_result;
v.illegal := illegal;
v.nsnan_result := v.quieten_nan;
v.res_negate := v.negate;
v.res_subtract := v.is_subtract;
v.res_rmode := r.round_mode;
v.res_sign := rsign;
if r.integer_op = '1' then
v.cr_mask := num_to_fxm(0);
elsif r.is_cmp = '0' then
@ -3574,9 +3569,8 @@ begin
if r.int_result = '1' then
fp_result <= r.r;
else
fp_result <= pack_dp(r.result_sign, r.result_class, r.result_exp, r.r,
r.sp_result, r.nsnan_result,
r.res_negate, r.res_subtract, r.res_rmode);
fp_result <= pack_dp(r.res_sign, r.result_class, r.result_exp, r.r,
r.sp_result, r.nsnan_result);
end if;

rin <= v;

Loading…
Cancel
Save