From 072913bbade6c9ec841c1b349d6d719f0832a16a Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 7 Jun 2022 21:49:09 -0700 Subject: [PATCH] DSPLLE: More accurately handle initialization behavior --- Source/Core/Core/DSP/DSPCore.cpp | 1 + Source/Core/Core/DSP/DSPCore.h | 4 +- Source/Core/Core/DSP/DSPHWInterface.cpp | 12 ---- .../Core/DSP/Interpreter/DSPInterpreter.cpp | 55 ++++++++++++++----- Source/Core/Core/HW/DSP.cpp | 2 +- Source/Core/Core/State.cpp | 2 +- 6 files changed, 44 insertions(+), 32 deletions(-) diff --git a/Source/Core/Core/DSP/DSPCore.cpp b/Source/Core/Core/DSP/DSPCore.cpp index 9d30ea0812..dadc8effa6 100644 --- a/Source/Core/Core/DSP/DSPCore.cpp +++ b/Source/Core/Core/DSP/DSPCore.cpp @@ -379,6 +379,7 @@ void SDSP::DoState(PointerWrap& p) p.Do(r); p.Do(pc); p.Do(control_reg); + p.Do(control_reg_init_code_clear_time); p.Do(reg_stack_ptrs); p.Do(exceptions); p.Do(external_interrupt_waiting); diff --git a/Source/Core/Core/DSP/DSPCore.h b/Source/Core/Core/DSP/DSPCore.h index ac105922c3..a12f49270d 100644 --- a/Source/Core/Core/DSP/DSPCore.h +++ b/Source/Core/Core/DSP/DSPCore.h @@ -424,6 +424,7 @@ struct SDSP // The engine has control over 0x0C07 of this reg. // Bits are defined in a struct in DSP.cpp. u16 control_reg = 0; + u64 control_reg_init_code_clear_time = 0; u8 reg_stack_ptrs[4]{}; u8 exceptions = 0; // pending exceptions @@ -577,9 +578,6 @@ public: Interpreter::Interpreter& GetInterpreter() { return *m_dsp_interpreter; } const Interpreter::Interpreter& GetInterpreter() const { return *m_dsp_interpreter; } - bool GetInitHax() const { return m_init_hax; } - void SetInitHax(bool value) { m_init_hax = value; } - private: SDSP m_dsp; DSPBreakpoints m_dsp_breakpoints; diff --git a/Source/Core/Core/DSP/DSPHWInterface.cpp b/Source/Core/Core/DSP/DSPHWInterface.cpp index c2b0a50a28..736055b2ca 100644 --- a/Source/Core/Core/DSP/DSPHWInterface.cpp +++ b/Source/Core/Core/DSP/DSPHWInterface.cpp @@ -39,13 +39,6 @@ u16 SDSP::ReadMailboxLow(Mailbox mailbox) const u32 value = GetMailbox(mailbox).load(std::memory_order_acquire); GetMailbox(mailbox).store(value & ~0x80000000, std::memory_order_release); - if (m_dsp_core.GetInitHax() && mailbox == Mailbox::DSP) - { - m_dsp_core.SetInitHax(false); - m_dsp_core.Reset(); - return 0x4348; - } - #if defined(_DEBUG) || defined(DEBUGFAST) const char* const type = mailbox == Mailbox::DSP ? "DSP" : "CPU"; DEBUG_LOG_FMT(DSP_MAIL, "{}(RM) B:{} M:{:#010x} (pc={:#06x})", type, static_cast(mailbox), @@ -57,11 +50,6 @@ u16 SDSP::ReadMailboxLow(Mailbox mailbox) u16 SDSP::ReadMailboxHigh(Mailbox mailbox) { - if (m_dsp_core.GetInitHax() && mailbox == Mailbox::DSP) - { - return 0x8054; - } - // TODO: mask away the top bit? return static_cast(PeekMailbox(mailbox) >> 16); } diff --git a/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp b/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp index b8478eb87a..dfc351a18a 100644 --- a/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp +++ b/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp @@ -7,12 +7,17 @@ #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" +#include "Common/MemoryUtil.h" +#include "Core/CoreTiming.h" #include "Core/DSP/DSPAnalyzer.h" #include "Core/DSP/DSPCore.h" +#include "Core/DSP/DSPHost.h" #include "Core/DSP/DSPTables.h" #include "Core/DSP/Interpreter/DSPIntCCUtil.h" #include "Core/DSP/Interpreter/DSPIntTables.h" +#include "Core/HW/Memmap.h" +#include "Core/HW/SystemTimers.h" namespace DSP::Interpreter { @@ -214,6 +219,17 @@ int Interpreter::RunCycles(int cycles) // NOTE: These have nothing to do with SDSP::r::cr! void Interpreter::WriteControlRegister(u16 val) { + auto& state = m_dsp_core.DSPState(); + + if ((state.control_reg & CR_HALT) != (val & CR_HALT)) + { + // This bit is handled by Interpreter::RunCycles and DSPEmitter::CompileDispatcher + INFO_LOG_FMT(DSPLLE, "DSP_CONTROL halt bit changed: {:04x} -> {:04x}, PC {:04x}", + state.control_reg, val, state.pc); + } + + // The CR_EXTERNAL_INT bit is handled by DSPLLE::DSP_WriteControlRegister + // reset if ((val & CR_RESET) != 0) { @@ -221,33 +237,42 @@ void Interpreter::WriteControlRegister(u16 val) m_dsp_core.Reset(); val &= ~CR_RESET; } - // init - else if (val == CR_HALT) + // init - unclear if writing CR_INIT_CODE does something. Clearing CR_INIT immediately sets + // CR_INIT_CODE, which gets unset a bit later... + if (((state.control_reg & CR_INIT) != 0) && ((val & CR_INIT) == 0)) { - // HAX! - // OSInitAudioSystem ucode should send this mail - not DSP core itself INFO_LOG_FMT(DSPLLE, "DSP_CONTROL INIT"); - m_dsp_core.SetInitHax(true); - val |= CR_INIT; + // Copy 1024(?) bytes of uCode from main memory 0x81000000 (or is it ARAM 00000000?) + // to IMEM 0000 and jump to that code + // TODO: Determine exactly how this initialization works + state.pc = 0; + + Common::UnWriteProtectMemory(state.iram, DSP_IRAM_BYTE_SIZE, false); + Host::DMAToDSP(state.iram, 0x81000000, 0x1000); + Common::WriteProtectMemory(state.iram, DSP_IRAM_BYTE_SIZE, false); + + Host::CodeLoaded(m_dsp_core, 0x81000000, 0x1000); + + val &= ~CR_INIT; + val |= CR_INIT_CODE; + // Number obtained from real hardware on a Wii, but it's not perfectly consistent + state.control_reg_init_code_clear_time = SystemTimers::GetFakeTimeBase() + 130; } // update cr - m_dsp_core.DSPState().control_reg = val; + state.control_reg = val; } u16 Interpreter::ReadControlRegister() { auto& state = m_dsp_core.DSPState(); - - if ((state.pc & 0x8000) != 0) + if ((state.control_reg & CR_INIT_CODE) != 0) { - state.control_reg |= CR_INIT; + if (SystemTimers::GetFakeTimeBase() >= state.control_reg_init_code_clear_time) + state.control_reg &= ~CR_INIT_CODE; + else + CoreTiming::ForceExceptionCheck(50); // Keep checking } - else - { - state.control_reg &= ~CR_INIT; - } - return state.control_reg; } diff --git a/Source/Core/Core/HW/DSP.cpp b/Source/Core/Core/HW/DSP.cpp index 5edc5314a5..1858aa5ce2 100644 --- a/Source/Core/Core/HW/DSP.cpp +++ b/Source/Core/Core/HW/DSP.cpp @@ -330,6 +330,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) s_dspState.DSPReset = tmpControl.DSPReset; s_dspState.DSPAssertInt = tmpControl.DSPAssertInt; s_dspState.DSPHalt = tmpControl.DSPHalt; + s_dspState.DSPInitCode = tmpControl.DSPInitCode; s_dspState.DSPInit = tmpControl.DSPInit; // Interrupt (mask) @@ -346,7 +347,6 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) s_dspState.DSP = 0; // unknown - s_dspState.DSPInitCode = tmpControl.DSPInitCode; s_dspState.pad = tmpControl.pad; if (s_dspState.pad != 0) { diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 9387adf72c..76349ba4d2 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -74,7 +74,7 @@ static std::recursive_mutex g_save_thread_mutex; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -constexpr u32 STATE_VERSION = 141; // Last changed in PR 8067 +constexpr u32 STATE_VERSION = 142; // Last changed in PR 10732 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list,