diff --git a/Source/Core/Common/ArmFPURoundMode.cpp b/Source/Core/Common/ArmFPURoundMode.cpp index 94ed16d279..81daf68d2f 100644 --- a/Source/Core/Common/ArmFPURoundMode.cpp +++ b/Source/Core/Common/ArmFPURoundMode.cpp @@ -41,10 +41,6 @@ void SetRoundMode(int mode) // We don't need to do anything here since SetSIMDMode is always called after calling this } -void SetPrecisionMode(PrecisionMode mode) -{ -} - void SetSIMDMode(int rounding_mode, bool non_ieee_mode) { // When AH is disabled, FZ controls flush-to-zero for both inputs and outputs. When AH is enabled, diff --git a/Source/Core/Common/FPURoundMode.h b/Source/Core/Common/FPURoundMode.h index ac99478982..5fba5c9fda 100644 --- a/Source/Core/Common/FPURoundMode.h +++ b/Source/Core/Common/FPURoundMode.h @@ -29,8 +29,6 @@ enum PrecisionMode void SetRoundMode(int mode); -void SetPrecisionMode(PrecisionMode mode); - void SetSIMDMode(int rounding_mode, bool non_ieee_mode); /* diff --git a/Source/Core/Common/GenericFPURoundMode.cpp b/Source/Core/Common/GenericFPURoundMode.cpp index e8bbbb7e48..81b59e6d1e 100644 --- a/Source/Core/Common/GenericFPURoundMode.cpp +++ b/Source/Core/Common/GenericFPURoundMode.cpp @@ -11,9 +11,6 @@ namespace FPURoundMode void SetRoundMode(int mode) { } -void SetPrecisionMode(PrecisionMode mode) -{ -} void SetSIMDMode(int rounding_mode, bool non_ieee_mode) { } diff --git a/Source/Core/Common/x64FPURoundMode.cpp b/Source/Core/Common/x64FPURoundMode.cpp index a12f99efd2..9af3ec4691 100644 --- a/Source/Core/Common/x64FPURoundMode.cpp +++ b/Source/Core/Common/x64FPURoundMode.cpp @@ -22,11 +22,6 @@ void SetRoundMode(int mode) fesetround(rounding_mode_lut[mode]); } -void SetPrecisionMode(PrecisionMode /* mode */) -{ - // x64 doesn't need this - fpu is done with SSE -} - void SetSIMDMode(int rounding_mode, bool non_ieee_mode) { // OR-mask for disabling FPU exceptions (bits 7-12 in the MXCSR register) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 1ec847cecc..ddda19036f 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -25,6 +25,7 @@ #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" #include "Common/Event.h" +#include "Common/FPURoundMode.h" #include "Common/FileUtil.h" #include "Common/Flag.h" #include "Common/Logging/Log.h" @@ -625,6 +626,7 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi // thread, and then takes over and becomes the video thread Common::SetCurrentThreadName("Video thread"); UndeclareAsCPUThread(); + FPURoundMode::LoadDefaultSIMDState(); // Spawn the CPU thread. The CPU thread will signal the event that boot is complete. s_cpu_thread = std::thread(cpuThreadFunc, savestate_path, delete_savestate); diff --git a/Source/Core/Core/HW/CPU.cpp b/Source/Core/Core/HW/CPU.cpp index b708263bfc..e12db40dde 100644 --- a/Source/Core/Core/HW/CPU.cpp +++ b/Source/Core/Core/HW/CPU.cpp @@ -87,6 +87,10 @@ static void ExecutePendingJobs(std::unique_lock& state_lock) void Run() { + // Updating the host CPU's rounding mode must be done on the CPU thread. + // We can't rely on PowerPC::Init doing it, since it's called from EmuThread. + PowerPC::RoundingModeUpdated(); + std::unique_lock state_lock(s_state_change_lock); while (s_state != State::PowerDown) { diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp index c9d23577b8..ae0ff724c3 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp @@ -6,7 +6,6 @@ #include "Common/Assert.h" #include "Common/CommonTypes.h" -#include "Common/FPURoundMode.h" #include "Common/Logging/Log.h" #include "Core/HW/GPFifo.h" #include "Core/HW/SystemTimers.h" @@ -26,13 +25,10 @@ mffsx: 80036608 mffsx: 80036650 (huh?) */ -// TODO(ector): More proper handling of SSE state. -// That is, set rounding mode etc when entering jit code or the interpreter loop -// Restore rounding mode when calling anything external -static void FPSCRtoFPUSettings(UReg_FPSCR fp) +static void FPSCRUpdated(UReg_FPSCR fp) { - FPURoundMode::SetRoundMode(fp.RN); + PowerPC::RoundingModeUpdated(); if (fp.VE || fp.OE || fp.UE || fp.ZE || fp.XE) { @@ -40,9 +36,6 @@ static void FPSCRtoFPUSettings(UReg_FPSCR fp) // fp.VE, fp.OE, fp.UE, fp.ZE, fp.XE); // Pokemon Colosseum does this. Gah. } - - // Set SSE rounding mode and denormal handling - FPURoundMode::SetSIMDMode(fp.RN, fp.NI); } static void UpdateFPSCR(UReg_FPSCR* fpscr) @@ -57,7 +50,7 @@ void Interpreter::mtfsb0x(UGeckoInstruction inst) u32 b = 0x80000000 >> inst.CRBD; FPSCR.Hex &= ~b; - FPSCRtoFPUSettings(FPSCR); + FPSCRUpdated(FPSCR); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -74,7 +67,7 @@ void Interpreter::mtfsb1x(UGeckoInstruction inst) else FPSCR |= b; - FPSCRtoFPUSettings(FPSCR); + FPSCRUpdated(FPSCR); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -89,7 +82,7 @@ void Interpreter::mtfsfix(UGeckoInstruction inst) FPSCR = (FPSCR.Hex & ~mask) | (imm >> (4 * field)); - FPSCRtoFPUSettings(FPSCR); + FPSCRUpdated(FPSCR); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -106,7 +99,7 @@ void Interpreter::mtfsfx(UGeckoInstruction inst) } FPSCR = (FPSCR.Hex & ~m) | (static_cast(rPS(inst.FB).PS0AsU64()) & m); - FPSCRtoFPUSettings(FPSCR); + FPSCRUpdated(FPSCR); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index 4388a6ce5f..73eac23a94 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -20,6 +20,7 @@ #include "Common/Logging/Log.h" #include "Core/ConfigManager.h" +#include "Core/Core.h" #include "Core/CoreTiming.h" #include "Core/HW/CPU.h" #include "Core/HW/SystemTimers.h" @@ -129,6 +130,7 @@ void DoState(PointerWrap& p) if (p.GetMode() == PointerWrap::MODE_READ) { + RoundingModeUpdated(); IBATUpdated(); DBATUpdated(); } @@ -180,6 +182,7 @@ static void ResetRegisters() } SetXER({}); + RoundingModeUpdated(); DBATUpdated(); IBATUpdated(); @@ -246,10 +249,6 @@ CPUCore DefaultCPUCore() void Init(CPUCore cpu_core) { - // NOTE: This function runs on EmuThread, not the CPU Thread. - // Changing the rounding mode has a limited effect. - FPURoundMode::SetPrecisionMode(FPURoundMode::PREC_53); - s_invalidate_cache_thread_safe = CoreTiming::RegisterEvent("invalidateEmulatedCache", InvalidateCacheThreadSafe); @@ -632,4 +631,13 @@ void UpdateFPRF(double dvalue) FPSCR.FPRF = Common::ClassifyDouble(dvalue); } +void RoundingModeUpdated() +{ + // The rounding mode is separate for each thread, so this must run on the CPU thread + ASSERT(Core::IsCPUThread()); + + FPURoundMode::SetRoundMode(FPSCR.RN); + FPURoundMode::SetSIMDMode(FPSCR.RN, FPSCR.NI); +} + } // namespace PowerPC diff --git a/Source/Core/Core/PowerPC/PowerPC.h b/Source/Core/Core/PowerPC/PowerPC.h index 34804dfb12..73919161f2 100644 --- a/Source/Core/Core/PowerPC/PowerPC.h +++ b/Source/Core/Core/PowerPC/PowerPC.h @@ -306,4 +306,6 @@ inline void SetXER_OV(bool value) void UpdateFPRF(double dvalue); +void RoundingModeUpdated(); + } // namespace PowerPC