From 3475ba8918766f5aeda0a6384d2fa238457bfe42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Mon, 4 Sep 2017 00:14:22 +0200 Subject: [PATCH] DSP: Fix missing masking for accelerator registers Based on hardware tests, masking occurs for the accelerator registers. This fixes Red Steel and Far Cry Vengeance, which rely on this behavior when reading back the current playback position from the DSP. --- Source/Core/Core/DSP/DSPAccelerator.cpp | 5 +++-- Source/Core/Core/DSP/DSPHWInterface.cpp | 12 ++++++++++++ Source/Core/Core/HW/DSPHLE/UCodes/AXVoice.h | 11 +++++++---- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/DSP/DSPAccelerator.cpp b/Source/Core/Core/DSP/DSPAccelerator.cpp index 3777333719..6940bb0725 100644 --- a/Source/Core/Core/DSP/DSPAccelerator.cpp +++ b/Source/Core/Core/DSP/DSPAccelerator.cpp @@ -9,6 +9,7 @@ #include "Common/MathUtil.h" #include "Core/DSP/DSPCore.h" +#include "Core/DSP/DSPHWInterface.h" #include "Core/DSP/DSPHost.h" namespace DSP @@ -177,8 +178,8 @@ u16 dsp_read_accelerator() DSPCore_SetException(EXP_ACCOV); } - g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16; - g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff; + gdsp_ifx_write(DSP_ACCAH, Address >> 16); + gdsp_ifx_write(DSP_ACCAL, Address & 0xffff); return val; } } // namespace DSP diff --git a/Source/Core/Core/DSP/DSPHWInterface.cpp b/Source/Core/Core/DSP/DSPHWInterface.cpp index fa18c96968..c965233a8e 100644 --- a/Source/Core/Core/DSP/DSPHWInterface.cpp +++ b/Source/Core/Core/DSP/DSPHWInterface.cpp @@ -156,6 +156,18 @@ void gdsp_ifx_write(u32 addr, u32 val) dsp_step_accelerator(); break; */ + + // Masking occurs for the start and end addresses as soon as the registers are written to. + case DSP_ACSAH: + case DSP_ACEAH: + g_dsp.ifx_regs[addr & 0xff] = val & 0x3fff; + break; + + // This also happens for the current address, but with a different mask. + case DSP_ACCAH: + g_dsp.ifx_regs[addr & 0xff] = val & 0xbfff; + break; + default: if ((addr & 0xff) >= 0xa0) { diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AXVoice.h b/Source/Core/Core/HW/DSPHLE/UCodes/AXVoice.h index b7fca29356..d0a407c342 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AXVoice.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AXVoice.h @@ -171,9 +171,12 @@ static bool acc_end_reached; void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr) { acc_pb = pb; - acc_loop_addr = HILO_TO_32(pb->audio_addr.loop_addr); - acc_end_addr = HILO_TO_32(pb->audio_addr.end_addr); + // Masking occurs for the start and end addresses as soon as the registers are written to. + acc_loop_addr = HILO_TO_32(pb->audio_addr.loop_addr) & 0x3fffffff; + acc_end_addr = HILO_TO_32(pb->audio_addr.end_addr) & 0x3fffffff; acc_cur_addr = cur_addr; + // It also happens for the current address, but with a different mask. + *acc_cur_addr &= 0xbfffffff; acc_end_reached = false; } @@ -456,8 +459,8 @@ void GetInputSamples(PB_TYPE& pb, s16* samples, u16 count, const s16* coeffs) pb.src.cur_addr_frac = (curr_pos & 0xFFFF); // Update current position in the PB. - pb.audio_addr.cur_addr_hi = (u16)(cur_addr >> 16); - pb.audio_addr.cur_addr_lo = (u16)(cur_addr & 0xFFFF); + pb.audio_addr.cur_addr_hi = static_cast(cur_addr >> 16) & 0xbfff; + pb.audio_addr.cur_addr_lo = static_cast(cur_addr); } // Add samples to an output buffer, with optional volume ramping.