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.
This commit is contained in:
Léo Lam 2017-09-19 18:51:02 +02:00
parent bd03f2e46e
commit de6e807364
1 changed files with 15 additions and 14 deletions

View File

@ -76,19 +76,6 @@ u16 Accelerator::Read(s16* coefs)
{ {
case 0x00: // ADPCM audio 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 scale = 1 << (m_pred_scale & 0xF);
int coef_idx = (m_pred_scale >> 4) & 0x7; 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); s32 val32 = (scale * temp) + ((0x400 + coef1 * m_yn1 + coef2 * m_yn2) >> 11);
val = static_cast<s16>(MathUtil::Clamp<s32>(val32, -0x7FFF, 0x7FFF)); val = static_cast<s16>(MathUtil::Clamp<s32>(val32, -0x7FFF, 0x7FFF));
step_size_bytes = 2;
m_yn2 = m_yn1; m_yn2 = m_yn1;
m_yn1 = val; m_yn1 = val;
m_current_address += 1; 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_pred_scale = ReadMemory((m_current_address & ~15) >> 1);
m_current_address += 2; m_current_address += 2;