Merge pull request #9805 from JosJuice/rounding-mode-savestate

PowerPC: Set host CPU rounding mode on init and savestate
This commit is contained in:
Léo Lam 2021-06-13 11:49:29 +02:00 committed by GitHub
commit 8ef4bd682b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 26 additions and 31 deletions

View File

@ -41,10 +41,6 @@ void SetRoundMode(int mode)
// We don't need to do anything here since SetSIMDMode is always called after calling this // 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) 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, // When AH is disabled, FZ controls flush-to-zero for both inputs and outputs. When AH is enabled,

View File

@ -29,8 +29,6 @@ enum PrecisionMode
void SetRoundMode(int mode); void SetRoundMode(int mode);
void SetPrecisionMode(PrecisionMode mode);
void SetSIMDMode(int rounding_mode, bool non_ieee_mode); void SetSIMDMode(int rounding_mode, bool non_ieee_mode);
/* /*

View File

@ -11,9 +11,6 @@ namespace FPURoundMode
void SetRoundMode(int mode) void SetRoundMode(int mode)
{ {
} }
void SetPrecisionMode(PrecisionMode mode)
{
}
void SetSIMDMode(int rounding_mode, bool non_ieee_mode) void SetSIMDMode(int rounding_mode, bool non_ieee_mode)
{ {
} }

View File

@ -22,11 +22,6 @@ void SetRoundMode(int mode)
fesetround(rounding_mode_lut[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) void SetSIMDMode(int rounding_mode, bool non_ieee_mode)
{ {
// OR-mask for disabling FPU exceptions (bits 7-12 in the MXCSR register) // OR-mask for disabling FPU exceptions (bits 7-12 in the MXCSR register)

View File

@ -25,6 +25,7 @@
#include "Common/CommonPaths.h" #include "Common/CommonPaths.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Event.h" #include "Common/Event.h"
#include "Common/FPURoundMode.h"
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
#include "Common/Flag.h" #include "Common/Flag.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
@ -625,6 +626,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
// thread, and then takes over and becomes the video thread // thread, and then takes over and becomes the video thread
Common::SetCurrentThreadName("Video thread"); Common::SetCurrentThreadName("Video thread");
UndeclareAsCPUThread(); UndeclareAsCPUThread();
FPURoundMode::LoadDefaultSIMDState();
// Spawn the CPU thread. The CPU thread will signal the event that boot is complete. // 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); s_cpu_thread = std::thread(cpuThreadFunc, savestate_path, delete_savestate);

View File

@ -87,6 +87,10 @@ static void ExecutePendingJobs(std::unique_lock<std::mutex>& state_lock)
void Run() 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); std::unique_lock state_lock(s_state_change_lock);
while (s_state != State::PowerDown) while (s_state != State::PowerDown)
{ {

View File

@ -6,7 +6,6 @@
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/FPURoundMode.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Core/HW/GPFifo.h" #include "Core/HW/GPFifo.h"
#include "Core/HW/SystemTimers.h" #include "Core/HW/SystemTimers.h"
@ -26,13 +25,10 @@ mffsx: 80036608
mffsx: 80036650 (huh?) 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) 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); // fp.VE, fp.OE, fp.UE, fp.ZE, fp.XE);
// Pokemon Colosseum does this. Gah. // Pokemon Colosseum does this. Gah.
} }
// Set SSE rounding mode and denormal handling
FPURoundMode::SetSIMDMode(fp.RN, fp.NI);
} }
static void UpdateFPSCR(UReg_FPSCR* fpscr) static void UpdateFPSCR(UReg_FPSCR* fpscr)
@ -57,7 +50,7 @@ void Interpreter::mtfsb0x(UGeckoInstruction inst)
u32 b = 0x80000000 >> inst.CRBD; u32 b = 0x80000000 >> inst.CRBD;
FPSCR.Hex &= ~b; FPSCR.Hex &= ~b;
FPSCRtoFPUSettings(FPSCR); FPSCRUpdated(FPSCR);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@ -74,7 +67,7 @@ void Interpreter::mtfsb1x(UGeckoInstruction inst)
else else
FPSCR |= b; FPSCR |= b;
FPSCRtoFPUSettings(FPSCR); FPSCRUpdated(FPSCR);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@ -89,7 +82,7 @@ void Interpreter::mtfsfix(UGeckoInstruction inst)
FPSCR = (FPSCR.Hex & ~mask) | (imm >> (4 * field)); FPSCR = (FPSCR.Hex & ~mask) | (imm >> (4 * field));
FPSCRtoFPUSettings(FPSCR); FPSCRUpdated(FPSCR);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();
@ -106,7 +99,7 @@ void Interpreter::mtfsfx(UGeckoInstruction inst)
} }
FPSCR = (FPSCR.Hex & ~m) | (static_cast<u32>(rPS(inst.FB).PS0AsU64()) & m); FPSCR = (FPSCR.Hex & ~m) | (static_cast<u32>(rPS(inst.FB).PS0AsU64()) & m);
FPSCRtoFPUSettings(FPSCR); FPSCRUpdated(FPSCR);
if (inst.Rc) if (inst.Rc)
PowerPC::ppcState.UpdateCR1(); PowerPC::ppcState.UpdateCR1();

View File

@ -20,6 +20,7 @@
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h" #include "Core/CoreTiming.h"
#include "Core/HW/CPU.h" #include "Core/HW/CPU.h"
#include "Core/HW/SystemTimers.h" #include "Core/HW/SystemTimers.h"
@ -129,6 +130,7 @@ void DoState(PointerWrap& p)
if (p.GetMode() == PointerWrap::MODE_READ) if (p.GetMode() == PointerWrap::MODE_READ)
{ {
RoundingModeUpdated();
IBATUpdated(); IBATUpdated();
DBATUpdated(); DBATUpdated();
} }
@ -180,6 +182,7 @@ static void ResetRegisters()
} }
SetXER({}); SetXER({});
RoundingModeUpdated();
DBATUpdated(); DBATUpdated();
IBATUpdated(); IBATUpdated();
@ -246,10 +249,6 @@ CPUCore DefaultCPUCore()
void Init(CPUCore cpu_core) 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 = s_invalidate_cache_thread_safe =
CoreTiming::RegisterEvent("invalidateEmulatedCache", InvalidateCacheThreadSafe); CoreTiming::RegisterEvent("invalidateEmulatedCache", InvalidateCacheThreadSafe);
@ -632,4 +631,13 @@ void UpdateFPRF(double dvalue)
FPSCR.FPRF = Common::ClassifyDouble(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 } // namespace PowerPC

View File

@ -306,4 +306,6 @@ inline void SetXER_OV(bool value)
void UpdateFPRF(double dvalue); void UpdateFPRF(double dvalue);
void RoundingModeUpdated();
} // namespace PowerPC } // namespace PowerPC