mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-06 12:40:24 +00:00
Merge pull request #6978 from lioncash/fcti
Interpreter_FloatingPoint: Handle NaN flag setting within fctiw and fctiwz
This commit is contained in:
commit
f1b7259446
@ -288,7 +288,6 @@ private:
|
|||||||
|
|
||||||
// flag helper
|
// flag helper
|
||||||
static void Helper_UpdateCR0(u32 value);
|
static void Helper_UpdateCR0(u32 value);
|
||||||
static void Helper_UpdateCR1();
|
|
||||||
|
|
||||||
// address helper
|
// address helper
|
||||||
static u32 Helper_Get_EA(const UGeckoInstruction inst);
|
static u32 Helper_Get_EA(const UGeckoInstruction inst);
|
||||||
|
@ -52,6 +52,11 @@ inline void UpdateFPSCR()
|
|||||||
(FPSCR.ZX & FPSCR.ZE) | (FPSCR.XX & FPSCR.XE);
|
(FPSCR.ZX & FPSCR.ZE) | (FPSCR.XX & FPSCR.XE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Helper_UpdateCR1()
|
||||||
|
{
|
||||||
|
PowerPC::SetCRField(1, (FPSCR.FX << 3) | (FPSCR.FEX << 2) | (FPSCR.VX << 1) | FPSCR.OX);
|
||||||
|
}
|
||||||
|
|
||||||
inline double ForceSingle(double value)
|
inline double ForceSingle(double value)
|
||||||
{
|
{
|
||||||
// convert to float...
|
// convert to float...
|
||||||
|
@ -11,12 +11,117 @@
|
|||||||
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
|
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
|
|
||||||
// Extremely rare - actually, never seen.
|
namespace
|
||||||
// Star Wars : Rogue Leader spams that at some point :|
|
|
||||||
void Interpreter::Helper_UpdateCR1()
|
|
||||||
{
|
{
|
||||||
PowerPC::SetCRField(1, (FPSCR.FX << 3) | (FPSCR.FEX << 2) | (FPSCR.VX << 1) | FPSCR.OX);
|
// Apply current rounding mode
|
||||||
|
enum class RoundingMode
|
||||||
|
{
|
||||||
|
Nearest = 0b00,
|
||||||
|
TowardsZero = 0b01,
|
||||||
|
TowardsPositiveInfinity = 0b10,
|
||||||
|
TowardsNegativeInfinity = 0b11
|
||||||
|
};
|
||||||
|
|
||||||
|
// Note that the convert to integer operation is defined
|
||||||
|
// in Appendix C.4.2 in PowerPC Microprocessor Family:
|
||||||
|
// The Programming Environments Manual for 32 and 64-bit Microprocessors
|
||||||
|
void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
|
||||||
|
{
|
||||||
|
const double b = rPS0(inst.FB);
|
||||||
|
u32 value;
|
||||||
|
bool exception_occurred = false;
|
||||||
|
|
||||||
|
if (std::isnan(b))
|
||||||
|
{
|
||||||
|
if (Common::IsSNAN(b))
|
||||||
|
SetFPException(FPSCR_VXSNAN);
|
||||||
|
|
||||||
|
value = 0x80000000;
|
||||||
|
SetFPException(FPSCR_VXCVI);
|
||||||
|
exception_occurred = true;
|
||||||
|
}
|
||||||
|
else if (b > static_cast<double>(0x7fffffff))
|
||||||
|
{
|
||||||
|
// Positive large operand or +inf
|
||||||
|
value = 0x7fffffff;
|
||||||
|
SetFPException(FPSCR_VXCVI);
|
||||||
|
exception_occurred = true;
|
||||||
|
}
|
||||||
|
else if (b < -static_cast<double>(0x80000000))
|
||||||
|
{
|
||||||
|
// Negative large operand or -inf
|
||||||
|
value = 0x80000000;
|
||||||
|
SetFPException(FPSCR_VXCVI);
|
||||||
|
exception_occurred = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s32 i = 0;
|
||||||
|
switch (rounding_mode)
|
||||||
|
{
|
||||||
|
case RoundingMode::Nearest:
|
||||||
|
{
|
||||||
|
const double t = b + 0.5;
|
||||||
|
i = static_cast<s32>(t);
|
||||||
|
|
||||||
|
if (t - i < 0 || (t - i == 0 && b > 0))
|
||||||
|
{
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RoundingMode::TowardsZero:
|
||||||
|
i = static_cast<s32>(b);
|
||||||
|
break;
|
||||||
|
case RoundingMode::TowardsPositiveInfinity:
|
||||||
|
i = static_cast<s32>(b);
|
||||||
|
if (b - i > 0)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RoundingMode::TowardsNegativeInfinity:
|
||||||
|
i = static_cast<s32>(b);
|
||||||
|
if (b - i < 0)
|
||||||
|
{
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value = static_cast<u32>(i);
|
||||||
|
const double di = i;
|
||||||
|
if (di == b)
|
||||||
|
{
|
||||||
|
FPSCR.FI = 0;
|
||||||
|
FPSCR.FR = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Also sets FPSCR[XX]
|
||||||
|
SetFI(1);
|
||||||
|
FPSCR.FR = fabs(di) > fabs(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exception_occurred)
|
||||||
|
{
|
||||||
|
FPSCR.FI = 0;
|
||||||
|
FPSCR.FR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!exception_occurred || FPSCR.VE == 0)
|
||||||
|
{
|
||||||
|
// Based on HW tests
|
||||||
|
// FPRF is not affected
|
||||||
|
riPS0(inst.FD) = 0xfff8000000000000ull | value;
|
||||||
|
if (value == 0 && std::signbit(b))
|
||||||
|
riPS0(inst.FD) |= 0x100000000ull;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inst.Rc)
|
||||||
|
Helper_UpdateCR1();
|
||||||
}
|
}
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction inst, double fa, double fb)
|
void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction inst, double fa, double fb)
|
||||||
{
|
{
|
||||||
@ -103,127 +208,14 @@ void Interpreter::fcmpu(UGeckoInstruction inst)
|
|||||||
Helper_FloatCompareUnordered(inst, rPS0(inst.FA), rPS0(inst.FB));
|
Helper_FloatCompareUnordered(inst, rPS0(inst.FA), rPS0(inst.FB));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply current rounding mode
|
|
||||||
void Interpreter::fctiwx(UGeckoInstruction inst)
|
void Interpreter::fctiwx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
const double b = rPS0(inst.FB);
|
ConvertToInteger(inst, static_cast<RoundingMode>(FPSCR.RN));
|
||||||
u32 value;
|
|
||||||
|
|
||||||
if (b > (double)0x7fffffff)
|
|
||||||
{
|
|
||||||
value = 0x7fffffff;
|
|
||||||
SetFPException(FPSCR_VXCVI);
|
|
||||||
FPSCR.FI = 0;
|
|
||||||
FPSCR.FR = 0;
|
|
||||||
}
|
|
||||||
else if (b < -(double)0x80000000)
|
|
||||||
{
|
|
||||||
value = 0x80000000;
|
|
||||||
SetFPException(FPSCR_VXCVI);
|
|
||||||
FPSCR.FI = 0;
|
|
||||||
FPSCR.FR = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s32 i = 0;
|
|
||||||
switch (FPSCR.RN)
|
|
||||||
{
|
|
||||||
case 0: // nearest
|
|
||||||
{
|
|
||||||
double t = b + 0.5;
|
|
||||||
i = (s32)t;
|
|
||||||
|
|
||||||
if (t - i < 0 || (t - i == 0 && b > 0))
|
|
||||||
{
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1: // zero
|
|
||||||
i = (s32)b;
|
|
||||||
break;
|
|
||||||
case 2: // +inf
|
|
||||||
i = (s32)b;
|
|
||||||
if (b - i > 0)
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3: // -inf
|
|
||||||
i = (s32)b;
|
|
||||||
if (b - i < 0)
|
|
||||||
{
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
value = (u32)i;
|
|
||||||
double di = i;
|
|
||||||
if (di == b)
|
|
||||||
{
|
|
||||||
FPSCR.FI = 0;
|
|
||||||
FPSCR.FR = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetFI(1);
|
|
||||||
FPSCR.FR = fabs(di) > fabs(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// based on HW tests
|
|
||||||
// FPRF is not affected
|
|
||||||
riPS0(inst.FD) = 0xfff8000000000000ull | value;
|
|
||||||
if (value == 0 && std::signbit(b))
|
|
||||||
riPS0(inst.FD) |= 0x100000000ull;
|
|
||||||
if (inst.Rc)
|
|
||||||
Helper_UpdateCR1();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always round toward zero
|
|
||||||
void Interpreter::fctiwzx(UGeckoInstruction inst)
|
void Interpreter::fctiwzx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
const double b = rPS0(inst.FB);
|
ConvertToInteger(inst, RoundingMode::TowardsZero);
|
||||||
u32 value;
|
|
||||||
|
|
||||||
if (b > (double)0x7fffffff)
|
|
||||||
{
|
|
||||||
value = 0x7fffffff;
|
|
||||||
SetFPException(FPSCR_VXCVI);
|
|
||||||
FPSCR.FI = 0;
|
|
||||||
FPSCR.FR = 0;
|
|
||||||
}
|
|
||||||
else if (b < -(double)0x80000000)
|
|
||||||
{
|
|
||||||
value = 0x80000000;
|
|
||||||
SetFPException(FPSCR_VXCVI);
|
|
||||||
FPSCR.FI = 0;
|
|
||||||
FPSCR.FR = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s32 i = (s32)b;
|
|
||||||
double di = i;
|
|
||||||
if (di == b)
|
|
||||||
{
|
|
||||||
FPSCR.FI = 0;
|
|
||||||
FPSCR.FR = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetFI(1);
|
|
||||||
FPSCR.FR = fabs(di) > fabs(b);
|
|
||||||
}
|
|
||||||
value = (u32)i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// based on HW tests
|
|
||||||
// FPRF is not affected
|
|
||||||
riPS0(inst.FD) = 0xfff8000000000000ull | value;
|
|
||||||
if (value == 0 && std::signbit(b))
|
|
||||||
riPS0(inst.FD) |= 0x100000000ull;
|
|
||||||
if (inst.Rc)
|
|
||||||
Helper_UpdateCR1();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::fmrx(UGeckoInstruction inst)
|
void Interpreter::fmrx(UGeckoInstruction inst)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user