Merge pull request #10732 from Pokechu22/dsp-init
Increase accuracy of DSP initialization process
This commit is contained in:
commit
c8e716234e
|
@ -161,7 +161,7 @@ bool SDSP::Initialize(const DSPInitOptions& opts)
|
||||||
r.sr |= SR_INT_ENABLE;
|
r.sr |= SR_INT_ENABLE;
|
||||||
r.sr |= SR_EXT_INT_ENABLE;
|
r.sr |= SR_EXT_INT_ENABLE;
|
||||||
|
|
||||||
cr = CR_INIT | CR_HALT;
|
control_reg = CR_INIT | CR_HALT;
|
||||||
InitializeIFX();
|
InitializeIFX();
|
||||||
// Mostly keep IRAM write protected. We unprotect only when DMA-ing
|
// Mostly keep IRAM write protected. We unprotect only when DMA-ing
|
||||||
// in new ucodes.
|
// in new ucodes.
|
||||||
|
@ -210,7 +210,7 @@ void SDSP::CheckExternalInterrupt()
|
||||||
// Signal the SPU about new mail
|
// Signal the SPU about new mail
|
||||||
SetException(ExceptionType::ExternalInterrupt);
|
SetException(ExceptionType::ExternalInterrupt);
|
||||||
|
|
||||||
cr &= ~CR_EXTERNAL_INT;
|
control_reg &= ~CR_EXTERNAL_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDSP::CheckExceptions()
|
void SDSP::CheckExceptions()
|
||||||
|
@ -378,7 +378,8 @@ void SDSP::DoState(PointerWrap& p)
|
||||||
{
|
{
|
||||||
p.Do(r);
|
p.Do(r);
|
||||||
p.Do(pc);
|
p.Do(pc);
|
||||||
p.Do(cr);
|
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);
|
||||||
|
|
|
@ -419,11 +419,12 @@ struct SDSP
|
||||||
DSP_Regs r{};
|
DSP_Regs r{};
|
||||||
u16 pc = 0;
|
u16 pc = 0;
|
||||||
|
|
||||||
// This is NOT the same cr as r.cr.
|
// This is NOT the same as r.cr.
|
||||||
// This register is shared with the main emulation, see DSP.cpp
|
// This register is shared with the main emulation, see DSP.cpp
|
||||||
// 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 cr = 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;
|
||||||
|
|
|
@ -39,16 +39,9 @@ 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:0x{:#010x} (pc={:#06x})", type, static_cast<int>(mailbox),
|
DEBUG_LOG_FMT(DSP_MAIL, "{}(RM) B:{} M:{:#010x} (pc={:#06x})", type, static_cast<int>(mailbox),
|
||||||
PeekMailbox(mailbox), pc);
|
PeekMailbox(mailbox), pc);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@ void Interpreter::rti(const UDSPInstruction opc)
|
||||||
void Interpreter::halt(const UDSPInstruction)
|
void Interpreter::halt(const UDSPInstruction)
|
||||||
{
|
{
|
||||||
auto& state = m_dsp_core.DSPState();
|
auto& state = m_dsp_core.DSPState();
|
||||||
state.cr |= CR_HALT;
|
state.control_reg |= CR_HALT;
|
||||||
state.pc--;
|
state.pc--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -81,7 +86,7 @@ int Interpreter::RunCyclesThread(int cycles)
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if ((state.cr & CR_HALT) != 0)
|
if ((state.control_reg & CR_HALT) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (state.external_interrupt_waiting.exchange(false, std::memory_order_acquire))
|
if (state.external_interrupt_waiting.exchange(false, std::memory_order_acquire))
|
||||||
|
@ -104,7 +109,7 @@ int Interpreter::RunCyclesDebug(int cycles)
|
||||||
// First, let's run a few cycles with no idle skipping so that things can progress a bit.
|
// First, let's run a few cycles with no idle skipping so that things can progress a bit.
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
if ((state.cr & CR_HALT) != 0)
|
if ((state.control_reg & CR_HALT) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (m_dsp_core.BreakPoints().IsAddressBreakPoint(state.pc))
|
if (m_dsp_core.BreakPoints().IsAddressBreakPoint(state.pc))
|
||||||
|
@ -124,7 +129,7 @@ int Interpreter::RunCyclesDebug(int cycles)
|
||||||
// idle loops.
|
// idle loops.
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
if ((state.cr & CR_HALT) != 0)
|
if ((state.control_reg & CR_HALT) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (m_dsp_core.BreakPoints().IsAddressBreakPoint(state.pc))
|
if (m_dsp_core.BreakPoints().IsAddressBreakPoint(state.pc))
|
||||||
|
@ -169,7 +174,7 @@ int Interpreter::RunCycles(int cycles)
|
||||||
// progress a bit.
|
// progress a bit.
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
if ((state.cr & CR_HALT) != 0)
|
if ((state.control_reg & CR_HALT) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Step();
|
Step();
|
||||||
|
@ -185,7 +190,7 @@ int Interpreter::RunCycles(int cycles)
|
||||||
// idle loops.
|
// idle loops.
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
if ((state.cr & CR_HALT) != 0)
|
if ((state.control_reg & CR_HALT) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (state.GetAnalyzer().IsIdleSkip(state.pc))
|
if (state.GetAnalyzer().IsIdleSkip(state.pc))
|
||||||
|
@ -212,8 +217,19 @@ 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::WriteCR(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,34 +237,43 @@ void Interpreter::WriteCR(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().cr = val;
|
state.control_reg = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 Interpreter::ReadCR()
|
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.cr |= CR_INIT;
|
if (SystemTimers::GetFakeTimeBase() >= state.control_reg_init_code_clear_time)
|
||||||
}
|
state.control_reg &= ~CR_INIT_CODE;
|
||||||
else
|
else
|
||||||
{
|
CoreTiming::ForceExceptionCheck(50); // Keep checking
|
||||||
state.cr &= ~CR_INIT;
|
|
||||||
}
|
}
|
||||||
|
return state.control_reg;
|
||||||
return state.cr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::SetSRFlag(u16 flag)
|
void Interpreter::SetSRFlag(u16 flag)
|
||||||
|
|
|
@ -32,8 +32,8 @@ public:
|
||||||
int RunCycles(int cycles);
|
int RunCycles(int cycles);
|
||||||
int RunCyclesDebug(int cycles);
|
int RunCyclesDebug(int cycles);
|
||||||
|
|
||||||
void WriteCR(u16 val);
|
void WriteControlRegister(u16 val);
|
||||||
u16 ReadCR();
|
u16 ReadControlRegister();
|
||||||
|
|
||||||
void SetSRFlag(u16 flag);
|
void SetSRFlag(u16 flag);
|
||||||
bool IsSRFlagSet(u16 flag) const;
|
bool IsSRFlagSet(u16 flag) const;
|
||||||
|
|
|
@ -443,7 +443,7 @@ void DSPEmitter::CompileDispatcher()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for DSP halt
|
// Check for DSP halt
|
||||||
TEST(8, M_SDSP_cr(), Imm8(CR_HALT));
|
TEST(8, M_SDSP_control_reg(), Imm8(CR_HALT));
|
||||||
FixupBranch _halt = J_CC(CC_NE);
|
FixupBranch _halt = J_CC(CC_NE);
|
||||||
|
|
||||||
// Execute block. Cycles executed returned in EAX.
|
// Execute block. Cycles executed returned in EAX.
|
||||||
|
@ -484,9 +484,9 @@ Gen::OpArg DSPEmitter::M_SDSP_exceptions()
|
||||||
return MDisp(R15, static_cast<int>(offsetof(SDSP, exceptions)));
|
return MDisp(R15, static_cast<int>(offsetof(SDSP, exceptions)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Gen::OpArg DSPEmitter::M_SDSP_cr()
|
Gen::OpArg DSPEmitter::M_SDSP_control_reg()
|
||||||
{
|
{
|
||||||
return MDisp(R15, static_cast<int>(offsetof(SDSP, cr)));
|
return MDisp(R15, static_cast<int>(offsetof(SDSP, control_reg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Gen::OpArg DSPEmitter::M_SDSP_external_interrupt_waiting()
|
Gen::OpArg DSPEmitter::M_SDSP_external_interrupt_waiting()
|
||||||
|
|
|
@ -292,7 +292,7 @@ private:
|
||||||
// SDSP memory offset helpers
|
// SDSP memory offset helpers
|
||||||
Gen::OpArg M_SDSP_pc();
|
Gen::OpArg M_SDSP_pc();
|
||||||
Gen::OpArg M_SDSP_exceptions();
|
Gen::OpArg M_SDSP_exceptions();
|
||||||
Gen::OpArg M_SDSP_cr();
|
Gen::OpArg M_SDSP_control_reg();
|
||||||
Gen::OpArg M_SDSP_external_interrupt_waiting();
|
Gen::OpArg M_SDSP_external_interrupt_waiting();
|
||||||
Gen::OpArg M_SDSP_r_st(size_t index);
|
Gen::OpArg M_SDSP_r_st(size_t index);
|
||||||
Gen::OpArg M_SDSP_reg_stack_ptrs(size_t index);
|
Gen::OpArg M_SDSP_reg_stack_ptrs(size_t index);
|
||||||
|
|
|
@ -304,7 +304,7 @@ void DSPEmitter::rti(const UDSPInstruction opc)
|
||||||
// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR.
|
// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR.
|
||||||
void DSPEmitter::halt(const UDSPInstruction)
|
void DSPEmitter::halt(const UDSPInstruction)
|
||||||
{
|
{
|
||||||
OR(16, M_SDSP_cr(), Imm16(CR_HALT));
|
OR(16, M_SDSP_control_reg(), Imm16(CR_HALT));
|
||||||
// g_dsp.pc = dsp_reg_load_stack(StackRegister::Call);
|
// g_dsp.pc = dsp_reg_load_stack(StackRegister::Call);
|
||||||
dsp_reg_load_stack(StackRegister::Call);
|
dsp_reg_load_stack(StackRegister::Call);
|
||||||
MOV(16, M_SDSP_pc(), R(DX));
|
MOV(16, M_SDSP_pc(), R(DX));
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
|
#include "Core/CoreTiming.h"
|
||||||
#include "Core/HW/DSPHLE/UCodes/UCodes.h"
|
#include "Core/HW/DSPHLE/UCodes/UCodes.h"
|
||||||
#include "Core/HW/SystemTimers.h"
|
#include "Core/HW/SystemTimers.h"
|
||||||
|
|
||||||
|
@ -104,6 +105,7 @@ void DSPHLE::DoState(PointerWrap& p)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.DoPOD(m_dsp_control);
|
p.DoPOD(m_dsp_control);
|
||||||
|
p.Do(m_control_reg_init_code_clear_time);
|
||||||
p.DoPOD(m_dsp_state);
|
p.DoPOD(m_dsp_state);
|
||||||
|
|
||||||
int ucode_crc = UCodeInterface::GetCRC(m_ucode.get());
|
int ucode_crc = UCodeInterface::GetCRC(m_ucode.get());
|
||||||
|
@ -190,16 +192,33 @@ u16 DSPHLE::DSP_WriteControlRegister(u16 value)
|
||||||
{
|
{
|
||||||
DSP::UDSPControl temp(value);
|
DSP::UDSPControl temp(value);
|
||||||
|
|
||||||
|
if (m_dsp_control.DSPHalt != temp.DSPHalt)
|
||||||
|
{
|
||||||
|
INFO_LOG_FMT(DSPHLE, "DSP_CONTROL halt bit changed: {:04x} -> {:04x}", m_dsp_control.Hex,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
if (temp.DSPReset)
|
if (temp.DSPReset)
|
||||||
{
|
{
|
||||||
SetUCode(UCODE_ROM);
|
SetUCode(UCODE_ROM);
|
||||||
temp.DSPReset = 0;
|
temp.DSPReset = 0;
|
||||||
}
|
}
|
||||||
if (temp.DSPInit == 0)
|
|
||||||
|
// init - unclear if writing DSPInitCode does something. Clearing DSPInit immediately sets
|
||||||
|
// DSPInitCode, which gets unset a bit later...
|
||||||
|
if ((m_dsp_control.DSPInit != 0) && (temp.DSPInit == 0))
|
||||||
{
|
{
|
||||||
// copy 128 byte from ARAM 0x000000 to IMEM
|
// 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
|
||||||
|
// We could hash the input data, but this is only used for initialization purposes on licensed
|
||||||
|
// games and by devkitpro, so there's no real point in doing so.
|
||||||
|
// Datel has similar logic to retail games, but they clear bit 0x80 (DSP) instead of bit 0x800
|
||||||
|
// (DSPInit) so they end up not using the init uCode.
|
||||||
SetUCode(UCODE_INIT_AUDIO_SYSTEM);
|
SetUCode(UCODE_INIT_AUDIO_SYSTEM);
|
||||||
temp.DSPInitCode = 0;
|
temp.DSPInitCode = 1;
|
||||||
|
// Number obtained from real hardware on a Wii, but it's not perfectly consistent
|
||||||
|
m_control_reg_init_code_clear_time = SystemTimers::GetFakeTimeBase() + 130;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_dsp_control.Hex = temp.Hex;
|
m_dsp_control.Hex = temp.Hex;
|
||||||
|
@ -208,6 +227,13 @@ u16 DSPHLE::DSP_WriteControlRegister(u16 value)
|
||||||
|
|
||||||
u16 DSPHLE::DSP_ReadControlRegister()
|
u16 DSPHLE::DSP_ReadControlRegister()
|
||||||
{
|
{
|
||||||
|
if (m_dsp_control.DSPInitCode != 0)
|
||||||
|
{
|
||||||
|
if (SystemTimers::GetFakeTimeBase() >= m_control_reg_init_code_clear_time)
|
||||||
|
m_dsp_control.DSPInitCode = 0;
|
||||||
|
else
|
||||||
|
CoreTiming::ForceExceptionCheck(50); // Keep checking
|
||||||
|
}
|
||||||
return m_dsp_control.Hex;
|
return m_dsp_control.Hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,7 @@ private:
|
||||||
std::unique_ptr<UCodeInterface> m_last_ucode;
|
std::unique_ptr<UCodeInterface> m_last_ucode;
|
||||||
|
|
||||||
DSP::UDSPControl m_dsp_control;
|
DSP::UDSPControl m_dsp_control;
|
||||||
|
u64 m_control_reg_init_code_clear_time = 0;
|
||||||
CMailHandler m_mail_handler;
|
CMailHandler m_mail_handler;
|
||||||
};
|
};
|
||||||
} // namespace DSP::HLE
|
} // namespace DSP::HLE
|
||||||
|
|
|
@ -183,7 +183,7 @@ void DSPLLE::Shutdown()
|
||||||
|
|
||||||
u16 DSPLLE::DSP_WriteControlRegister(u16 value)
|
u16 DSPLLE::DSP_WriteControlRegister(u16 value)
|
||||||
{
|
{
|
||||||
m_dsp_core.GetInterpreter().WriteCR(value);
|
m_dsp_core.GetInterpreter().WriteControlRegister(value);
|
||||||
|
|
||||||
if ((value & CR_EXTERNAL_INT) != 0)
|
if ((value & CR_EXTERNAL_INT) != 0)
|
||||||
{
|
{
|
||||||
|
@ -207,7 +207,7 @@ u16 DSPLLE::DSP_WriteControlRegister(u16 value)
|
||||||
|
|
||||||
u16 DSPLLE::DSP_ReadControlRegister()
|
u16 DSPLLE::DSP_ReadControlRegister()
|
||||||
{
|
{
|
||||||
return m_dsp_core.GetInterpreter().ReadCR();
|
return m_dsp_core.GetInterpreter().ReadControlRegister();
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 DSPLLE::DSP_ReadMailBoxHigh(bool cpu_mailbox)
|
u16 DSPLLE::DSP_ReadMailBoxHigh(bool cpu_mailbox)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue