PatchEngine: Handle MSR more cleanly
Instead of fiddling with the MSR value, just reschedule and try again after the game fixes it itself.
This commit is contained in:
parent
83407263e5
commit
c3cef54910
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "Common/Assert.h"
|
||||||
#include "Common/CommonPaths.h"
|
#include "Common/CommonPaths.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
|
@ -178,7 +179,8 @@ bool CBoot::EmulatedBS2_GC(bool skipAppLoader)
|
||||||
PatchEngine::LoadPatches();
|
PatchEngine::LoadPatches();
|
||||||
|
|
||||||
// If we have any patches that need to be applied very early, here's a good place
|
// If we have any patches that need to be applied very early, here's a good place
|
||||||
PatchEngine::ApplyFramePatches();
|
bool patched = PatchEngine::ApplyFramePatches();
|
||||||
|
_assert_(patched);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,25 +157,11 @@ static Installation InstallCodeHandlerLocked()
|
||||||
return Installation::Installed;
|
return Installation::Installed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunCodeHandler(u32 msr_reg)
|
void RunCodeHandler()
|
||||||
{
|
{
|
||||||
if (!SConfig::GetInstance().bEnableCheats)
|
if (!SConfig::GetInstance().bEnableCheats)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Dolphin's hook mechanism is less 'precise' than Gecko OS' which detects particular
|
|
||||||
// instruction sequences (uses configuration, not automatic) that only run once per frame
|
|
||||||
// which includes a BLR as one of the instructions. It then overwrites the BLR with a
|
|
||||||
// "B 0x800018A8" to establish the hook. Dolphin uses its own internal VI interrupt which
|
|
||||||
// means the PC is non-deterministic and could be anywhere.
|
|
||||||
UReg_MSR msr = msr_reg;
|
|
||||||
if (!msr.DR || !msr.IR)
|
|
||||||
{
|
|
||||||
WARN_LOG(ACTIONREPLAY, "GeckoCode: Skipping frame update. MSR.IR/DR is currently disabled. "
|
|
||||||
"PC = 0x%08X, MSR = 0x%08X",
|
|
||||||
PC, msr_reg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> codes_lock(s_active_codes_lock);
|
std::lock_guard<std::mutex> codes_lock(s_active_codes_lock);
|
||||||
// Don't spam retry if the install failed. The corrupt / missing disk file is not likely to be
|
// Don't spam retry if the install failed. The corrupt / missing disk file is not likely to be
|
||||||
// fixed within 1 frame of the last error.
|
// fixed within 1 frame of the last error.
|
||||||
|
|
|
@ -52,6 +52,6 @@ constexpr u32 HLE_TRAMPOLINE_ADDRESS = INSTALLER_END_ADDRESS - 4;
|
||||||
constexpr u32 MAGIC_GAMEID = 0xD01F1BAD;
|
constexpr u32 MAGIC_GAMEID = 0xD01F1BAD;
|
||||||
|
|
||||||
void SetActiveCodes(const std::vector<GeckoCode>& gcodes);
|
void SetActiveCodes(const std::vector<GeckoCode>& gcodes);
|
||||||
void RunCodeHandler(u32 msr_reg);
|
void RunCodeHandler();
|
||||||
|
|
||||||
} // namespace Gecko
|
} // namespace Gecko
|
||||||
|
|
|
@ -166,11 +166,29 @@ s64 GetLocalTimeRTCOffset()
|
||||||
return s_localtime_rtc_offset;
|
return s_localtime_rtc_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PatchEngineCallback(u64 userdata, s64 cyclesLate)
|
static void PatchEngineCallback(u64 userdata, s64 cycles_late)
|
||||||
{
|
{
|
||||||
// Patch mem and run the Action Replay
|
// We have 2 periods, a 1000 cycle error period and the VI period.
|
||||||
PatchEngine::ApplyFramePatches();
|
// We have to carefully combine these together so that we stay on the VI period without drifting.
|
||||||
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerField() - cyclesLate, et_PatchEngine);
|
u32 vi_interval = VideoInterface::GetTicksPerField();
|
||||||
|
s64 cycles_pruned = (userdata + cycles_late) % vi_interval;
|
||||||
|
s64 next_schedule = 0;
|
||||||
|
|
||||||
|
// Try to patch mem and run the Action Replay
|
||||||
|
if (PatchEngine::ApplyFramePatches())
|
||||||
|
{
|
||||||
|
next_schedule = vi_interval - cycles_pruned;
|
||||||
|
cycles_pruned = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The patch failed, usually because the CPU is in an inappropriate state (interrupt handler).
|
||||||
|
// We'll try again after 1000 cycles.
|
||||||
|
next_schedule = 1000;
|
||||||
|
cycles_pruned += next_schedule;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreTiming::ScheduleEvent(next_schedule, et_PatchEngine, cycles_pruned);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ThrottleCallback(u64 last_time, s64 cyclesLate)
|
static void ThrottleCallback(u64 last_time, s64 cyclesLate)
|
||||||
|
|
|
@ -203,22 +203,29 @@ static void ApplyPatches(const std::vector<Patch>& patches)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyFramePatches()
|
bool ApplyFramePatches()
|
||||||
{
|
{
|
||||||
// TODO: Messing with MSR this way is really, really, evil; we should
|
// Because we're using the VI Interrupt to time this instead of patching the game with a
|
||||||
// probably be using some sort of Gecko OS-style hooking mechanism
|
// callback hook we can end up catching the game in an exception vector.
|
||||||
// so the emulated CPU is in a predictable state when we process cheats.
|
// We deal with this by returning false so that SystemTimers will reschedule us in a few cycles
|
||||||
u32 oldMSR = MSR;
|
// where we can try again after the CPU hopefully returns back to the normal instruction flow.
|
||||||
UReg_MSR newMSR = oldMSR;
|
UReg_MSR msr = MSR;
|
||||||
newMSR.IR = 1;
|
if (!msr.DR || !msr.IR)
|
||||||
newMSR.DR = 1;
|
{
|
||||||
MSR = newMSR.Hex;
|
INFO_LOG(
|
||||||
|
ACTIONREPLAY,
|
||||||
|
"Need to retry later. CPU configuration is currently incorrect. PC = 0x%08X, MSR = 0x%08X",
|
||||||
|
PC, MSR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ApplyPatches(onFrame);
|
ApplyPatches(onFrame);
|
||||||
|
|
||||||
// Run the Gecko code handler
|
// Run the Gecko code handler
|
||||||
Gecko::RunCodeHandler(oldMSR);
|
Gecko::RunCodeHandler();
|
||||||
ActionReplay::RunAllActive();
|
ActionReplay::RunAllActive();
|
||||||
MSR = oldMSR;
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
|
|
|
@ -43,7 +43,7 @@ int GetSpeedhackCycles(const u32 addr);
|
||||||
void LoadPatchSection(const std::string& section, std::vector<Patch>& patches, IniFile& globalIni,
|
void LoadPatchSection(const std::string& section, std::vector<Patch>& patches, IniFile& globalIni,
|
||||||
IniFile& localIni);
|
IniFile& localIni);
|
||||||
void LoadPatches();
|
void LoadPatches();
|
||||||
void ApplyFramePatches();
|
bool ApplyFramePatches();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
inline int GetPatchTypeCharLength(PatchType type)
|
inline int GetPatchTypeCharLength(PatchType type)
|
||||||
|
|
Loading…
Reference in New Issue