SPU2: Improve ADMA behaviour/timing

This commit is contained in:
refractionpcsx2 2021-01-23 06:20:14 +00:00
parent b9a6dca4b4
commit 4497532edb
3 changed files with 29 additions and 38 deletions

View File

@ -97,8 +97,10 @@ void V_Core::LogAutoDMA(FILE* fp)
void V_Core::AutoDMAReadBuffer(int mode) //mode: 0= split stereo; 1 = do not split stereo
{
int spos = ((InputPosRead + 0xff) & 0x100); //starting position of the free buffer
int spos = ActiveTSA & 0x100;// ((InputPosRead + 0xff) & 0x100); //starting position of the free buffer
if (spos == (OutPos & 0x100))
return;
LogAutoDMA(Index ? ADMA7LogFile : ADMA4LogFile);
// HACKFIX!! DMAPtr can be invalid after a savestate load, so the savestate just forces it
@ -129,6 +131,9 @@ void V_Core::AutoDMAReadBuffer(int mode) //mode: 0= split stereo; 1 = do not spl
MADR += 0x200;
InputDataLeft -= 0x100;
InputDataProgress += 0x100;
ActiveTSA += 0x100;
ActiveTSA &= ~0x200;
TSA = ActiveTSA;
}
// See ReadInput at mixer.cpp for explanation on the commented out lines
//
@ -155,6 +160,7 @@ void V_Core::StartADMAWrite(u16* pMem, u32 sz)
else if (size >= 512)
{
InputDataLeft = size;
AutoDMACtrl &= 3;
if (AdmaInProgress == 0)
{
#ifdef PCM24_S1_INTERLEAVE
@ -172,15 +178,18 @@ void V_Core::StartADMAWrite(u16* pMem, u32 sz)
AutoDMAReadBuffer(0);
#endif
AdmaInProgress = 1;
// Klonoa 2
if (size == 512)
if (!InputDataLeft)
{
DMAICounter = size * 4;
LastClock = *cyclePtr;
AdmaInProgress = 0;
AutoDMACtrl |= ~3;
}
}
AdmaInProgress = 1;
}
else
{
@ -357,8 +366,6 @@ void V_Core::FinishDMAwrite()
void V_Core::FinishDMAread()
{
if (ActiveTSA != TSA)
ConLog("Read WTF TSA %x Active %x\n", TSA, ActiveTSA);
u32 buff1end = ActiveTSA + std::min(ReadSize, (u32)0x100 + std::abs(DMAICounter / 4));
u32 start = ActiveTSA;
u32 buff2end = 0;
@ -520,7 +527,7 @@ void V_Core::DoDMAwrite(u16* pMem, u32 size)
else
{
PlainDMAWrite(pMem, size);
Regs.STATX &= ~0x80;
Regs.STATX |= 0x400;
}
Regs.STATX &= ~0x80;
Regs.STATX |= 0x400;
}

View File

@ -123,7 +123,7 @@ StereoOut32 V_Core::ReadInput()
if ((Index != 1) || ((PlayMode & 2) == 0))
{
for (int i = 0; i < 2; i++)
if (Cores[i].IRQEnable && 0x2000 + (Index << 10) + InputPosRead == (Cores[i].IRQA & 0xfffffdff))
if (Cores[i].IRQEnable && 0x2000 + (Index << 10) + OutPos == (Cores[i].IRQA & 0xfffffdff))
SetIrqCall(i);
//retval = StereoOut32(
@ -131,8 +131,8 @@ StereoOut32 V_Core::ReadInput()
// (s32)ADMATempBuffer[InputPosRead+0x200]
//);
retval = StereoOut32(
(s32)(*GetMemPtr(0x2000 + (Index << 10) + InputPosRead)),
(s32)(*GetMemPtr(0x2200 + (Index << 10) + InputPosRead)));
(s32)(*GetMemPtr(0x2000 + (Index << 10) + OutPos)),
(s32)(*GetMemPtr(0x2200 + (Index << 10) + OutPos)));
}
#ifdef PCSX2_DEVBUILD
@ -142,21 +142,19 @@ StereoOut32 V_Core::ReadInput()
InputPosRead++;
if ((AutoDMACtrl & (Index + 1)) && (InputPosRead == 0x100 || InputPosRead == 0x200))
if ((OutPos == 0xFF || OutPos == 0x1FF))
{
AdmaInProgress = 0;
if (InputDataLeft >= 0x200)
{
//u8 k=InputDataLeft>=InputDataProgress;
int oldOutPos = OutPos;
OutPos = (OutPos + 1) & 0x1FF;
AutoDMAReadBuffer(0);
OutPos = oldOutPos;
AdmaInProgress = 1;
ActiveTSA = (Index << 10) + InputPosRead;
TSA = ActiveTSA;
if (InputDataLeft < 0x200)
{
if((AutoDMACtrl & (Index + 1)))
if ((AutoDMACtrl & (Index + 1)))
AutoDMACtrl |= ~3;
if (IsDevBuild)
@ -168,24 +166,10 @@ StereoOut32 V_Core::ReadInput()
ConLog("WARNING: adma buffer didn't finish with a whole block!!\n");
}
}
AdmaInProgress = 0;
InputDataLeft = 0;
// Hack, kinda. We call the interrupt early here, since PCSX2 doesn't like them delayed.
//DMAICounter = 1;
if (Index == 0)
{
if (!SPU2_dummy_callback)
spu2DMA4Irq();
else
SPU2interruptDMA4();
}
else
{
if (!SPU2_dummy_callback)
spu2DMA7Irq();
else
SPU2interruptDMA7();
}
DMAICounter = 0x200 * 4;
LastClock = *cyclePtr;
}
}
}

View File

@ -1522,11 +1522,11 @@ static void __fastcall RegWrite_Core(u16 value)
return;
}
thiscore.AutoDMACtrl = value;
if (value == 0 && thiscore.AdmaInProgress && (thiscore.Regs.STATX & 0x400))
if (value == 0 && thiscore.AdmaInProgress)
{
// Kill the current transfer so it doesn't continue
thiscore.AdmaInProgress = 0;
thiscore.Regs.STATX &= ~0x400; // Set DMA as not busy transferring
// No need to end the DMA here, the IOP seems to handle that
thiscore.InputDataLeft = 0;
}
break;