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. diff --git a/Source/DSPSpy/tests/accelerator_test.ds b/Source/DSPSpy/tests/accelerator_test.ds new file mode 100644 index 0000000000..ac9cb99b83 --- /dev/null +++ b/Source/DSPSpy/tests/accelerator_test.ds @@ -0,0 +1,153 @@ +; Test for the DSP accelerator, in particular to check its masking behaviour. +; See https://github.com/dolphin-emu/dolphin/pull/5997 +incdir "tests" +include "dsp_base.inc" +jmp test_main + +; Writes the passed format, start and end addresses to the accelerator registers, +; then reads them back to registers. +; The current address is initialised to the start. +; Parameters: +; AC0.H: sample format +; AC0.M/L: start address +; AC1.M/L: end address +test_accelerator_addrs_ex: + ; Set the sample format + sr @0xffd1, $AC0.H + + ; Set the accelerator start and current address. + srs @ACSAH, $AC0.M + srs @ACCAH, $AC0.M + srs @ACSAL, $AC0.L + srs @ACCAL, $AC0.L + ; Set the accelerator end address. + srs @ACEAH, $AC1.M + srs @ACEAL, $AC1.L + + ; Move the values back to registers that can be printed by dspspy. + ; AC0 -> start, AC1 -> end, AX0 -> current + lri $AC0.H, #0 + lrs $AC0.M, @ACSAH + lrs $AC0.L, @ACSAL + lri $AC1.H, #0 + lrs $AC1.M, @ACEAH + lrs $AC1.L, @ACEAL + lrs $AX0.H, @ACCAH + lrs $AX0.L, @ACCAL + + ; Make the accelerator read memory + lrs $AX1.H, @ARAM + lrs $AX1.H, @ARAM + ; AX1 -> new current position after read + lrs $AX1.H, @ACCAH + lrs $AX1.L, @ACCAL + + call send_back + ret + +; Same as test_accelerator_addrs_ex, but with the end address set to start + 0x1000. +test_accelerator_addrs: + lri $AC1.H, #0 + lri $AC1.M, #0 + lri $AC1.L, #0x1000 + add $ACC1, $ACC0 + jmp test_accelerator_addrs_ex + +test_main: + ; Test 1 + lri $AC0.H, #0x19 ; 8-bit PCM + lri $AC0.M, #0x0000 ; start + lri $AC0.L, #0x1000 ; start + call test_accelerator_addrs + + ; Test 2 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0x0000 ; start + lri $AC0.L, #0x1000 ; start + call test_accelerator_addrs + + ; Test 3 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0x1000 ; start + lri $AC0.L, #0x0000 ; start + call test_accelerator_addrs + + ; Test 4 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0x2000 ; start + lri $AC0.L, #0x0000 ; start + call test_accelerator_addrs + + ; Test 5 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0x3000 ; start + lri $AC0.L, #0x0000 ; start + call test_accelerator_addrs + + ; Test 6 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0x3fff ; start + lri $AC0.L, #0xffff ; start + call test_accelerator_addrs + + ; Test 7 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0x4000 ; start + lri $AC0.L, #0x0000 ; start + call test_accelerator_addrs + + ; Test 8 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0x5000 ; start + lri $AC0.L, #0x0000 ; start + call test_accelerator_addrs + + ; Test 9 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0x6000 ; start + lri $AC0.L, #0x0000 ; start + call test_accelerator_addrs + + ; Test 10 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0x7000 ; start + lri $AC0.L, #0x0000 ; start + call test_accelerator_addrs + + ; Test 11 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0x7fff ; start + lri $AC0.L, #0xffff ; start + call test_accelerator_addrs + + ; Test 12 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0x8000 ; start + lri $AC0.L, #0x0000 ; start + call test_accelerator_addrs + + ; Test 13 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0x9000 ; start + lri $AC0.L, #0x0000 ; start + call test_accelerator_addrs + + ; Test 14 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0xc000 ; start + lri $AC0.L, #0x1000 ; start + call test_accelerator_addrs + + ; Test 15 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0xd000 ; start + lri $AC0.L, #0x1000 ; start + call test_accelerator_addrs + + ; Test 16 + lri $AC0.H, #0xa ; 16-bit PCM + lri $AC0.M, #0xffff ; start + lri $AC0.L, #0xffff ; start + call test_accelerator_addrs + + jmp end_of_test