From 7812a55b6ce73ba1388b0cdc767afe3de43b6a56 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 5 Feb 2024 21:57:59 +1100 Subject: [PATCH] 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 --- fpu.vhdl | 74 +++++++++++++++++++++++++------------------------------- 1 file changed, 33 insertions(+), 41 deletions(-) diff --git a/fpu.vhdl b/fpu.vhdl index f0a180f..d7a5e42 100644 --- a/fpu.vhdl +++ b/fpu.vhdl @@ -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;