mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-04-12 22:56:59 +00:00
FPU: Simplify sign calculation in FP multiply-add instructions
By starting out with result_sign = +/- sign of B, we avoid the need to flip the result sign in a few places. This also simplifies DO_FMADD state a bit by having DO_ZERO_DEN go to DO_FMUL state for floating multiply-add where B is zero. (The RENORM_A2 and RENORM_C2 states already do this.) Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
24
fpu.vhdl
24
fpu.vhdl
@@ -952,7 +952,7 @@ begin
|
||||
when "11100" | "11101" | "11110" | "11111" => --fmadd family
|
||||
v.is_multiply := '1';
|
||||
v.is_addition := '1';
|
||||
v.result_sign := e_in.fra(63) xor e_in.frc(63);
|
||||
v.result_sign := e_in.frb(63) xnor e_in.insn(1);
|
||||
v.is_subtract := not (e_in.fra(63) xor e_in.frb(63) xor
|
||||
e_in.frc(63) xor e_in.insn(1));
|
||||
v.negate := e_in.insn(2);
|
||||
@@ -1253,6 +1253,7 @@ begin
|
||||
v.fpscr(FPSCR_VXIDI) := '1';
|
||||
qnan_result := '1';
|
||||
else
|
||||
sign_inv := r.is_multiply and r.is_subtract;
|
||||
v.result_class := INFINITY;
|
||||
end if;
|
||||
arith_done := '1';
|
||||
@@ -1265,6 +1266,7 @@ begin
|
||||
v.fpscr(FPSCR_VXISI) := '1';
|
||||
qnan_result := '1';
|
||||
else
|
||||
sign_inv := r.is_multiply and r.is_subtract;
|
||||
v.result_class := INFINITY;
|
||||
end if;
|
||||
arith_done := '1';
|
||||
@@ -1281,7 +1283,6 @@ begin
|
||||
v.result_class := ZERO;
|
||||
arith_done := '1';
|
||||
else
|
||||
sign_inv := r.is_multiply and r.is_subtract;
|
||||
v.result_class := INFINITY;
|
||||
arith_done := '1';
|
||||
end if;
|
||||
@@ -1308,9 +1309,6 @@ begin
|
||||
elsif r.is_addition = '1' then
|
||||
-- result is +/- B
|
||||
v.opsel_a := AIN_B;
|
||||
if r.is_multiply = '1' then
|
||||
rsgn_op := RSGN_SUB;
|
||||
end if;
|
||||
v.state := EXC_RESULT;
|
||||
else
|
||||
v.result_class := ZERO;
|
||||
@@ -1318,7 +1316,6 @@ begin
|
||||
end if;
|
||||
elsif r.use_c = '1' and r.c.class = ZERO then
|
||||
v.opsel_a := AIN_B;
|
||||
rsgn_op := RSGN_SUB;
|
||||
v.state := EXC_RESULT;
|
||||
else
|
||||
-- B is zero, other operands are finite
|
||||
@@ -1349,6 +1346,14 @@ begin
|
||||
if r.use_a = '1' and (r.use_b = '0' or r.use_c = '0') then
|
||||
v.opsel_a := AIN_A;
|
||||
end if;
|
||||
if r.use_b = '1' and r.b.class = ZERO and r.use_c = '1' then
|
||||
-- turn fmadd/sub into fmul
|
||||
v.opsel_a := AIN_A;
|
||||
rsgn_op := RSGN_SUB;
|
||||
v.state := DO_FMUL;
|
||||
else
|
||||
v.state := r.exec_state;
|
||||
end if;
|
||||
-- input selection for denorm cases
|
||||
case r.insn(5 downto 1) is
|
||||
when "10010" => -- fdiv
|
||||
@@ -1367,7 +1372,6 @@ begin
|
||||
end if;
|
||||
when others =>
|
||||
end case;
|
||||
v.state := r.exec_state;
|
||||
end if;
|
||||
|
||||
when DO_ILLEGAL =>
|
||||
@@ -1792,14 +1796,9 @@ begin
|
||||
v.state := RENORM_A;
|
||||
elsif r.c.mantissa(UNIT_BIT) = '0' then
|
||||
v.state := RENORM_C;
|
||||
elsif r.b.class = ZERO then
|
||||
-- no addend, degenerates to multiply
|
||||
f_to_multiply.valid <= '1';
|
||||
v.state := MULT_1;
|
||||
elsif r.madd_cmp = '0' then
|
||||
-- addend is bigger, do multiply first
|
||||
-- if subtracting, sign is opposite to initial estimate
|
||||
rsgn_op := RSGN_SUB;
|
||||
f_to_multiply.valid <= '1';
|
||||
v.first := '1';
|
||||
v.state := FMADD_0;
|
||||
@@ -2006,7 +2005,6 @@ begin
|
||||
-- product is bigger here
|
||||
-- shift B right and use it as the addend to the multiplier
|
||||
-- for subtract, multiplier does B - A * C
|
||||
rsgn_op := RSGN_SUB;
|
||||
re_sel2 <= REXP2_B;
|
||||
re_set_result <= '1';
|
||||
-- set shift to b.exp - result_exp + 64
|
||||
|
||||
Reference in New Issue
Block a user