diff --git a/Source/Core/Core/PowerPC/Gekko.h b/Source/Core/Core/PowerPC/Gekko.h index a47f26f08f..fda28b1fbc 100644 --- a/Source/Core/Core/PowerPC/Gekko.h +++ b/Source/Core/Core/PowerPC/Gekko.h @@ -474,8 +474,37 @@ union UReg_FPSCR }; u32 Hex = 0; + // The FPSCR's 20th bit (11th from a little endian perspective) + // is defined as reserved and set to zero. Attempts to modify it + // are ignored by hardware, so we do the same. + static constexpr u32 mask = 0xFFFFF7FF; + UReg_FPSCR() = default; - explicit UReg_FPSCR(u32 hex_) : Hex{hex_} {} + explicit UReg_FPSCR(u32 hex_) : Hex{hex_ & mask} {} + + UReg_FPSCR& operator=(u32 value) + { + Hex = value & mask; + return *this; + } + + UReg_FPSCR& operator|=(u32 value) + { + Hex |= value & mask; + return *this; + } + + UReg_FPSCR& operator&=(u32 value) + { + Hex &= value; + return *this; + } + + UReg_FPSCR& operator^=(u32 value) + { + Hex ^= value & mask; + return *this; + } void ClearFIFR() { diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp index 5772b3c732..57942be5e8 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp @@ -62,20 +62,14 @@ void Interpreter::mtfsb0x(UGeckoInstruction inst) void Interpreter::mtfsb1x(UGeckoInstruction inst) { const u32 bit = inst.CRBD; + const u32 b = 0x80000000 >> bit; - // 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 |= b; - if (b & FPSCR_ANY_X) - SetFPException(b); - else - FPSCR.Hex |= b; - - FPSCRtoFPUSettings(FPSCR); - } + FPSCRtoFPUSettings(FPSCR); if (inst.Rc) Helper_UpdateCR1(); @@ -83,14 +77,12 @@ void Interpreter::mtfsb1x(UGeckoInstruction inst) void Interpreter::mtfsfix(UGeckoInstruction inst) { - // 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 pre_shifted_mask = 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 * field)); + FPSCR = (FPSCR.Hex & ~mask) | (imm >> (4 * field)); FPSCRtoFPUSettings(FPSCR); @@ -108,13 +100,7 @@ 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); + FPSCR = (FPSCR.Hex & ~m) | (static_cast(riPS0(inst.FB)) & m); FPSCRtoFPUSettings(FPSCR); if (inst.Rc) diff --git a/Source/Core/DolphinQt2/Debugger/RegisterWidget.cpp b/Source/Core/DolphinQt2/Debugger/RegisterWidget.cpp index 98db9f671f..2a2fff7aa2 100644 --- a/Source/Core/DolphinQt2/Debugger/RegisterWidget.cpp +++ b/Source/Core/DolphinQt2/Debugger/RegisterWidget.cpp @@ -290,7 +290,7 @@ void RegisterWidget::PopulateTable() // FPSCR AddRegister(22, 5, RegisterType::fpscr, "FPSCR", [] { return PowerPC::ppcState.fpscr.Hex; }, - [](u64 value) { PowerPC::ppcState.fpscr.Hex = value; }); + [](u64 value) { PowerPC::ppcState.fpscr = static_cast(value); }); // MSR AddRegister(23, 5, RegisterType::msr, "MSR", [] { return PowerPC::ppcState.msr.Hex; }, diff --git a/Source/Core/DolphinWX/Debugger/RegisterView.cpp b/Source/Core/DolphinWX/Debugger/RegisterView.cpp index 6d62ca6b5e..0e392d829d 100644 --- a/Source/Core/DolphinWX/Debugger/RegisterView.cpp +++ b/Source/Core/DolphinWX/Debugger/RegisterView.cpp @@ -124,7 +124,7 @@ void SetSpecialRegValue(int reg, u32 value) PowerPC::SetXER(UReg_XER(value)); break; case 5: - PowerPC::ppcState.fpscr.Hex = value; + PowerPC::ppcState.fpscr = value; break; case 6: PowerPC::ppcState.msr.Hex = value;