From 6f25e20c6a0c5b4027fffe2bea0116728018e7df Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Sat, 16 Nov 2024 16:08:54 +0000 Subject: [PATCH] VideoCommon: reset some CP registers during PI_FIFO_RESET This fixes the shutdown error in SpongeBob Globs of Doom. --- Source/Core/Core/HW/MMIO.cpp | 2 +- Source/Core/Core/HW/ProcessorInterface.cpp | 7 ++--- Source/Core/Core/State.cpp | 2 +- Source/Core/VideoCommon/CommandProcessor.cpp | 28 +++++++++++++++++--- Source/Core/VideoCommon/CommandProcessor.h | 7 ++++- 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/Source/Core/Core/HW/MMIO.cpp b/Source/Core/Core/HW/MMIO.cpp index fad1105532..af50aae0a0 100644 --- a/Source/Core/Core/HW/MMIO.cpp +++ b/Source/Core/Core/HW/MMIO.cpp @@ -175,7 +175,7 @@ ReadHandlingMethod* InvalidRead() return ComplexRead([](Core::System&, u32 addr) { ERROR_LOG_FMT(MEMMAP, "Trying to read {} bits from an invalid MMIO (addr={:08x})", 8 * sizeof(T), addr); - return -1; + return 0; }); } template diff --git a/Source/Core/Core/HW/ProcessorInterface.cpp b/Source/Core/Core/HW/ProcessorInterface.cpp index 72c8cb87b2..d805d2fa0e 100644 --- a/Source/Core/Core/HW/ProcessorInterface.cpp +++ b/Source/Core/Core/HW/ProcessorInterface.cpp @@ -20,6 +20,7 @@ #include "Core/PowerPC/PowerPC.h" #include "Core/System.h" #include "VideoCommon/AsyncRequests.h" +#include "VideoCommon/CommandProcessor.h" #include "VideoCommon/Fifo.h" namespace ProcessorInterface @@ -96,11 +97,11 @@ void ProcessorInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base) INFO_LOG_FMT(PROCESSORINTERFACE, "Wrote PI_FIFO_RESET: {:08x}", val); if ((val & 1) != 0) { + // TODO: Is this still necessary now that we reset the CP registers? system.GetGPFifo().ResetGatherPipe(); - // Assume that all bytes that made it into the GPU fifo did in fact execute - // before this MMIO write takes effect. - system.GetFifo().SyncGPUForRegisterAccess(); + // Reset some CP registers. This may trigger an ad-hoc GPU time slice. + system.GetCommandProcessor().ResetFifo(); // Call Fifo::ResetVideoBuffer() from the video thread. Since that function // resets various pointers used by the video thread, we can't call it directly diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 052a3ed1ff..556aff170a 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -95,7 +95,7 @@ static size_t s_state_writes_in_queue; static std::condition_variable s_state_write_queue_is_empty; // Don't forget to increase this after doing changes on the savestate system -constexpr u32 STATE_VERSION = 173; // Last changed in PR 10084 +constexpr u32 STATE_VERSION = 174; // Last changed in PR 13342 // Increase this if the StateExtendedHeader definition changes constexpr u32 EXTENDED_HEADER_VERSION = 1; // Last changed in PR 12217 diff --git a/Source/Core/VideoCommon/CommandProcessor.cpp b/Source/Core/VideoCommon/CommandProcessor.cpp index 3a771e1f2a..8342bfb6fb 100644 --- a/Source/Core/VideoCommon/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/CommandProcessor.cpp @@ -87,6 +87,8 @@ void CommandProcessorManager::DoState(PointerWrap& p) p.Do(m_cp_status_reg); p.Do(m_cp_ctrl_reg); p.Do(m_cp_clear_reg); + p.Do(m_perf_select); + p.Do(m_unk_0a_reg); m_fifo.DoState(p); p.Do(m_interrupt_set); @@ -200,13 +202,13 @@ void CommandProcessorManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base) mmio->Register(base | CTRL_REGISTER, MMIO::DirectRead(&m_cp_ctrl_reg.Hex), MMIO::ComplexWrite([](Core::System& system_, u32, u16 val) { auto& cp = system_.GetCommandProcessor(); - UCPCtrlReg tmp(val); + UCPCtrlReg tmp(val & 0x3F); cp.m_cp_ctrl_reg.Hex = tmp.Hex; cp.SetCpControlRegister(); system_.GetFifo().RunGpu(); })); - mmio->Register(base | CLEAR_REGISTER, MMIO::DirectRead(&m_cp_clear_reg.Hex), + mmio->Register(base | CLEAR_REGISTER, MMIO::Constant(0), MMIO::ComplexWrite([](Core::System& system_, u32, u16 val) { auto& cp = system_.GetCommandProcessor(); UCPClearReg tmp(val); @@ -215,7 +217,14 @@ void CommandProcessorManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base) system_.GetFifo().RunGpu(); })); - mmio->Register(base | PERF_SELECT, MMIO::InvalidRead(), MMIO::Nop()); + // TODO: Figure out how this works. Written by GXSetGPMetric. Nicktoons MLB has DWARF v2 with enum + // names. + mmio->Register(base | PERF_SELECT, MMIO::DirectRead(&m_perf_select), + MMIO::DirectWrite(&m_perf_select, 0x0007)); + + // TODO: Figure out what this is. + mmio->Register(base | UNK_0A_REGISTER, MMIO::DirectRead(&m_unk_0a_reg), + MMIO::DirectWrite(&m_unk_0a_reg, 0x00FF)); // Some MMIOs have different handlers for single core vs. dual core mode. const bool is_on_thread = IsOnThread(m_system); @@ -565,6 +574,7 @@ void CommandProcessorManager::SetCpStatusRegister() void CommandProcessorManager::SetCpControlRegister() { + // Just before disabling reads, give the GPU a chance to catch up. if (m_fifo.bFF_GPReadEnable.load(std::memory_order_relaxed) && !m_cp_ctrl_reg.GPReadEnable) { m_system.GetFifo().SyncGPUForRegisterAccess(); @@ -591,6 +601,18 @@ void CommandProcessorManager::SetCpClearRegister() { } +void CommandProcessorManager::ResetFifo() +{ + // Link fifos, disable interrupts, disable reads. + m_cp_ctrl_reg.Hex = 0x0010; + SetCpControlRegister(); + m_perf_select = 0; + m_unk_0a_reg = 0; + m_fifo.CPLoWatermark = 0; + m_fifo.CPHiWatermark = GetPhysicalAddressMask(m_system.IsWii()) & ~31u; + SetCpStatusRegister(); +} + void CommandProcessorManager::HandleUnknownOpcode(u8 cmd_byte, const u8* buffer, bool preprocess) { // Datel software uses 0x01 during startup, and Mario Party 5's Wiggler capsule accidentally uses diff --git a/Source/Core/VideoCommon/CommandProcessor.h b/Source/Core/VideoCommon/CommandProcessor.h index fcd81a893e..e4bb4cd136 100644 --- a/Source/Core/VideoCommon/CommandProcessor.h +++ b/Source/Core/VideoCommon/CommandProcessor.h @@ -60,6 +60,7 @@ enum CTRL_REGISTER = 0x02, CLEAR_REGISTER = 0x04, PERF_SELECT = 0x06, + UNK_0A_REGISTER = 0x0A, FIFO_BASE_LO = 0x20, FIFO_BASE_HI = 0x22, FIFO_END_LO = 0x24, @@ -142,7 +143,8 @@ union UCPClearReg { u16 ClearFifoOverflow : 1; u16 ClearFifoUnderflow : 1; - u16 ClearMetrices : 1; + // set by GXClearGPMetric + u16 ClearMetrics : 1; u16 : 13; }; u16 Hex; @@ -178,6 +180,7 @@ public: void SetCpClearRegister(); void SetCpControlRegister(); void SetCpStatusRegister(); + void ResetFifo(); void HandleUnknownOpcode(u8 cmd_byte, const u8* buffer, bool preprocess); @@ -194,6 +197,8 @@ private: UCPStatusReg m_cp_status_reg; UCPCtrlReg m_cp_ctrl_reg; UCPClearReg m_cp_clear_reg; + u16 m_perf_select = 0; + u16 m_unk_0a_reg = 0; u16 m_bbox_left = 0; u16 m_bbox_top = 0;