// ====================================================================== // // FloatingPointUnit.cpp // copyright 1999 Bootprint Entertainment // copyright 2001 Sony Online Entertainment // // ====================================================================== #include "sharedFoundation/FirstSharedFoundation.h" #include "sharedFoundation/FloatingPointUnit.h" #include "sharedFoundation/ConfigSharedFoundation.h" // ====================================================================== int FloatingPointUnit::updateNumber; ushort FloatingPointUnit::status; FloatingPointUnit::Precision FloatingPointUnit::precision; FloatingPointUnit::Rounding FloatingPointUnit::rounding; bool FloatingPointUnit::exceptionEnabled[E_max]; // ====================================================================== const WORD PRECISION_MASK = BINARY4(0000,0011,0000,0000); const WORD PRECISION_24 = BINARY4(0000,0000,0000,0000); const WORD PRECISION_53 = BINARY4(0000,0010,0000,0000); const WORD PRECISION_64 = BINARY4(0000,0011,0000,0000); const WORD ROUND_MASK = BINARY4(0000,1100,0000,0000); const WORD ROUND_NEAREST = BINARY4(0000,0000,0000,0000); const WORD ROUND_CHOP = BINARY4(0000,1100,0000,0000); const WORD ROUND_DOWN = BINARY4(0000,0100,0000,0000); const WORD ROUND_UP = BINARY4(0000,1000,0000,0000); const WORD EXCEPTION_PRECISION = BINARY4(0000,0000,0010,0000); const WORD EXCEPTION_UNDERFLOW = BINARY4(0000,0000,0001,0000); const WORD EXCEPTION_OVERFLOW = BINARY4(0000,0000,0000,1000); const WORD EXCEPTION_ZERO_DIVIDE = BINARY4(0000,0000,0000,0100); const WORD EXCEPTION_DENORMAL = BINARY4(0000,0000,0000,0010); const WORD EXCEPTION_INVALID = BINARY4(0000,0000,0000,0001); const WORD EXCEPTION_ALL = BINARY4(0000,0000,0011,1111); // ====================================================================== void FloatingPointUnit::install(void) { precision = P_24; rounding = R_roundToNearestOrEven; memset(exceptionEnabled, 0, sizeof(exceptionEnabled)); // preserve all other bits status = getControlWord(); status &= ~(PRECISION_MASK | ROUND_MASK | EXCEPTION_ALL); // set to single precision, rounding, and all exceptions masked status |= PRECISION_24 | ROUND_NEAREST | EXCEPTION_ALL; // check the config platform flags to see if we should enable some exceptions if (ConfigSharedFoundation::getFpuExceptionPrecision()) { exceptionEnabled[E_precision] = true; status &= ~EXCEPTION_PRECISION; } if (ConfigSharedFoundation::getFpuExceptionUnderflow()) { exceptionEnabled[E_underflow] = true; status &= ~EXCEPTION_UNDERFLOW; } if (ConfigSharedFoundation::getFpuExceptionOverflow()) { exceptionEnabled[E_overflow] = true; status &= ~EXCEPTION_OVERFLOW; } if (ConfigSharedFoundation::getFpuExceptionZeroDivide()) { exceptionEnabled[E_zeroDivide] = true; status &= ~EXCEPTION_ZERO_DIVIDE; } if (ConfigSharedFoundation::getFpuExceptionDenormal()) { exceptionEnabled[E_denormal] = true; status &= ~EXCEPTION_DENORMAL; } if (ConfigSharedFoundation::getFpuExceptionInvalid()) { exceptionEnabled[E_invalid] = true; status &= ~EXCEPTION_INVALID; } setControlWord(status); } // ---------------------------------------------------------------------- void FloatingPointUnit::update(void) { WORD currentStatus = getControlWord(); if (currentStatus != status) { // DEBUG_REPORT_LOG_PRINT(true, ("FPU: update=%d, in mode=%04x, should be in mode=%04x\n", updateNumber, static_cast(currentStatus), static_cast(status))); setControlWord(status); } ++updateNumber; } // ---------------------------------------------------------------------- WORD FloatingPointUnit::getControlWord(void) { WORD controlWord = 0; __asm fnstcw controlWord; return controlWord; } // ---------------------------------------------------------------------- void FloatingPointUnit::setControlWord(WORD controlWord) { UNREF(controlWord); __asm fldcw controlWord; } // ---------------------------------------------------------------------- void FloatingPointUnit::setPrecision(Precision newPrecision) { WORD bits = 0; switch (precision) { case P_24: bits = PRECISION_24; break; case P_53: bits = PRECISION_53; break; case P_64: bits = PRECISION_64; break; case P_max: default: DEBUG_FATAL(true, ("bad case")); } // record the current state precision = newPrecision; // set the proper bit pattern status &= ~PRECISION_MASK; status |= bits; // slam it into the FPU setControlWord(status); } // ---------------------------------------------------------------------- void FloatingPointUnit::setRounding(Rounding newRounding) { WORD bits = 0; switch (newRounding) { case R_roundToNearestOrEven: bits = ROUND_NEAREST; break; case R_chop: bits = ROUND_CHOP; break; case R_roundDown: bits = ROUND_DOWN; break; case R_roundUp: bits = ROUND_UP; break; case R_max: default: DEBUG_FATAL(true, ("bad case")); } // record the current state rounding = newRounding; // set the proper bit pattern status &= ~ROUND_MASK; status |= bits; // slam it into the FPU setControlWord(status); } // ---------------------------------------------------------------------- void FloatingPointUnit::setExceptionEnabled(Exception exception, bool enabled) { WORD bits = 0; switch (exception) { case E_precision: bits = EXCEPTION_PRECISION; break; case E_underflow: bits = EXCEPTION_UNDERFLOW; break; case E_overflow: bits = EXCEPTION_OVERFLOW; break; case E_zeroDivide: bits = EXCEPTION_ZERO_DIVIDE; break; case E_denormal: bits = EXCEPTION_DENORMAL; break; case E_invalid: bits = EXCEPTION_INVALID; break; case E_max: default: DEBUG_FATAL(true, ("bad case")); } // record the current state exceptionEnabled[exception] = enabled; // twiddle the bit appropriately. these bits masks, so set the bit to disable the exception, clear the bit to enable it. if (enabled) status &= ~bits; else status |= bits; // slam it into the FPU setControlWord(status); } // ======================================================================