From de6e80736445110aa3f1e896fbfd75ac1cadc090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Tue, 19 Sep 2017 18:51:02 +0200 Subject: [PATCH] DSP: Handle two accelerator loop edge cases properly There are two special cases that the DSP accelerator handles in a special way: when the end address is of the form xxxxxxx0 or xxxxxxx1. For these two cases, the normal overflow handling doesn't apply. Instead, the overflow check is different, the ACCOV exception never fires at all, the predscale register is not updated, reads are not suspended, and if the end address is 16-byte aligned, the DSP loops back to start_address + 1 instead of the regular start_address. --- Source/Core/Core/DSP/DSPAccelerator.cpp | 29 +++++++++++++------------ 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/Source/Core/Core/DSP/DSPAccelerator.cpp b/Source/Core/Core/DSP/DSPAccelerator.cpp index 6e40d7f930..1692e192fe 100644 --- a/Source/Core/Core/DSP/DSPAccelerator.cpp +++ b/Source/Core/Core/DSP/DSPAccelerator.cpp @@ -76,19 +76,6 @@ u16 Accelerator::Read(s16* coefs) { case 0x00: // ADPCM audio { - switch (m_end_address & 15) - { - case 0: // Tom and Jerry - step_size_bytes = 1; - break; - case 1: // Blazing Angels - step_size_bytes = 0; - break; - default: - step_size_bytes = 2; - break; - } - int scale = 1 << (m_pred_scale & 0xF); int coef_idx = (m_pred_scale >> 4) & 0x7; @@ -103,12 +90,26 @@ u16 Accelerator::Read(s16* coefs) s32 val32 = (scale * temp) + ((0x400 + coef1 * m_yn1 + coef2 * m_yn2) >> 11); val = static_cast(MathUtil::Clamp(val32, -0x7FFF, 0x7FFF)); + step_size_bytes = 2; m_yn2 = m_yn1; m_yn1 = val; m_current_address += 1; - if ((m_current_address & 15) == 0) + // These two cases are handled in a special way, separate from normal overflow handling: + // the ACCOV exception does not fire at all, the predscale register is not updated, + // and if the end address is 16-byte aligned, the DSP loops to start_address + 1 + // instead of start_address. + if ((m_end_address & 0xf) == 0x0 && m_current_address == m_end_address) + { + m_current_address = m_start_address + 1; + } + else if ((m_end_address & 0xf) == 0x1 && m_current_address == m_end_address - 1) + { + m_current_address = m_start_address; + } + // If any of these special cases were hit, the DSP does not update the predscale register. + else if ((m_current_address & 15) == 0) { m_pred_scale = ReadMemory((m_current_address & ~15) >> 1); m_current_address += 2;