From 983ea69a57b2b0028abfcb802edad6ecf51e82f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 6 Dec 2024 14:12:21 +0100 Subject: [PATCH] Replay: Add some plumbing to propagate the Break status outwards --- Core/HLE/sceKernelModule.cpp | 14 +++++++--- GPU/Debugger/Playback.cpp | 53 +++++++++++++++++++++++++++++------- GPU/Debugger/Playback.h | 8 +++++- 3 files changed, 60 insertions(+), 15 deletions(-) diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index dd510c79fb..590bdb5921 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -1984,6 +1984,7 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str bool __KernelLoadGEDump(const std::string &base_filename, std::string *error_string) { __KernelLoadReset(); + // Start at the very base of user memory. constexpr u32 codeStart = PSP_GetUserMemoryBase(); mipsr4k.pc = codeStart; @@ -2000,7 +2001,7 @@ bool __KernelLoadGEDump(const std::string &base_filename, std::string *error_str // Make sure we don't get out of sync. MIPS_MAKE_LUI(MIPS_REG_A0, 0), MIPS_MAKE_SYSCALL("sceGe_user", "sceGeDrawSync"), - // Wait for the next vblank to render again. + // Wait for the next vblank to render again, then (through the delay slot) jump right back up to __KernelGPUReplay. MIPS_MAKE_J(codeStart + 8), MIPS_MAKE_SYSCALL("sceDisplay", "sceDisplayWaitVblankStart"), // This never gets reached, just here to be "safe". @@ -2030,13 +2031,16 @@ int __KernelGPUReplay() { // Special ABI: s0 and s1 are the "args". Not null terminated. const char *filenamep = Memory::GetCharPointer(currentMIPS->r[MIPS_REG_S1]); if (!filenamep) { - ERROR_LOG(Log::G3D, "Failed to load dump filename"); + ERROR_LOG(Log::G3D, "__KernelGPUReplay: Failed to load dump filename"); Core_Stop(); return 0; } std::string filename(filenamep, currentMIPS->r[MIPS_REG_S0]); - if (!GPURecord::RunMountedReplay(filename)) { + GPURecord::ReplayResult result = GPURecord::RunMountedReplay(filename); + + if (result == GPURecord::ReplayResult::Error) { + ERROR_LOG(Log::G3D, "__KernelGPUReplay: Failed running replay."); Core_Stop(); } @@ -2047,7 +2051,9 @@ int __KernelGPUReplay() { System_SendDebugScreenshot(std::string((const char *)&topaddr[0], linesize * 272), 272); Core_Stop(); } - return 0; + + // Return 0 for normal looping, 1 for break. + return result == GPURecord::ReplayResult::Break ? 1 : 0; } int sceKernelLoadExec(const char *filename, u32 paramPtr) diff --git a/GPU/Debugger/Playback.cpp b/GPU/Debugger/Playback.cpp index 1efe13da70..14dc56d52f 100644 --- a/GPU/Debugger/Playback.cpp +++ b/GPU/Debugger/Playback.cpp @@ -291,7 +291,7 @@ public: } ~DumpExecute(); - bool Run(); + ReplayResult Run(); private: void SyncStall(); @@ -328,6 +328,9 @@ private: const std::vector &commands_; BufMapping mapping_; uint32_t version_ = 0; + + bool hitBreakPoint_ = false; + int resumeIndex_ = -1; }; void DumpExecute::SyncStall() { @@ -340,7 +343,17 @@ void DumpExecute::SyncStall() { gpu->UpdateStall(execListID, execListPos, &runList); if (runList) { DLResult result = gpu->ProcessDLQueue(); - _dbg_assert_(result == DLResult::Done || result == DLResult::Stall); + switch (result) { + case DLResult::Done: + case DLResult::Stall: + break; + case DLResult::Break: + // Hit breakpoint while interpreting! + hitBreakPoint_ = true; + break; + default: + _dbg_assert_(false); + } } s64 listTicks = gpu->GetListTicks(execListID); if (listTicks != -1) { @@ -660,12 +673,23 @@ DumpExecute::~DumpExecute() { mapping_.Reset(); } -bool DumpExecute::Run() { +ReplayResult DumpExecute::Run() { // Start with the default value. if (gpu) gpu->SetAddrTranslation(0x400); - for (size_t i = 0; i < commands_.size(); i++) { + if (resumeIndex_ >= 0) { + SyncStall(); + if (hitBreakPoint_) { + hitBreakPoint_ = false; + INFO_LOG(Log::System, "Hit breakpoint while running GE dump (resumeIndex_ = %d)", resumeIndex_); + // Done until next time + return ReplayResult::Break; + } + } + + int start = resumeIndex_ >= 0 ? resumeIndex_ : 0; + for (size_t i = start; i < commands_.size(); i++) { const Command &cmd = commands_[i]; switch (cmd.type) { case CommandType::INIT: @@ -740,12 +764,21 @@ bool DumpExecute::Run() { default: ERROR_LOG(Log::System, "Unsupported GE dump command: %d", (int)cmd.type); - return false; + return ReplayResult::Error; + } + + if (hitBreakPoint_) { + hitBreakPoint_ = false; + resumeIndex_ = (int)i; + _dbg_assert_(resumeIndex_ >= 0); + INFO_LOG(Log::System, "Hit breakpoint while running GE dump (at index %d)", i); + // Done until next time + return ReplayResult::Break; } } SubmitListEnd(); - return true; + return ReplayResult::Done; } static bool ReadCompressed(u32 fp, void *dest, size_t sz, uint32_t version) { @@ -779,7 +812,7 @@ static void ReplayStop() { lastExecVersion = 0; } -bool RunMountedReplay(const std::string &filename) { +ReplayResult RunMountedReplay(const std::string &filename) { _assert_msg_(!GPURecord::IsActivePending(), "Cannot run replay while recording."); std::lock_guard guard(executeLock); @@ -796,7 +829,7 @@ bool RunMountedReplay(const std::string &filename) { if (memcmp(header.magic, HEADER_MAGIC, sizeof(header.magic)) != 0 || header.version > VERSION || header.version < MIN_VERSION) { ERROR_LOG(Log::System, "Invalid GE dump or unsupported version"); pspFileSystem.CloseFile(fp); - return false; + return ReplayResult::Error; } if (header.version <= 3) { pspFileSystem.SeekFile(fp, 12, FILEMOVE_BEGIN); @@ -823,8 +856,8 @@ bool RunMountedReplay(const std::string &filename) { pspFileSystem.CloseFile(fp); if (truncated) { - ERROR_LOG(Log::System, "Truncated GE dump"); - return false; + ERROR_LOG(Log::System, "Truncated GE dump detected - can't replay"); + return ReplayResult::Error; } lastExecFilename = filename; diff --git a/GPU/Debugger/Playback.h b/GPU/Debugger/Playback.h index 433801cbf2..66d70fefa7 100644 --- a/GPU/Debugger/Playback.h +++ b/GPU/Debugger/Playback.h @@ -21,6 +21,12 @@ namespace GPURecord { -bool RunMountedReplay(const std::string &filename); +enum class ReplayResult { + Done = 0, + Error = 1, + Break = 2, +}; + +ReplayResult RunMountedReplay(const std::string &filename); };