From 4befbeac7c81dd8a08632d313b1b7537cbb87a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 9 Dec 2024 16:21:08 +0100 Subject: [PATCH] Move the dump playback mips code to Playback.cpp. Assorted cleanup. --- Core/HLE/sceKernelModule.cpp | 31 ++++--------------------------- Core/MIPS/MIPSCodeUtils.h | 2 +- Core/PSPLoaders.cpp | 2 +- GPU/Debugger/Playback.cpp | 36 +++++++++++++++++++++++++++++++++++- GPU/Debugger/Playback.h | 4 +++- UI/EmuScreen.cpp | 2 +- 6 files changed, 45 insertions(+), 32 deletions(-) diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 590bdb5921..97d8b6f513 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -1984,40 +1984,17 @@ 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; + const u32 codeStartAddr = PSP_GetUserMemoryBase(); + mipsr4k.pc = codeStartAddr; - const static u32_le runDumpCode[] = { - // Save the filename. - MIPS_MAKE_ORI(MIPS_REG_S0, MIPS_REG_A0, 0), - MIPS_MAKE_ORI(MIPS_REG_S1, MIPS_REG_A1, 0), - // Call the actual render. Jump here to start over. - MIPS_MAKE_SYSCALL("FakeSysCalls", "__KernelGPUReplay"), - MIPS_MAKE_NOP(), - // Re-run immediately if requested by the return value from __KernelGPUReplay - MIPS_MAKE_BNEZ(codeStart + 4 * 4, codeStart + 8, MIPS_REG_V0), - MIPS_MAKE_NOP(), - // 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, 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". - MIPS_MAKE_BREAK(0), - }; - - for (size_t i = 0; i < ARRAY_SIZE(runDumpCode); ++i) { - Memory::WriteUnchecked_U32(runDumpCode[i], mipsr4k.pc + (u32)i * sizeof(u32_le)); - } + GPURecord::WriteRunDumpCode(codeStartAddr); PSPModule *module = new PSPModule(); kernelObjects.Create(module); loadedModules.insert(module->GetUID()); memset(&module->nm, 0, sizeof(module->nm)); module->isFake = true; - module->nm.entry_addr = mipsr4k.pc; + module->nm.entry_addr = codeStartAddr; module->nm.gp_value = -1; SceUID threadID = __KernelSetupRootThread(module->GetUID(), (int)base_filename.size(), base_filename.data(), 0x20, 0x1000, 0); diff --git a/Core/MIPS/MIPSCodeUtils.h b/Core/MIPS/MIPSCodeUtils.h index 9665f49886..6f545f0aef 100644 --- a/Core/MIPS/MIPSCodeUtils.h +++ b/Core/MIPS/MIPSCodeUtils.h @@ -29,7 +29,7 @@ #define MIPS_MAKE_JAL(addr) (0x0C000000 | ((addr)>>2)) #define MIPS_MAKE_JR_RA() (0x03e00008) #define MIPS_MAKE_NOP() (0) -#define MIPS_MAKE_BNEZ(pc, addr, rs) (0x14000000 | (rs << 21) | (((int)(addr - (pc + 4)) >> 2) & 0xFFFF)) +#define MIPS_MAKE_BNEZ(pc, addr, rs) (0x14000000 | (rs << 21) | (u32)(((int)(addr - (pc + 4)) >> 2) & 0xFFFF)) #define MIPS_MAKE_ADDIU(dreg, sreg, immval) ((9 << 26) | ((dreg) << 16) | ((sreg) << 21) | (immval)) #define MIPS_MAKE_LUI(reg, immval) (0x3c000000 | ((reg) << 16) | (immval)) diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index 6a4aaa44c2..fc948fccba 100644 --- a/Core/PSPLoaders.cpp +++ b/Core/PSPLoaders.cpp @@ -45,12 +45,12 @@ #include "Core/MIPS/MIPS.h" #include "Core/MIPS/MIPSAnalyst.h" -#include "Core/MIPS/MIPSCodeUtils.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/System.h" #include "Core/PSPLoaders.h" +#include "GPU/Debugger/Playback.h" #include "Core/HLE/HLE.h" #include "Core/HLE/sceKernel.h" #include "Core/HLE/sceKernelThread.h" diff --git a/GPU/Debugger/Playback.cpp b/GPU/Debugger/Playback.cpp index 7288e66d39..b30354b399 100644 --- a/GPU/Debugger/Playback.cpp +++ b/GPU/Debugger/Playback.cpp @@ -40,6 +40,7 @@ #include "Core/HLE/sceKernelMemory.h" #include "Core/MemMap.h" #include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSCodeUtils.h" #include "Core/System.h" #include "GPU/GPUCommon.h" #include "GPU/GPUState.h" @@ -388,7 +389,10 @@ void DumpExecute::SyncStall() { currentMIPS->downcount -= listTicks - nowTicks; } } - // Make sure downcount doesn't overflow. + + // Make sure downcount doesn't overflow. (can this even happen?) + // Also this doesn't do anything in this context, we don't reschedule... or at least + // aren't supposed to. // CoreTiming::ForceCheck(); } @@ -408,6 +412,7 @@ void DumpExecute::Registers(u32 ptr, u32 sz) { Memory::Write_U32(GE_CMD_NOP << 24, execListPos); execListPos += 4; + // TODO: Why do we disable interrupts here? gpu->EnableInterrupts(false); ExecuteOnMain(Operation{ OpType::EnqueueList, execListBuf, execListPos }); gpu->EnableInterrupts(true); @@ -866,6 +871,35 @@ static u32 LoadReplay(const std::string &filename) { return version; } +void WriteRunDumpCode(u32 codeStart) { + // NOTE: Not static, since parts are run-time computed (MIPS_MAKE_SYSCALL etc) + const u32 runDumpCode[] = { + // Save the filename. + MIPS_MAKE_ORI(MIPS_REG_S0, MIPS_REG_A0, 0), + MIPS_MAKE_ORI(MIPS_REG_S1, MIPS_REG_A1, 0), + // Call the actual render. Jump here to start over. + MIPS_MAKE_SYSCALL("FakeSysCalls", "__KernelGPUReplay"), + MIPS_MAKE_NOP(), + // Re-run immediately if requested by the return value from __KernelGPUReplay + MIPS_MAKE_BNEZ(codeStart + 4 * 4, codeStart + 8, MIPS_REG_V0), + MIPS_MAKE_NOP(), + // When done (__KernelGPUReplay returned 0), make sure we don't get out of sync (is this needed?) + MIPS_MAKE_LUI(MIPS_REG_A0, 0), + MIPS_MAKE_SYSCALL("sceGe_user", "sceGeDrawSync"), + MIPS_MAKE_NOP(), + // Wait for the next vblank to render again, then (through the delay slot) jump right back up to __KernelGPUReplay. + MIPS_MAKE_SYSCALL("sceDisplay", "sceDisplayWaitVblankStart"), + MIPS_MAKE_NOP(), + MIPS_MAKE_J(codeStart + 8), + MIPS_MAKE_NOP(), + // This never gets reached, just here to be "safe". + MIPS_MAKE_BREAK(0), + }; + for (size_t i = 0; i < ARRAY_SIZE(runDumpCode); ++i) { + Memory::WriteUnchecked_U32(runDumpCode[i], codeStart + (u32)i * sizeof(u32_le)); + } +} + // This is called by the syscall. ReplayResult RunMountedReplay(const std::string &filename) { _assert_msg_(!GPURecord::IsActivePending(), "Cannot run replay while recording."); diff --git a/GPU/Debugger/Playback.h b/GPU/Debugger/Playback.h index 66d70fefa7..fe0af7c636 100644 --- a/GPU/Debugger/Playback.h +++ b/GPU/Debugger/Playback.h @@ -17,6 +17,7 @@ #pragma once +#include #include namespace GPURecord { @@ -27,6 +28,7 @@ enum class ReplayResult { Break = 2, }; +void WriteRunDumpCode(u32 addr); ReplayResult RunMountedReplay(const std::string &filename); -}; +} // namespace GPURecord diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index d96eb8726f..e8d809c0da 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1554,7 +1554,7 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) { // Hopefully, after running, coreState is now CORE_NEXTFRAME switch (coreState) { case CORE_NEXTFRAME: - // Reached the end of the frame, all good. Set back to running for the next frame + // Reached the end of the frame while running at full blast, all good. Set back to running for the next frame coreState = CORE_RUNNING_CPU; flags |= ScreenRenderFlags::HANDLED_THROTTLING; break;