DSPLLE: More accurately handle initialization behavior

This commit is contained in:
Pokechu22 2022-06-07 21:49:09 -07:00
parent c38c2b1aaa
commit 072913bbad
6 changed files with 44 additions and 32 deletions

View file

@ -379,6 +379,7 @@ void SDSP::DoState(PointerWrap& p)
p.Do(r); p.Do(r);
p.Do(pc); p.Do(pc);
p.Do(control_reg); p.Do(control_reg);
p.Do(control_reg_init_code_clear_time);
p.Do(reg_stack_ptrs); p.Do(reg_stack_ptrs);
p.Do(exceptions); p.Do(exceptions);
p.Do(external_interrupt_waiting); p.Do(external_interrupt_waiting);

View file

@ -424,6 +424,7 @@ struct SDSP
// The engine has control over 0x0C07 of this reg. // The engine has control over 0x0C07 of this reg.
// Bits are defined in a struct in DSP.cpp. // Bits are defined in a struct in DSP.cpp.
u16 control_reg = 0; u16 control_reg = 0;
u64 control_reg_init_code_clear_time = 0;
u8 reg_stack_ptrs[4]{}; u8 reg_stack_ptrs[4]{};
u8 exceptions = 0; // pending exceptions u8 exceptions = 0; // pending exceptions
@ -577,9 +578,6 @@ public:
Interpreter::Interpreter& GetInterpreter() { return *m_dsp_interpreter; } Interpreter::Interpreter& GetInterpreter() { return *m_dsp_interpreter; }
const Interpreter::Interpreter& GetInterpreter() const { 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: private:
SDSP m_dsp; SDSP m_dsp;
DSPBreakpoints m_dsp_breakpoints; DSPBreakpoints m_dsp_breakpoints;

View file

@ -39,13 +39,6 @@ u16 SDSP::ReadMailboxLow(Mailbox mailbox)
const u32 value = GetMailbox(mailbox).load(std::memory_order_acquire); const u32 value = GetMailbox(mailbox).load(std::memory_order_acquire);
GetMailbox(mailbox).store(value & ~0x80000000, std::memory_order_release); 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) #if defined(_DEBUG) || defined(DEBUGFAST)
const char* const type = mailbox == Mailbox::DSP ? "DSP" : "CPU"; const char* const type = mailbox == Mailbox::DSP ? "DSP" : "CPU";
DEBUG_LOG_FMT(DSP_MAIL, "{}(RM) B:{} M:{:#010x} (pc={:#06x})", type, static_cast<int>(mailbox), DEBUG_LOG_FMT(DSP_MAIL, "{}(RM) B:{} M:{:#010x} (pc={:#06x})", type, static_cast<int>(mailbox),
@ -57,11 +50,6 @@ u16 SDSP::ReadMailboxLow(Mailbox mailbox)
u16 SDSP::ReadMailboxHigh(Mailbox mailbox) u16 SDSP::ReadMailboxHigh(Mailbox mailbox)
{ {
if (m_dsp_core.GetInitHax() && mailbox == Mailbox::DSP)
{
return 0x8054;
}
// TODO: mask away the top bit? // TODO: mask away the top bit?
return static_cast<u16>(PeekMailbox(mailbox) >> 16); return static_cast<u16>(PeekMailbox(mailbox) >> 16);
} }

View file

@ -7,12 +7,17 @@
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/MemoryUtil.h"
#include "Core/CoreTiming.h"
#include "Core/DSP/DSPAnalyzer.h" #include "Core/DSP/DSPAnalyzer.h"
#include "Core/DSP/DSPCore.h" #include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPHost.h"
#include "Core/DSP/DSPTables.h" #include "Core/DSP/DSPTables.h"
#include "Core/DSP/Interpreter/DSPIntCCUtil.h" #include "Core/DSP/Interpreter/DSPIntCCUtil.h"
#include "Core/DSP/Interpreter/DSPIntTables.h" #include "Core/DSP/Interpreter/DSPIntTables.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/SystemTimers.h"
namespace DSP::Interpreter namespace DSP::Interpreter
{ {
@ -214,6 +219,17 @@ int Interpreter::RunCycles(int cycles)
// NOTE: These have nothing to do with SDSP::r::cr! // NOTE: These have nothing to do with SDSP::r::cr!
void Interpreter::WriteControlRegister(u16 val) 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 // reset
if ((val & CR_RESET) != 0) if ((val & CR_RESET) != 0)
{ {
@ -221,33 +237,42 @@ void Interpreter::WriteControlRegister(u16 val)
m_dsp_core.Reset(); m_dsp_core.Reset();
val &= ~CR_RESET; val &= ~CR_RESET;
} }
// init // init - unclear if writing CR_INIT_CODE does something. Clearing CR_INIT immediately sets
else if (val == CR_HALT) // 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"); INFO_LOG_FMT(DSPLLE, "DSP_CONTROL INIT");
m_dsp_core.SetInitHax(true); // Copy 1024(?) bytes of uCode from main memory 0x81000000 (or is it ARAM 00000000?)
val |= CR_INIT; // 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 // update cr
m_dsp_core.DSPState().control_reg = val; state.control_reg = val;
} }
u16 Interpreter::ReadControlRegister() u16 Interpreter::ReadControlRegister()
{ {
auto& state = m_dsp_core.DSPState(); auto& state = m_dsp_core.DSPState();
if ((state.control_reg & CR_INIT_CODE) != 0)
if ((state.pc & 0x8000) != 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; return state.control_reg;
} }

View file

@ -330,6 +330,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
s_dspState.DSPReset = tmpControl.DSPReset; s_dspState.DSPReset = tmpControl.DSPReset;
s_dspState.DSPAssertInt = tmpControl.DSPAssertInt; s_dspState.DSPAssertInt = tmpControl.DSPAssertInt;
s_dspState.DSPHalt = tmpControl.DSPHalt; s_dspState.DSPHalt = tmpControl.DSPHalt;
s_dspState.DSPInitCode = tmpControl.DSPInitCode;
s_dspState.DSPInit = tmpControl.DSPInit; s_dspState.DSPInit = tmpControl.DSPInit;
// Interrupt (mask) // Interrupt (mask)
@ -346,7 +347,6 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
s_dspState.DSP = 0; s_dspState.DSP = 0;
// unknown // unknown
s_dspState.DSPInitCode = tmpControl.DSPInitCode;
s_dspState.pad = tmpControl.pad; s_dspState.pad = tmpControl.pad;
if (s_dspState.pad != 0) if (s_dspState.pad != 0)
{ {

View file

@ -74,7 +74,7 @@ static std::recursive_mutex g_save_thread_mutex;
static std::thread g_save_thread; static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system // 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. // Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list, // Versions after 42 don't need to be added to this list,