summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorLioncash <mathew1800@gmail.com>2018-06-05 16:00:14 -0400
committerLioncash <mathew1800@gmail.com>2018-06-05 16:27:10 -0400
commit11a35d47efff3d96f48629b189cdf6f02fba3e90 (patch)
tree100b7c4a96ede6d2f9c463d08800a5c37434cac0 /Source/Core
parent36ff2a20d52ed9901ee5d24644b2d0e026a1fd2c (diff)
Interpreter_SystemRegisters: Ensure FPSCR modifying instructions don't set bit 20
Bit 20 is defined as being reserved and attempts to set it are ignored by hardware, so we should be doing the same thing.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp39
1 files changed, 29 insertions, 10 deletions
diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp
index 8eca362718..05c88032ed 100644
--- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp
+++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp
@@ -58,15 +58,24 @@ void Interpreter::mtfsb0x(UGeckoInstruction inst)
Helper_UpdateCR1();
}
+// This instruction can affect FX
void Interpreter::mtfsb1x(UGeckoInstruction inst)
{
- // this instruction can affect FX
- u32 b = 0x80000000 >> inst.CRBD;
- if (b & FPSCR_ANY_X)
- SetFPException(b);
- else
- FPSCR.Hex |= b;
- FPSCRtoFPUSettings(FPSCR);
+ const u32 bit = inst.CRBD;
+
+ // Bit 20 in the FPSCR is reserved and defined as zero,
+ // so we ensure that we don't set it.
+ if (bit != 20)
+ {
+ const u32 b = 0x80000000 >> bit;
+
+ if (b & FPSCR_ANY_X)
+ SetFPException(b);
+ else
+ FPSCR.Hex |= b;
+
+ FPSCRtoFPUSettings(FPSCR);
+ }
if (inst.Rc)
Helper_UpdateCR1();
@@ -74,10 +83,14 @@ void Interpreter::mtfsb1x(UGeckoInstruction inst)
void Interpreter::mtfsfix(UGeckoInstruction inst)
{
- u32 mask = (0xF0000000 >> (4 * inst.CRFD));
- u32 imm = (inst.hex << 16) & 0xF0000000;
+ // Bit 20 of the FPSCR is reserved and defined as zero on hardware,
+ // so ensure that we don't set it.
+ const u32 field = inst.CRFD;
+ const u32 pre_shifted_mask = field == 4 ? 0x70000000 : 0xF0000000;
+ const u32 mask = (pre_shifted_mask >> (4 * field));
+ const u32 imm = (inst.hex << 16) & pre_shifted_mask;
- FPSCR.Hex = (FPSCR.Hex & ~mask) | (imm >> (4 * inst.CRFD));
+ FPSCR.Hex = (FPSCR.Hex & ~mask) | (imm >> (4 * field));
FPSCRtoFPUSettings(FPSCR);
@@ -95,6 +108,12 @@ void Interpreter::mtfsfx(UGeckoInstruction inst)
m |= (0xFU << (i * 4));
}
+ // Bit 20 of the FPSCR is defined as always being zero
+ // (bit 11 in a little endian context), so ensure that
+ // we don't actually set that bit.
+ if ((fm & 0b100) != 0)
+ m &= 0xFFFFF7FF;
+
FPSCR.Hex = (FPSCR.Hex & ~m) | (static_cast<u32>(riPS0(inst.FB)) & m);
FPSCRtoFPUSettings(FPSCR);