DSP: Fix ACCOV not suspending accelerator reads

When an ACCOV is triggered, the accelerator stops reading back anything
and updating the current address until the YN2 register is set.

This is kept track of internally by the DSP; this state is not exposed
via any register.

However, we need to emulate this behaviour correctly because some
ucodes rely on it (notably AX GC); failure to emulate it will result
in reading past the end and start address for non-looped voices.
This commit is contained in:
Léo Lam 2017-09-19 18:16:50 +02:00
parent 8310a672b0
commit bd03f2e46e
4 changed files with 16 additions and 5 deletions

View File

@ -60,6 +60,9 @@ void Accelerator::WriteD3(u16 value)
u16 Accelerator::Read(s16* coefs) u16 Accelerator::Read(s16* coefs)
{ {
if (m_reads_stopped)
return 0x0000;
u16 val; u16 val;
u8 step_size_bytes = 0; u8 step_size_bytes = 0;
@ -148,6 +151,7 @@ u16 Accelerator::Read(s16* coefs)
{ {
// Set address back to start address. // Set address back to start address.
m_current_address = m_start_address; m_current_address = m_start_address;
m_reads_stopped = true;
OnEndException(); OnEndException();
} }
@ -164,6 +168,7 @@ void Accelerator::DoState(PointerWrap& p)
p.Do(m_yn1); p.Do(m_yn1);
p.Do(m_yn2); p.Do(m_yn2);
p.Do(m_pred_scale); p.Do(m_pred_scale);
p.Do(m_reads_stopped);
} }
constexpr u32 START_END_ADDRESS_MASK = 0x3fffffff; constexpr u32 START_END_ADDRESS_MASK = 0x3fffffff;
@ -197,6 +202,7 @@ void Accelerator::SetYn1(s16 yn1)
void Accelerator::SetYn2(s16 yn2) void Accelerator::SetYn2(s16 yn2)
{ {
m_yn2 = yn2; m_yn2 = yn2;
m_reads_stopped = false;
} }
void Accelerator::SetPredScale(u16 pred_scale) void Accelerator::SetPredScale(u16 pred_scale)

View File

@ -50,5 +50,10 @@ protected:
s16 m_yn1 = 0; s16 m_yn1 = 0;
s16 m_yn2 = 0; s16 m_yn2 = 0;
u16 m_pred_scale = 0; u16 m_pred_scale = 0;
// When an ACCOV is triggered, the accelerator stops reading back anything
// and updating the current address register, unless the YN2 register is written to.
// This is kept track of internally; this state is not exposed via any register.
bool m_reads_stopped = false;
}; };
} // namespace DSP } // namespace DSP

View File

@ -199,10 +199,10 @@ protected:
#ifdef AX_WII #ifdef AX_WII
// One of the few meaningful differences between AXGC and AXWii: // One of the few meaningful differences between AXGC and AXWii:
// while AXGC handles non looping voices ending by having 0000 // while AXGC handles non looping voices ending by relying on the
// samples at the loop address, AXWii has the 0000 samples // accelerator to stop reads once the loop address is reached,
// internally in DRAM and use an internal pointer to it (loop addr // AXWii has the 0000 samples internally in DRAM and use an internal
// does not contain 0000 samples on AXWii!). // pointer to it (loop addr does not contain 0000 samples on AXWii!).
acc_end_reached = true; acc_end_reached = true;
#endif #endif
} }

View File

@ -74,7 +74,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread; static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system // Don't forget to increase this after doing changes on the savestate system
static const u32 STATE_VERSION = 89; // Last changed in PR 5890 static const u32 STATE_VERSION = 90; // Last changed in PR 6077
// Maps savestate versions to Dolphin versions. // Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list, // Versions after 42 don't need to be added to this list,