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;