check first for faults (IE, DE, DZ) and only then for traps (OE, UE, PE)
This commit is contained in:
parent
c2975e5d3c
commit
d4c3838427
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user