DSPHLE: More accurately handle initialization behavior

This improves timing, but does not fix Datel titles.
This commit is contained in:
Pokechu22 2022-06-08 14:02:14 -07:00
parent 072913bbad
commit 053b3e725b
2 changed files with 30 additions and 3 deletions

View File

@ -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;
} }

View File

@ -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