diff options
| author | Lioncash <mathew1800@gmail.com> | 2018-05-26 18:53:19 -0400 |
|---|---|---|
| committer | Lioncash <mathew1800@gmail.com> | 2018-05-28 13:28:44 -0400 |
| commit | 0125d9b0999834dc2de4e526fe9823722a00877a (patch) | |
| tree | 97232d18d12f801081d11270df8d6271c8b8f620 /Source/Core | |
| parent | bda668925a25000c197764ceac678fe345e59ada (diff) | |
Interpreter_FloatingPoint: Factor out common code from fctiw and fctiwz
fctiwz functions in the same manner as fctiw, with the difference being
that fctiwz always assumes the rounding mode being towards zero. Because
of this, we can implement fctiwz in terms of fctiw's code, but modify it
to accept a rounding mode, allowing us to preserve proper behavior for
both instructions.
We also move Helper_UpdateCR1 to a temporary home in
Interpreter_FPUtils.h for the time being. It would be more desirable to
move it to a new common header for all the helpers, so that even JITs
can use them if they so wish, however, this and the following changes
are intended to only touch the interpreter to keep changes minimal for
fixing instruction behavior.
JitCommon already duplicates the Helper_Mask function within
JitBase.cpp/.h, and the ARM JIT includes the Interpreter header in order
to call Helper_Carry. So a follow up is best suited here, as this
touches two other CPU backends.
Diffstat (limited to 'Source/Core')
3 files changed, 92 insertions, 120 deletions
diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter.h index dd4c88d94c..b1ea851041 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.h +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.h @@ -288,7 +288,6 @@ private: // flag helper static void Helper_UpdateCR0(u32 value); - static void Helper_UpdateCR1(); // address helper static u32 Helper_Get_EA(const UGeckoInstruction inst); diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h index 2d16cbea84..0c98d3a939 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h @@ -52,6 +52,11 @@ inline void UpdateFPSCR() (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) { // convert to float... diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp index de4f453654..f8f64ed37f 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp @@ -11,12 +11,93 @@ #include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h" #include "Core/PowerPC/PowerPC.h" -// Extremely rare - actually, never seen. -// Star Wars : Rogue Leader spams that at some point :| -void Interpreter::Helper_UpdateCR1() +namespace { - 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 +}; + +void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode) +{ + const double b = rPS0(inst.FB); + u32 value; + + if (b > static_cast<double>(0x7fffffff)) + { + value = 0x7fffffff; + SetFPException(FPSCR_VXCVI); + FPSCR.FI = 0; + FPSCR.FR = 0; + } + else if (b < -static_cast<double>(0x80000000)) + { + value = 0x80000000; + SetFPException(FPSCR_VXCVI); + FPSCR.FI = 0; + FPSCR.FR = 0; + } + 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 + { + 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(); } +} // Anonymous namespace void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction inst, double fa, double fb) { @@ -103,127 +184,14 @@ void Interpreter::fcmpu(UGeckoInstruction inst) Helper_FloatCompareUnordered(inst, rPS0(inst.FA), rPS0(inst.FB)); } -// Apply current rounding mode void Interpreter::fctiwx(UGeckoInstruction inst) { - const double b = rPS0(inst.FB); - 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(); + ConvertToInteger(inst, static_cast<RoundingMode>(FPSCR.RN)); } -// Always round toward zero void Interpreter::fctiwzx(UGeckoInstruction inst) { - const double b = rPS0(inst.FB); - 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(); + ConvertToInteger(inst, RoundingMode::TowardsZero); } void Interpreter::fmrx(UGeckoInstruction inst) |
