mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
PowerPC: Set host CPU rounding mode on init and savestate
Not doing this can cause desyncs when TASing. (I don't know how common such desyncs would be, though. For games that don't change rounding modes, they shouldn't be a problem.)
This commit is contained in:
parent
8f9bb5612a
commit
9db0ebd4b6
@ -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,
|
||||||
|
@ -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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -306,4 +306,6 @@ inline void SetXER_OV(bool value)
|
|||||||
|
|
||||||
void UpdateFPRF(double dvalue);
|
void UpdateFPRF(double dvalue);
|
||||||
|
|
||||||
|
void RoundingModeUpdated();
|
||||||
|
|
||||||
} // namespace PowerPC
|
} // namespace PowerPC
|
||||||
|
Loading…
Reference in New Issue
Block a user