From f929d79473ad62ce7e9d3a5f9e223a6574b13bc1 Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Sun, 29 Nov 2020 19:23:27 +0000 Subject: [PATCH] SPU2: Delay DMA Reads to prevent overrun Savestate bump --- pcsx2/SPU2/Dma.cpp | 20 +++++++++++++------- pcsx2/SPU2/defs.h | 4 ++++ pcsx2/SPU2/spu2sys.cpp | 6 ++++++ pcsx2/SaveState.h | 2 +- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/pcsx2/SPU2/Dma.cpp b/pcsx2/SPU2/Dma.cpp index ad4e713a6b..32ca6bc5ec 100644 --- a/pcsx2/SPU2/Dma.cpp +++ b/pcsx2/SPU2/Dma.cpp @@ -334,11 +334,9 @@ void V_Core::PlainDMAWrite(u16* pMem, u32 size) TADR = MADR + (size << 1); } -void V_Core::DoDMAread(u16* pMem, u32 size) +void V_Core::FinishDMAread() { - TSA &= 0xfffff; - - u32 buff1end = TSA + size; + u32 buff1end = TSA + ReadSize; u32 buff2end = 0; if (buff1end > 0x100000) { @@ -347,8 +345,7 @@ void V_Core::DoDMAread(u16* pMem, u32 size) } const u32 buff1size = (buff1end - TSA); - memcpy(pMem, GetMemPtr(TSA), buff1size * 2); - + memcpy(DMARPtr, GetMemPtr(TSA), buff1size * 2); // Note on TSA's position after our copy finishes: // IRQA should be measured by the end of the writepos+0x20. But the TDA // should be written back at the precise endpoint of the xfer. @@ -360,7 +357,7 @@ void V_Core::DoDMAread(u16* pMem, u32 size) // second branch needs cleared: // It starts at the beginning of memory and moves forward to buff2end - memcpy(&pMem[buff1size], GetMemPtr(0), buff2end * 2); + memcpy(&DMARPtr[buff1size], GetMemPtr(0), buff2end * 2); TDA = (buff2end + 0x20) & 0xfffff; @@ -396,6 +393,15 @@ void V_Core::DoDMAread(u16* pMem, u32 size) } TSA = TDA; + IsDMARead = false; +} + +void V_Core::DoDMAread(u16* pMem, u32 size) +{ + TSA &= 0xfffff; + DMARPtr = pMem; + ReadSize = size; + IsDMARead = true; DMAICounter = size; Regs.STATX &= ~0x80; diff --git a/pcsx2/SPU2/defs.h b/pcsx2/SPU2/defs.h index c620a4b2b3..f13f102aa2 100644 --- a/pcsx2/SPU2/defs.h +++ b/pcsx2/SPU2/defs.h @@ -437,6 +437,9 @@ struct V_Core // old dma only u16* DMAPtr; + u16* DMARPtr; // Mem pointer for DMA Reads + u32 ReadSize; + bool IsDMARead; u32 MADR; u32 TADR; @@ -525,6 +528,7 @@ struct V_Core // old dma only void DoDMAwrite(u16* pMem, u32 size); void DoDMAread(u16* pMem, u32 size); + void FinishDMAread(); void AutoDMAReadBuffer(int mode); void StartADMAWrite(u16* pMem, u32 sz); diff --git a/pcsx2/SPU2/spu2sys.cpp b/pcsx2/SPU2/spu2sys.cpp index d66ecc7d63..75de7ad615 100644 --- a/pcsx2/SPU2/spu2sys.cpp +++ b/pcsx2/SPU2/spu2sys.cpp @@ -427,6 +427,9 @@ __forceinline void TimeUpdate(u32 cClocks) Cores[0].DMAICounter -= TickInterval; if (Cores[0].DMAICounter <= 0) { + if (Cores[0].IsDMARead) + Cores[0].FinishDMAread(); + //ConLog("counter set and callback!\n"); Cores[0].MADR = Cores[0].TADR; Cores[0].DMAICounter = 0; @@ -447,6 +450,9 @@ __forceinline void TimeUpdate(u32 cClocks) Cores[1].DMAICounter -= TickInterval; if (Cores[1].DMAICounter <= 0) { + if (Cores[1].IsDMARead) + Cores[1].FinishDMAread(); + Cores[1].MADR = Cores[1].TADR; Cores[1].DMAICounter = 0; //ConLog( "* SPU2 > DMA 7 Callback! %d\n", Cycles ); diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index f0356680c4..d817ff642d 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -24,7 +24,7 @@ // the lower 16 bit value. IF the change is breaking of all compatibility with old // states, increment the upper 16 bit value, and clear the lower 16 bits to 0. -static const u32 g_SaveVersion = (0x9A10 << 16) | 0x0000; +static const u32 g_SaveVersion = (0x9A11 << 16) | 0x0000; // this function is meant to be used in the place of GSfreeze, and provides a safe layer // between the GS saving function and the MTGS's needs. :)