FPU: Reorganize NaN and infinity handling and improve arch compliance

The architecture specifies that an invalid operation exception for
signalling NaN (VXSNAN) can occur in the same instructions as an
invalid operation exception for infinity times zero (VXIMZ) in the
case of a multiply-add instruction where B is a signalling NaN, and
one of A and C is infinity and the other is zero.  This moves the
invalid operation tests around so as to handle this case correctly.
It also restructures the infinity and NaN cases to simplify the logic
a little.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/442/head
Paul Mackerras 1 year ago
parent 9ac71cfbf2
commit 7812a55b6c

@ -838,6 +838,7 @@ begin
variable set_y : std_ulogic;
variable set_s : std_ulogic;
variable qnan_result : std_ulogic;
variable invalid_mul : std_ulogic;
variable px_nz : std_ulogic;
variable pcmpb_eq : std_ulogic;
variable pcmpb_lt : std_ulogic;
@ -1217,6 +1218,7 @@ begin
-- At least one floating-point operand is infinity or NaN
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
invalid_mul := '0';

if (r.a.class = NAN and r.a.mantissa(QNAN_BIT) = '0') or
(r.b.class = NAN and r.b.mantissa(QNAN_BIT) = '0') or
@ -1225,6 +1227,15 @@ begin
v.fpscr(FPSCR_VXSNAN) := '1';
invalid := '1';
end if;
-- Check for this case here since VXIMZ can be set along with VXSNAN
if r.is_multiply = '1' and
((r.a.class = INFINITY and r.c.class = ZERO) or
(r.a.class = ZERO and r.c.class = INFINITY)) then
v.fpscr(FPSCR_VXIMZ) := '1';
qnan_result := '1';
invalid_mul := '1';
end if;

if r.a.class = NAN or r.b.class = NAN or r.c.class = NAN then
if r.int_result = '1' then
v.state := INT_OFLOW;
@ -1241,51 +1252,32 @@ begin
end if;

else
if r.a.class = INFINITY then
if r.is_multiply = '1' and r.c.class = ZERO then
-- invalid operation, construct QNaN
v.fpscr(FPSCR_VXIMZ) := '1';
qnan_result := '1';
elsif r.is_subtract = '1' and r.b.class = INFINITY then
if (r.a.class = INFINITY or r.c.class = INFINITY) and invalid_mul = '0' then
sign_inv := r.is_multiply and r.is_subtract;
if r.is_subtract = '1' and r.b.class = INFINITY then
v.fpscr(FPSCR_VXISI) := '1';
qnan_result := '1';
elsif r.is_inverse = '1' and r.b.class = INFINITY then
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';
elsif r.c.class = INFINITY then
if r.is_multiply = '1' and r.a.class = ZERO then
-- invalid operation, construct QNaN
v.fpscr(FPSCR_VXIMZ) := '1';
qnan_result := '1';
elsif r.is_subtract = '1' and r.b.class = INFINITY then
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';
end if;
if r.is_inverse = '1' and r.a.class = INFINITY and r.b.class = INFINITY then
v.fpscr(FPSCR_VXIDI) := '1';
qnan_result := '1';
end if;
if r.b.class = INFINITY and r.is_sqrt = '1' and r.b.negative = '1' then
v.fpscr(FPSCR_VXSQRT) := '1';
qnan_result := '1';
end if;
if r.b.class = INFINITY and r.is_inverse = '1' then
-- fdiv, fre, frsqrte
v.result_class := ZERO;
else
-- r.b.class = INFINITY
if r.int_result = '1' then
-- fcti*
v.state := INT_OFLOW;
elsif r.is_sqrt = '1' and r.b.negative = '1' then
v.fpscr(FPSCR_VXSQRT) := '1';
qnan_result := '1';
elsif r.is_inverse = '1' then
-- fdiv, fre, frsqrte
v.result_class := ZERO;
arith_done := '1';
else
v.result_class := INFINITY;
arith_done := '1';
end if;
v.result_class := INFINITY;
end if;
if r.b.class = INFINITY and r.int_result = '1' then
-- fcti*
v.state := INT_OFLOW;
else
arith_done := '1';
end if;
end if;


Loading…
Cancel
Save