SPU2: Handle partial ADMA Transfers

This commit is contained in:
refractionpcsx2 2021-01-23 16:53:18 +00:00
parent 7c37e86283
commit c7267d3665
2 changed files with 38 additions and 34 deletions

View File

@ -98,11 +98,18 @@ void V_Core::LogAutoDMA(FILE* fp)
void V_Core::AutoDMAReadBuffer(int mode) //mode: 0= split stereo; 1 = do not split stereo void V_Core::AutoDMAReadBuffer(int mode) //mode: 0= split stereo; 1 = do not split stereo
{ {
int spos = ActiveTSA & 0x100; // Starting position passed by TSA int spos = ActiveTSA & 0x100; // Starting position passed by TSA
bool leftbuffer = !(ActiveTSA & 0x80);
if (spos == (OutPos & 0x100)) if (spos == (OutPos & 0x100))
{
//ConLog("Ignoring buffer update Pos %x OutPos %x\n", spos, OutPos);
return; return;
}
int size = std::min(InputDataLeft, (u32)0x200);
if (!leftbuffer)
size = 0x100;
LogAutoDMA(Index ? ADMA7LogFile : ADMA4LogFile); LogAutoDMA(Index ? ADMA7LogFile : ADMA4LogFile);
//ConLog("Refilling ADMA buffer at %x OutPos %x with %x\n", spos, OutPos, size);
// HACKFIX!! DMAPtr can be invalid after a savestate load, so the savestate just forces it // HACKFIX!! DMAPtr can be invalid after a savestate load, so the savestate just forces it
// to nullptr and we ignore it here. (used to work in old VM editions of PCSX2 with fixed // to nullptr and we ignore it here. (used to work in old VM editions of PCSX2 with fixed
// addressing, but new PCSX2s have dynamic memory addressing). // addressing, but new PCSX2s have dynamic memory addressing).
@ -111,44 +118,45 @@ void V_Core::AutoDMAReadBuffer(int mode) //mode: 0= split stereo; 1 = do not spl
{ {
if (DMAPtr != nullptr) if (DMAPtr != nullptr)
//memcpy((ADMATempBuffer+(spos<<1)),DMAPtr+InputDataProgress,0x400); //memcpy((ADMATempBuffer+(spos<<1)),DMAPtr+InputDataProgress,0x400);
memcpy(GetMemPtr(0x2000 + (Index << 10) + spos), DMAPtr + InputDataProgress, 0x400); memcpy(GetMemPtr(0x2000 + (Index << 10) + spos), DMAPtr + InputDataProgress, size);
MADR += 0x400; MADR += size;
InputDataLeft -= 0x200; InputDataLeft -= 0x200;
InputDataProgress += 0x200; InputDataProgress += 0x200;
} }
else else
{ {
if (DMAPtr != nullptr) while (size)
//memcpy((ADMATempBuffer+spos),DMAPtr+InputDataProgress,0x200); {
memcpy(GetMemPtr(0x2000 + (Index << 10) + spos), DMAPtr + InputDataProgress, 0x200); if (!leftbuffer)
MADR += 0x200; spos |= 0x200;
InputDataLeft -= 0x100; else
InputDataProgress += 0x100; spos &= ~0x200;
//ConLog("Filling %s buffer\n", leftbuffer ? "Left" : "Right");
if (DMAPtr != nullptr) if (DMAPtr != nullptr)
//memcpy((ADMATempBuffer+spos+0x200),DMAPtr+InputDataProgress,0x200); //memcpy((ADMATempBuffer+spos),DMAPtr+InputDataProgress,0x200);
memcpy(GetMemPtr(0x2200 + (Index << 10) + spos), DMAPtr + InputDataProgress, 0x200); memcpy(GetMemPtr(0x2000 + (Index << 10) + spos), DMAPtr + InputDataProgress, 0x200);
MADR += 0x200; MADR += 0x200;
InputDataLeft -= 0x100; InputDataLeft -= 0x100;
InputDataProgress += 0x100; InputDataProgress += 0x100;
ActiveTSA += 0x100; leftbuffer = !leftbuffer;
ActiveTSA &= ~0x200; size -= 0x100;
TSA = ActiveTSA; ActiveTSA += 0x80;
ActiveTSA &= ~0x200;
TSA = ActiveTSA;
}
} }
// See ReadInput at mixer.cpp for explanation on the commented out lines
//
} }
void V_Core::StartADMAWrite(u16* pMem, u32 sz) void V_Core::StartADMAWrite(u16* pMem, u32 sz)
{ {
int size = (sz) & (~511); int size = sz;
if (cyclePtr != nullptr) if (cyclePtr != nullptr)
TimeUpdate(*cyclePtr); TimeUpdate(*cyclePtr);
if (MsgAutoDMA()) if (MsgAutoDMA())
ConLog("* SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n", ConLog("* SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).OutPos %x\n",
GetDmaIndexChar(), size << 1, ActiveTSA, DMABits, AutoDMACtrl, (~Regs.ATTR) & 0xffff); GetDmaIndexChar(), size << 1, ActiveTSA, DMABits, AutoDMACtrl, (~Regs.ATTR) & 0xffff, OutPos);
InputDataProgress = 0; InputDataProgress = 0;
if ((AutoDMACtrl & (Index + 1)) == 0) if ((AutoDMACtrl & (Index + 1)) == 0)
@ -157,7 +165,7 @@ void V_Core::StartADMAWrite(u16* pMem, u32 sz)
DMAICounter = size * 4; DMAICounter = size * 4;
LastClock = *cyclePtr; LastClock = *cyclePtr;
} }
else if (size >= 512) else if (size >= 256)
{ {
InputDataLeft = size; InputDataLeft = size;
AutoDMACtrl &= 3; AutoDMACtrl &= 3;
@ -178,7 +186,6 @@ void V_Core::StartADMAWrite(u16* pMem, u32 sz)
AdmaInProgress = 1; AdmaInProgress = 1;
// Klonoa 2
if (!InputDataLeft) if (!InputDataLeft)
{ {
DMAICounter = size * 4; DMAICounter = size * 4;
@ -190,7 +197,7 @@ void V_Core::StartADMAWrite(u16* pMem, u32 sz)
} }
else else
{ {
size = sz; ConLog("ADMA%c Error Size of %x too small\n", GetDmaIndexChar(), size);
InputDataLeft = 0; InputDataLeft = 0;
DMAICounter = size * 4; DMAICounter = size * 4;
LastClock = *cyclePtr; LastClock = *cyclePtr;

View File

@ -48,9 +48,6 @@ StereoOut32 V_Core::ReadInput_HiFi()
retval.Right >>= 4; retval.Right >>= 4;
} }
// Why does CDDA mode check for InputPos == 0x100? In the old code, SPDIF mode did not but CDDA did.
// One of these seems wrong, they should be the same. Since standard ADMA checks too I'm assuming that as default. -- air
if ((OutPos == 0xFF || OutPos == 0x1FF)) if ((OutPos == 0xFF || OutPos == 0x1FF))
{ {
if (InputDataLeft >= 0x200) if (InputDataLeft >= 0x200)
@ -103,9 +100,9 @@ StereoOut32 V_Core::ReadInput()
DebugCores[Index].admaWaveformR[OutPos % 0x100] = retval.Right; DebugCores[Index].admaWaveformR[OutPos % 0x100] = retval.Right;
#endif #endif
if ((OutPos == 0xFF || OutPos == 0x1FF)) if (OutPos == 0xFF || OutPos == 0x1FF || OutPos == 0x7F || OutPos == 0x17F)
{ {
if (InputDataLeft >= 0x200) if (InputDataLeft >= 0x100)
{ {
//u8 k=InputDataLeft>=InputDataProgress; //u8 k=InputDataLeft>=InputDataProgress;
int oldOutPos = OutPos; int oldOutPos = OutPos;
@ -113,7 +110,7 @@ StereoOut32 V_Core::ReadInput()
AutoDMAReadBuffer(0); AutoDMAReadBuffer(0);
OutPos = oldOutPos; OutPos = oldOutPos;
AdmaInProgress = 1; AdmaInProgress = 1;
if (InputDataLeft < 0x200) if (InputDataLeft < 0x100)
{ {
if ((AutoDMACtrl & (Index + 1))) if ((AutoDMACtrl & (Index + 1)))
AutoDMACtrl |= ~3; AutoDMACtrl |= ~3;