Interpreter_FloatingPoint: Handle NaN flag setting within fctiw and fctiwz

If a NaN of any type is passed as the operand to either of these
instructions, we shouldn't go down the regular code path, as we end up
potentially setting the wrong flags. For example, we wouldn't set the
FPSCR.VXCVI bit properly. We'd also set FPSCR.FI, when in actuality it
should be unset.

If an SNaN is passed as an operand, we also need to set the FPSCR.VXSNAN
bit as well.

The flag setting behavior for these can be found in Appendix C.4.2 in
PowerPC Microprocessor Family: The Programming Environments Manual for
32 and 64-bit Microprocessors.
This commit is contained in:
Lioncash 2018-05-26 19:18:18 -04:00
parent 0125d9b099
commit 8c4aa133ca

View File

@ -22,13 +22,27 @@ enum class RoundingMode
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;
if (b > static_cast<double>(0x7fffffff))
if (std::isnan(b))
{
if (Common::IsSNAN(b))
SetFPException(FPSCR_VXSNAN);
value = 0x80000000;
SetFPException(FPSCR_VXCVI);
FPSCR.FI = 0;
FPSCR.FR = 0;
}
else if (b > static_cast<double>(0x7fffffff))
{
// Positive large operand or +inf
value = 0x7fffffff;
SetFPException(FPSCR_VXCVI);
FPSCR.FI = 0;
@ -36,6 +50,7 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
}
else if (b < -static_cast<double>(0x80000000))
{
// Negative large operand or -inf
value = 0x80000000;
SetFPException(FPSCR_VXCVI);
FPSCR.FI = 0;
@ -84,6 +99,7 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
}
else
{
// Also sets FPSCR[XX]
SetFI(1);
FPSCR.FR = fabs(di) > fabs(b);
}