mirror of
https://bitbucket.org/theswgsource/src-1.2.git
synced 2026-07-28 23:16:15 -04:00
258 lines
6.2 KiB
C++
258 lines
6.2 KiB
C++
// ======================================================================
|
|
//
|
|
// 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<int>(currentStatus), static_cast<int>(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);
|
|
}
|
|
|
|
// ======================================================================
|