Interpreter_FloatingPoint: Handle cases when FPSCR.VE is set and exceptions occur in fctiw and fctiwz

If invalid operation exceptions are enabled and an invalid operation
occurs, then the destination value remains untouched. This fixes issues
that may arise when using these two instructions where the destination
gets steamrolled by an infinity or NaN value.
This commit is contained in:
Lioncash 2018-05-26 19:58:19 -04:00
parent 8c4aa133ca
commit 78a934bb12
1 changed files with 19 additions and 11 deletions

View File

@ -29,6 +29,7 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
{ {
const double b = rPS0(inst.FB); const double b = rPS0(inst.FB);
u32 value; u32 value;
bool exception_occurred = false;
if (std::isnan(b)) if (std::isnan(b))
{ {
@ -37,24 +38,21 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
value = 0x80000000; value = 0x80000000;
SetFPException(FPSCR_VXCVI); SetFPException(FPSCR_VXCVI);
FPSCR.FI = 0; exception_occurred = true;
FPSCR.FR = 0;
} }
else if (b > static_cast<double>(0x7fffffff)) else if (b > static_cast<double>(0x7fffffff))
{ {
// Positive large operand or +inf // Positive large operand or +inf
value = 0x7fffffff; value = 0x7fffffff;
SetFPException(FPSCR_VXCVI); SetFPException(FPSCR_VXCVI);
FPSCR.FI = 0; exception_occurred = true;
FPSCR.FR = 0;
} }
else if (b < -static_cast<double>(0x80000000)) else if (b < -static_cast<double>(0x80000000))
{ {
// Negative large operand or -inf // Negative large operand or -inf
value = 0x80000000; value = 0x80000000;
SetFPException(FPSCR_VXCVI); SetFPException(FPSCR_VXCVI);
FPSCR.FI = 0; exception_occurred = true;
FPSCR.FR = 0;
} }
else else
{ {
@ -105,11 +103,21 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
} }
} }
// Based on HW tests if (exception_occurred)
// FPRF is not affected {
riPS0(inst.FD) = 0xfff8000000000000ull | value; FPSCR.FI = 0;
if (value == 0 && std::signbit(b)) FPSCR.FR = 0;
riPS0(inst.FD) |= 0x100000000ull; }
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) if (inst.Rc)
Helper_UpdateCR1(); Helper_UpdateCR1();
} }