mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-13 15:18:09 +00:00
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>
This commit is contained in:
parent
9a4f0c18e1
commit
eecf1ca399
38
fpu.vhdl
38
fpu.vhdl
@ -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…
x
Reference in New Issue
Block a user