check first for faults (IE, DE, DZ) and only then for traps (OE, UE, PE)

This commit is contained in:
Stanislav Shwartsman 2009-05-24 15:29:43 +00:00
parent c2975e5d3c
commit d4c3838427
3 changed files with 57 additions and 27 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: ferr.cc,v 1.16 2009-04-27 17:58:17 sshwarts Exp $
// $Id: ferr.cc,v 1.17 2009-05-24 15:29:43 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003 Stanislav Shwartsman
@ -61,16 +61,41 @@ unsigned BX_CPU_C::FPU_exception(unsigned exception, bx_bool is_store)
Bit32u status = FPU_PARTIAL_STATUS;
/* Set the corresponding exception bits */
FPU_PARTIAL_STATUS |= exception;
unsigned unmasked = FPU_PARTIAL_STATUS & ~FPU_CONTROL_WORD & FPU_CW_Exceptions_Mask;
unsigned unmasked = exception & ~FPU_CONTROL_WORD & FPU_CW_Exceptions_Mask;
/* Set summary bits iff exception isn't masked */
if (unmasked)
FPU_PARTIAL_STATUS |= (FPU_SW_Summary | FPU_SW_Backward);
if (exception & (FPU_SW_Stack_Fault | FPU_EX_Precision))
if (exception & FPU_EX_Invalid) {
// FPU_EX_Invalid cannot come with any other exception but x87 stack fault
FPU_PARTIAL_STATUS |= exception;
if (exception & FPU_SW_Stack_Fault) {
if (! (exception & FPU_SW_C1)) {
/* This bit distinguishes over- from underflow for a stack fault,
and roundup from round-down for precision loss. */
FPU_PARTIAL_STATUS &= ~FPU_SW_C1;
}
}
return unmasked;
}
if (exception & FPU_EX_Denormal) {
FPU_PARTIAL_STATUS |= FPU_EX_Denormal;
if (unmasked & FPU_EX_Denormal)
return unmasked;
}
if (exception & FPU_EX_Zero_Div) {
FPU_PARTIAL_STATUS |= FPU_EX_Zero_Div;
if (unmasked & FPU_EX_Zero_Div)
return unmasked;
}
/* Set the corresponding exception bits */
FPU_PARTIAL_STATUS |= exception;
if (exception & FPU_EX_Precision)
{
if (! (exception & FPU_SW_C1)) {
/* This bit distinguishes over- from underflow for a stack fault,
@ -81,9 +106,9 @@ unsigned BX_CPU_C::FPU_exception(unsigned exception, bx_bool is_store)
// If #P unmasked exception occured the result still has to be
// written to the destination.
unmasked &= ~FPU_CW_Precision;
unmasked &= ~FPU_EX_Precision;
if (unmasked & (FPU_CW_Underflow | FPU_CW_Overflow)) {
if (unmasked & (FPU_EX_Underflow | FPU_EX_Overflow)) {
// If unmasked over- or underflow occurs and dest is a memory location:
// - the TOS and destination operands remain unchanged
// - the inexact-result condition is not reported and C1 flag is cleared
@ -91,12 +116,12 @@ unsigned BX_CPU_C::FPU_exception(unsigned exception, bx_bool is_store)
// If the destination is in the register stack, adjusted resulting value
// is stored in the destination operand.
if (! is_store) {
unmasked &= ~(FPU_CW_Underflow | FPU_CW_Overflow);
unmasked &= ~(FPU_EX_Underflow | FPU_EX_Overflow);
}
else {
FPU_PARTIAL_STATUS &= ~FPU_SW_C1; // clear C1 flag
if (! (status & FPU_CW_Precision))
FPU_PARTIAL_STATUS &= ~FPU_CW_Precision;
if (! (status & FPU_EX_Precision))
FPU_PARTIAL_STATUS &= ~FPU_EX_Precision;
}
}

View File

@ -71,7 +71,8 @@ static floatx80 do_fprem(floatx80 a, floatx80 b, Bit64u &q, int rounding_mode, f
{
return propagateFloatx80NaN(a, b, status);
}
goto invalid;
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
if (bExp == 0x7FFF) {
if ((Bit64u) (bSig<<1)) return propagateFloatx80NaN(a, b, status);
@ -79,7 +80,6 @@ static floatx80 do_fprem(floatx80 a, floatx80 b, Bit64u &q, int rounding_mode, f
}
if (bExp == 0) {
if (bSig == 0) {
invalid:
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}

View File

@ -639,7 +639,6 @@ float32 float32_div(float32 a, float32 b, float_status_t &status)
if (aSig) return propagateFloat32NaN(a, b, status);
if (bExp == 0xFF) {
if (bSig) return propagateFloat32NaN(a, b, status);
invalid:
float_raise(status, float_flag_invalid);
return float32_default_nan;
}
@ -653,7 +652,10 @@ float32 float32_div(float32 a, float32 b, float_status_t &status)
}
if (bExp == 0) {
if (bSig == 0) {
if ((aExp | aSig) == 0) goto invalid;
if ((aExp | aSig) == 0) {
float_raise(status, float_flag_invalid);
return float32_default_nan;
}
float_raise(status, float_flag_divbyzero);
return packFloat32(zSign, 0xFF, 0);
}
@ -1561,7 +1563,6 @@ float64 float64_div(float64 a, float64 b, float_status_t &status)
if (aSig) return propagateFloat64NaN(a, b, status);
if (bExp == 0x7FF) {
if (bSig) return propagateFloat64NaN(a, b, status);
invalid:
float_raise(status, float_flag_invalid);
return float64_default_nan;
}
@ -1575,7 +1576,10 @@ float64 float64_div(float64 a, float64 b, float_status_t &status)
}
if (bExp == 0) {
if (bSig == 0) {
if ((aExp | aSig) == 0) goto invalid;
if ((aExp | aSig) == 0) {
float_raise(status, float_flag_invalid);
return float64_default_nan;
}
float_raise(status, float_flag_divbyzero);
return packFloat64(zSign, 0x7FF, 0);
}
@ -2669,7 +2673,8 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status_t &status)
if ((Bit64u) (aSig<<1)) return propagateFloatx80NaN(a, b, status);
if (bExp == 0x7FFF) {
if ((Bit64u) (bSig<<1)) return propagateFloatx80NaN(a, b, status);
goto invalid;
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
if (bSig && (bExp == 0)) float_raise(status, float_flag_denormal);
return packFloatx80(zSign, 0x7FFF, BX_CONST64(0x8000000000000000));
@ -2682,7 +2687,6 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status_t &status)
if (bExp == 0) {
if (bSig == 0) {
if ((aExp | aSig) == 0) {
invalid:
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
@ -2751,11 +2755,11 @@ floatx80 floatx80_sqrt(floatx80 a, float_status_t &status)
if (aExp == 0x7FFF) {
if ((Bit64u) (aSig0<<1)) return propagateFloatx80NaN(a, status);
if (! aSign) return a;
goto invalid;
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
if (aSign) {
if ((aExp | aSig0) == 0) return a;
invalid:
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
@ -3148,17 +3152,18 @@ float128 float128_mul(float128 a, float128 b, float_status_t &status)
zSign = aSign ^ bSign;
if (aExp == 0x7FFF) {
if ((aSig0 | aSig1) || ((bExp == 0x7FFF) && (bSig0 | bSig1)))
{
if ((aSig0 | aSig1) || ((bExp == 0x7FFF) && (bSig0 | bSig1))) {
return propagateFloat128NaN(a, b, status);
}
if ((bExp | bSig0 | bSig1) == 0) goto invalid;
if ((bExp | bSig0 | bSig1) == 0) {
float_raise(status, float_flag_invalid);
return float128_default_nan;
}
return packFloat128(zSign, 0x7FFF, 0, 0);
}
if (bExp == 0x7FFF) {
if (bSig0 | bSig1) return propagateFloat128NaN(a, b, status);
if ((aExp | aSig0 | aSig1) == 0) {
invalid:
float_raise(status, float_flag_invalid);
return float128_default_nan;
}
@ -3214,7 +3219,8 @@ float128 float128_div(float128 a, float128 b, float_status_t &status)
if (aSig0 | aSig1) return propagateFloat128NaN(a, b, status);
if (bExp == 0x7FFF) {
if (bSig0 | bSig1) return propagateFloat128NaN(a, b, status);
goto invalid;
float_raise(status, float_flag_invalid);
return float128_default_nan;
}
return packFloat128(zSign, 0x7FFF, 0, 0);
}
@ -3225,7 +3231,6 @@ float128 float128_div(float128 a, float128 b, float_status_t &status)
if (bExp == 0) {
if ((bSig0 | bSig1) == 0) {
if ((aExp | aSig0 | aSig1) == 0) {
invalid:
float_raise(status, float_flag_invalid);
return float128_default_nan;
}