From 11a35d47efff3d96f48629b189cdf6f02fba3e90 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 5 Jun 2018 16:00:14 -0400 Subject: [PATCH] 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. --- .../Interpreter_SystemRegisters.cpp | 39 ++++++++++++++----- 1 file 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(riPS0(inst.FB)) & m); FPSCRtoFPUSettings(FPSCR);