Merge pull request #5440 from ligfx/axhledelayinterrupt
AX-HLE: delay sending interrupt when done processing command list
This commit is contained in:
commit
3a2ec8c8a1
|
@ -3,16 +3,9 @@
|
||||||
[Core]
|
[Core]
|
||||||
# Values set here will override the main Dolphin settings.
|
# Values set here will override the main Dolphin settings.
|
||||||
MMU = 1
|
MMU = 1
|
||||||
# LLE audio enabled by default for a listenable output
|
|
||||||
DSPHLE = False
|
|
||||||
|
|
||||||
[DSP]
|
|
||||||
# Ensure the LLE recompiler gets selected and not interpreter.
|
|
||||||
EnableJIT = True
|
|
||||||
|
|
||||||
[EmuState]
|
[EmuState]
|
||||||
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||||
EmulationIssues = Needs LLE audio for proper sound.
|
|
||||||
EmulationStateId = 4
|
EmulationStateId = 4
|
||||||
|
|
||||||
[OnLoad]
|
[OnLoad]
|
||||||
|
|
|
@ -408,15 +408,14 @@ static void GenerateDSPInterrupt(u64 DSPIntType, s64 cyclesLate)
|
||||||
// DSP_CONTROL - we mask by (INT_DSP | INT_ARAM | INT_AID) just to ensure people
|
// DSP_CONTROL - we mask by (INT_DSP | INT_ARAM | INT_AID) just to ensure people
|
||||||
// don't call this with bogus values.
|
// don't call this with bogus values.
|
||||||
s_dspState.Hex |= (DSPIntType & (INT_DSP | INT_ARAM | INT_AID));
|
s_dspState.Hex |= (DSPIntType & (INT_DSP | INT_ARAM | INT_AID));
|
||||||
|
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
// CALLED FROM DSP EMULATOR, POSSIBLY THREADED
|
// CALLED FROM DSP EMULATOR, POSSIBLY THREADED
|
||||||
void GenerateDSPInterruptFromDSPEmu(DSPInterruptType type)
|
void GenerateDSPInterruptFromDSPEmu(DSPInterruptType type, int cycles_into_future)
|
||||||
{
|
{
|
||||||
// TODO: Maybe rethink this? The timing is unpredictable.
|
CoreTiming::ScheduleEvent(cycles_into_future, s_et_GenerateDSPInterrupt, type,
|
||||||
CoreTiming::ScheduleEvent(0, s_et_GenerateDSPInterrupt, type, CoreTiming::FromThread::ANY);
|
CoreTiming::FromThread::ANY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// called whenever SystemTimers thinks the DSP deserves a few more cycles
|
// called whenever SystemTimers thinks the DSP deserves a few more cycles
|
||||||
|
|
|
@ -69,7 +69,8 @@ DSPEmulator* GetDSPEmulator();
|
||||||
|
|
||||||
void DoState(PointerWrap& p);
|
void DoState(PointerWrap& p);
|
||||||
|
|
||||||
void GenerateDSPInterruptFromDSPEmu(DSPInterruptType type);
|
// TODO: Maybe rethink this? The timing is unpredictable.
|
||||||
|
void GenerateDSPInterruptFromDSPEmu(DSPInterruptType type, int cycles_into_future = 0);
|
||||||
|
|
||||||
// Audio/DSP Helper
|
// Audio/DSP Helper
|
||||||
u8 ReadARAM(u32 address);
|
u8 ReadARAM(u32 address);
|
||||||
|
|
|
@ -22,21 +22,21 @@ CMailHandler::~CMailHandler()
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMailHandler::PushMail(u32 _Mail, bool interrupt)
|
void CMailHandler::PushMail(u32 mail, bool interrupt, int cycles_into_future)
|
||||||
{
|
{
|
||||||
if (interrupt)
|
if (interrupt)
|
||||||
{
|
{
|
||||||
if (m_Mails.empty())
|
if (m_Mails.empty())
|
||||||
{
|
{
|
||||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP, cycles_into_future);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_Mails.front().second = true;
|
m_Mails.front().second = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_Mails.emplace(_Mail, false);
|
m_Mails.emplace(mail, false);
|
||||||
DEBUG_LOG(DSP_MAIL, "DSP writes 0x%08x", _Mail);
|
DEBUG_LOG(DSP_MAIL, "DSP writes 0x%08x", mail);
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 CMailHandler::ReadDSPMailboxHigh()
|
u16 CMailHandler::ReadDSPMailboxHigh()
|
||||||
|
|
|
@ -21,7 +21,8 @@ public:
|
||||||
CMailHandler();
|
CMailHandler();
|
||||||
~CMailHandler();
|
~CMailHandler();
|
||||||
|
|
||||||
void PushMail(u32 _Mail, bool interrupt = false);
|
// TODO: figure out correct timing for interrupts rather than defaulting to "immediately."
|
||||||
|
void PushMail(u32 mail, bool interrupt = false, int cycles_into_future = 0);
|
||||||
void Clear();
|
void Clear();
|
||||||
void Halt(bool _Halt);
|
void Halt(bool _Halt);
|
||||||
void DoState(PointerWrap& p);
|
void DoState(PointerWrap& p);
|
||||||
|
|
|
@ -77,7 +77,22 @@ void AXUCode::LoadResamplingCoefficients()
|
||||||
void AXUCode::SignalWorkEnd()
|
void AXUCode::SignalWorkEnd()
|
||||||
{
|
{
|
||||||
// Signal end of processing
|
// Signal end of processing
|
||||||
m_mail_handler.PushMail(DSP_YIELD, true);
|
// TODO: figure out how many cycles this is actually supposed to take
|
||||||
|
|
||||||
|
// The Clone Wars hangs upon initial boot if this interrupt happens too quickly after submitting a
|
||||||
|
// command list. When played in DSP-LLE, the interrupt lags by about 160,000 cycles, though any
|
||||||
|
// value greater than or equal to 814 will work here. In other games, the lag can be as small as
|
||||||
|
// 50,000 cycles (in Metroid Prime) and as large as 718,092 cycles (in Tales of Symphonia!).
|
||||||
|
|
||||||
|
// On the PowerPC side, hthh_ discovered that The Clone Wars tracks a "AXCommandListCycles"
|
||||||
|
// variable which matches the aforementioned 160,000 cycles. It's initialized to ~2500 cycles for
|
||||||
|
// a minimal, empty command list, so that should be a safe number for pretty much anything a game
|
||||||
|
// does.
|
||||||
|
|
||||||
|
// For more information, see https://bugs.dolphin-emu.org/issues/10265.
|
||||||
|
constexpr int AX_EMPTY_COMMAND_LIST_CYCLES = 2500;
|
||||||
|
|
||||||
|
m_mail_handler.PushMail(DSP_YIELD, true, AX_EMPTY_COMMAND_LIST_CYCLES);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AXUCode::HandleCommandList()
|
void AXUCode::HandleCommandList()
|
||||||
|
|
Loading…
Reference in New Issue