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:
EmptyChaos 2016-09-24 15:14:51 +00:00
parent 83407263e5
commit c3cef54910
6 changed files with 46 additions and 33 deletions

View File

@ -2,6 +2,7 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/Assert.h"
#include "Common/CommonPaths.h"
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
@ -178,7 +179,8 @@ bool CBoot::EmulatedBS2_GC(bool skipAppLoader)
PatchEngine::LoadPatches();
// 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;
}

View File

@ -157,25 +157,11 @@ static Installation InstallCodeHandlerLocked()
return Installation::Installed;
}
void RunCodeHandler(u32 msr_reg)
void RunCodeHandler()
{
if (!SConfig::GetInstance().bEnableCheats)
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);
// 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.

View File

@ -52,6 +52,6 @@ constexpr u32 HLE_TRAMPOLINE_ADDRESS = INSTALLER_END_ADDRESS - 4;
constexpr u32 MAGIC_GAMEID = 0xD01F1BAD;
void SetActiveCodes(const std::vector<GeckoCode>& gcodes);
void RunCodeHandler(u32 msr_reg);
void RunCodeHandler();
} // namespace Gecko

View File

@ -166,11 +166,29 @@ s64 GetLocalTimeRTCOffset()
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
PatchEngine::ApplyFramePatches();
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerField() - cyclesLate, et_PatchEngine);
// We have 2 periods, a 1000 cycle error period and the VI period.
// We have to carefully combine these together so that we stay on the VI period without drifting.
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)

View File

@ -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
// probably be using some sort of Gecko OS-style hooking mechanism
// so the emulated CPU is in a predictable state when we process cheats.
u32 oldMSR = MSR;
UReg_MSR newMSR = oldMSR;
newMSR.IR = 1;
newMSR.DR = 1;
MSR = newMSR.Hex;
// Because we're using the VI Interrupt to time this instead of patching the game with a
// callback hook we can end up catching the game in an exception vector.
// We deal with this by returning false so that SystemTimers will reschedule us in a few cycles
// where we can try again after the CPU hopefully returns back to the normal instruction flow.
UReg_MSR msr = MSR;
if (!msr.DR || !msr.IR)
{
INFO_LOG(
ACTIONREPLAY,
"Need to retry later. CPU configuration is currently incorrect. PC = 0x%08X, MSR = 0x%08X",
PC, MSR);
return false;
}
ApplyPatches(onFrame);
// Run the Gecko code handler
Gecko::RunCodeHandler(oldMSR);
Gecko::RunCodeHandler();
ActionReplay::RunAllActive();
MSR = oldMSR;
return true;
}
void Shutdown()

View File

@ -43,7 +43,7 @@ int GetSpeedhackCycles(const u32 addr);
void LoadPatchSection(const std::string& section, std::vector<Patch>& patches, IniFile& globalIni,
IniFile& localIni);
void LoadPatches();
void ApplyFramePatches();
bool ApplyFramePatches();
void Shutdown();
inline int GetPatchTypeCharLength(PatchType type)