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/MsgHandler.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/HW/DSPHLE/UCodes/UCodes.h"
#include "Core/HW/SystemTimers.h"
@ -104,6 +105,7 @@ void DSPHLE::DoState(PointerWrap& p)
}
p.DoPOD(m_dsp_control);
p.Do(m_control_reg_init_code_clear_time);
p.DoPOD(m_dsp_state);
int ucode_crc = UCodeInterface::GetCRC(m_ucode.get());
@ -190,16 +192,33 @@ u16 DSPHLE::DSP_WriteControlRegister(u16 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)
{
SetUCode(UCODE_ROM);
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);
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;
@ -208,6 +227,13 @@ u16 DSPHLE::DSP_WriteControlRegister(u16 value)
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;
}

View File

@ -65,6 +65,7 @@ private:
std::unique_ptr<UCodeInterface> m_last_ucode;
DSP::UDSPControl m_dsp_control;
u64 m_control_reg_init_code_clear_time = 0;
CMailHandler m_mail_handler;
};
} // namespace DSP::HLE