mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-21 18:05:15 +00:00
FPU: Set sign of 0 result of subtraction in pack_dp
When a floating-point subtraction results in a zero result, the sign of the result is required to be positive in all rounding modes except the round to minus infinity mode, when it is negative. Consolidate the logic for doing this in one place, in the pack_dp function, instead of having it at each place where a zero result is generated. Since fnmadd[s] and fnmsub[s] negate the result after this rule has been applied, we use the r.negate signal to indicate a negation which is now done in pack_dp. Thus the EXC_RESULT state no longer uses r.negate, and in fact doesn't set v.result_sign at all; that is now done in the states that lead into EXC_RESULT. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
parent
932da4c114
commit
09965b9102
73
fpu.vhdl
73
fpu.vhdl
@ -169,6 +169,9 @@ 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);
|
||||
end record;
|
||||
|
||||
type lookup_table is array(0 to 1023) of std_ulogic_vector(17 downto 0);
|
||||
@ -605,15 +608,21 @@ architecture behaviour of fpu is
|
||||
end;
|
||||
|
||||
-- Construct a DP floating-point result from components
|
||||
function pack_dp(sign: 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)
|
||||
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)
|
||||
return std_ulogic_vector is
|
||||
variable dp_result : std_ulogic_vector(63 downto 0);
|
||||
variable sign : std_ulogic;
|
||||
begin
|
||||
dp_result := (others => '0');
|
||||
dp_result(63) := sign;
|
||||
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
|
||||
@ -633,6 +642,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;
|
||||
return dp_result;
|
||||
end;
|
||||
|
||||
@ -1468,8 +1478,8 @@ begin
|
||||
v.fpscr(FPSCR_FR) := '0';
|
||||
v.fpscr(FPSCR_FI) := '0';
|
||||
is_add := r.a.negative xor r.b.negative xor r.insn(1);
|
||||
v.is_subtract := not is_add;
|
||||
if r.a.class = FINITE and r.b.class = FINITE then
|
||||
v.is_subtract := not is_add;
|
||||
v.add_bsmall := r.exp_cmp;
|
||||
v.opsel_a := AIN_B;
|
||||
if r.exp_cmp = '0' then
|
||||
@ -1491,18 +1501,13 @@ begin
|
||||
v.fpscr(FPSCR_VXISI) := '1';
|
||||
qnan_result := '1';
|
||||
arith_done := '1';
|
||||
elsif r.a.class = ZERO and r.b.class = ZERO and is_add = '0' then
|
||||
-- return -0 for rounding to -infinity
|
||||
v.result_sign := r.round_mode(1) and r.round_mode(0);
|
||||
arith_done := '1';
|
||||
elsif r.a.class = INFINITY or r.b.class = ZERO then
|
||||
-- result is A
|
||||
v.opsel_a := AIN_A;
|
||||
v.state := EXC_RESULT;
|
||||
-- result is A; we're already set up to put A into R
|
||||
arith_done := '1';
|
||||
else
|
||||
-- result is +/- B
|
||||
v.opsel_a := AIN_B;
|
||||
v.negate := not r.insn(1);
|
||||
v.result_sign := r.b.negative xnor r.insn(1);
|
||||
v.state := EXC_RESULT;
|
||||
end if;
|
||||
end if;
|
||||
@ -1541,7 +1546,6 @@ begin
|
||||
else
|
||||
-- r.c.class is ZERO or INFINITY
|
||||
v.opsel_a := AIN_C;
|
||||
v.negate := r.a.negative;
|
||||
v.state := EXC_RESULT;
|
||||
end if;
|
||||
end if;
|
||||
@ -1599,8 +1603,10 @@ begin
|
||||
v.fpscr(FPSCR_FI) := '0';
|
||||
if r.a.class = ZERO or (r.a.negative = '0' and r.a.class /= NAN) then
|
||||
v.opsel_a := AIN_C;
|
||||
v.result_sign := r.c.negative;
|
||||
else
|
||||
v.opsel_a := AIN_B;
|
||||
v.result_sign := r.b.negative;
|
||||
end if;
|
||||
v.quieten_nan := '0';
|
||||
v.state := EXC_RESULT;
|
||||
@ -1720,9 +1726,10 @@ begin
|
||||
v.fpscr(FPSCR_FR) := '0';
|
||||
v.fpscr(FPSCR_FI) := '0';
|
||||
is_add := r.a.negative xor r.c.negative xor r.b.negative xor r.insn(1);
|
||||
v.negate := r.insn(2);
|
||||
v.is_subtract := not is_add;
|
||||
if r.a.class = FINITE and r.c.class = FINITE and
|
||||
(r.b.class = FINITE or r.b.class = ZERO) then
|
||||
v.is_subtract := not is_add;
|
||||
-- Make sure A and C are normalized
|
||||
if r.a.mantissa(UNIT_BIT) = '0' then
|
||||
v.state := RENORM_A;
|
||||
@ -1730,13 +1737,13 @@ begin
|
||||
v.state := RENORM_C;
|
||||
elsif r.b.class = ZERO then
|
||||
-- no addend, degenerates to multiply
|
||||
v.result_sign := r.a.negative xor r.c.negative xor r.insn(2);
|
||||
v.result_sign := r.a.negative xor r.c.negative;
|
||||
f_to_multiply.valid <= '1';
|
||||
v.is_multiply := '1';
|
||||
v.state := MULT_1;
|
||||
elsif r.madd_cmp = '0' then
|
||||
-- addend is bigger, do multiply first
|
||||
v.result_sign := not (r.b.negative xor r.insn(1) xor r.insn(2));
|
||||
v.result_sign := r.b.negative xnor r.insn(1);
|
||||
f_to_multiply.valid <= '1';
|
||||
v.first := '1';
|
||||
v.state := FMADD_0;
|
||||
@ -1760,19 +1767,14 @@ begin
|
||||
else
|
||||
-- result is infinity
|
||||
v.result_class := INFINITY;
|
||||
v.result_sign := r.a.negative xor r.c.negative xor r.insn(2);
|
||||
v.result_sign := r.a.negative xor r.c.negative;
|
||||
arith_done := '1';
|
||||
end if;
|
||||
else
|
||||
-- Here A is zero, C is zero, or B is infinity
|
||||
-- Result is +/-B in all of those cases
|
||||
v.opsel_a := AIN_B;
|
||||
if r.b.class /= ZERO or is_add = '1' then
|
||||
v.negate := not (r.insn(1) xor r.insn(2));
|
||||
else
|
||||
-- have to be careful about rule for 0 - 0 result sign
|
||||
v.negate := r.b.negative xor (r.round_mode(1) and r.round_mode(0)) xor r.insn(2);
|
||||
end if;
|
||||
v.result_sign := r.b.negative xnor r.insn(1);
|
||||
v.state := EXC_RESULT;
|
||||
end if;
|
||||
end if;
|
||||
@ -1910,10 +1912,6 @@ begin
|
||||
elsif (r_hi_nz or r_lo_nz or (or (r.r(DP_LSB - 1 downto 0)))) = '0' then
|
||||
-- r.x must be zero at this point
|
||||
v.result_class := ZERO;
|
||||
if r.is_subtract = '1' then
|
||||
-- set result sign depending on rounding mode
|
||||
v.result_sign := r.round_mode(1) and r.round_mode(0);
|
||||
end if;
|
||||
arith_done := '1';
|
||||
else
|
||||
rs_norm <= '1';
|
||||
@ -1970,7 +1968,7 @@ begin
|
||||
-- product is bigger here
|
||||
-- shift B right and use it as the addend to the multiplier
|
||||
-- for subtract, multiplier does B - A * C
|
||||
v.result_sign := r.a.negative xor r.c.negative xor r.insn(2) xor r.is_subtract;
|
||||
v.result_sign := r.a.negative xor r.c.negative xor r.is_subtract;
|
||||
re_sel2 <= REXP2_B;
|
||||
re_set_result <= '1';
|
||||
-- set shift to b.exp - result_exp + 64
|
||||
@ -2030,7 +2028,6 @@ begin
|
||||
if s_nz = '0' then
|
||||
-- must be a subtraction, and r.x must be zero
|
||||
v.result_class := ZERO;
|
||||
v.result_sign := r.round_mode(1) and r.round_mode(0);
|
||||
arith_done := '1';
|
||||
else
|
||||
-- R is all zeroes but there are non-zero bits in S
|
||||
@ -2572,10 +2569,6 @@ begin
|
||||
rs_neg2 <= '1';
|
||||
if mant_nz = '0' then
|
||||
v.result_class := ZERO;
|
||||
if r.is_subtract = '1' then
|
||||
-- set result sign depending on rounding mode
|
||||
v.result_sign := r.round_mode(1) and r.round_mode(0);
|
||||
end if;
|
||||
arith_done := '1';
|
||||
else
|
||||
-- Renormalize result after rounding
|
||||
@ -2597,6 +2590,7 @@ 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
|
||||
@ -2606,10 +2600,13 @@ begin
|
||||
end if;
|
||||
if r.use_a = '1' and r.a.class = NAN then
|
||||
v.opsel_a := AIN_A;
|
||||
v.result_sign := r.a.negative;
|
||||
elsif r.use_b = '1' and r.b.class = NAN then
|
||||
v.opsel_a := AIN_B;
|
||||
v.result_sign := r.b.negative;
|
||||
elsif r.use_c = '1' and r.c.class = NAN then
|
||||
v.opsel_a := AIN_C;
|
||||
v.result_sign := r.c.negative;
|
||||
end if;
|
||||
v.state := EXC_RESULT;
|
||||
|
||||
@ -2617,15 +2614,12 @@ begin
|
||||
-- r.opsel_a = AIN_A, AIN_B or AIN_C according to which input is the result
|
||||
case r.opsel_a is
|
||||
when AIN_B =>
|
||||
v.result_sign := r.b.negative xor r.negate;
|
||||
re_sel2 <= REXP2_B;
|
||||
v.result_class := r.b.class;
|
||||
when AIN_C =>
|
||||
v.result_sign := r.c.negative xor r.negate;
|
||||
re_sel2 <= REXP2_C;
|
||||
v.result_class := r.c.class;
|
||||
when others =>
|
||||
v.result_sign := r.a.negative xor r.negate;
|
||||
re_sel1 <= REXP1_A;
|
||||
v.result_class := r.a.class;
|
||||
end case;
|
||||
@ -3171,6 +3165,7 @@ begin
|
||||
invalid := '1';
|
||||
v.result_class := NAN;
|
||||
v.result_sign := '0';
|
||||
v.negate := '0';
|
||||
misc_sel <= "0001";
|
||||
opsel_r <= RES_MISC;
|
||||
arith_done := '1';
|
||||
@ -3550,6 +3545,9 @@ 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;
|
||||
if r.integer_op = '1' then
|
||||
v.cr_mask := num_to_fxm(0);
|
||||
elsif r.is_cmp = '0' then
|
||||
@ -3581,7 +3579,8 @@ begin
|
||||
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.sp_result, r.nsnan_result,
|
||||
r.res_negate, r.res_subtract, r.res_rmode);
|
||||
end if;
|
||||
|
||||
rin <= v;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user