mirror of https://github.com/PCSX2/pcsx2.git
SPU: Fix bugs in recent commits, redesign DMA slightly
Savestate bump, sorry
This commit is contained in:
parent
ddffd9acd6
commit
5cf5f40c65
|
@ -506,9 +506,9 @@ void psxRcntUpdate()
|
|||
|
||||
if (difference >= psxCounters[6].CycleT)
|
||||
{
|
||||
SPU2async(difference);
|
||||
psxCounters[6].sCycleT = psxRegs.cycle;
|
||||
psxCounters[6].CycleT = psxCounters[6].rate;
|
||||
SPU2async(difference);
|
||||
}
|
||||
else
|
||||
c -= difference;
|
||||
|
|
|
@ -138,14 +138,17 @@ void V_Core::StartADMAWrite(u16* pMem, u32 sz)
|
|||
{
|
||||
int size = (sz) & (~511);
|
||||
|
||||
if (cyclePtr != nullptr)
|
||||
TimeUpdate(*cyclePtr);
|
||||
|
||||
if (MsgAutoDMA())
|
||||
ConLog("* SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n",
|
||||
GetDmaIndexChar(), size << 1, TSA, DMABits, AutoDMACtrl, (~Regs.ATTR) & 0xffff);
|
||||
GetDmaIndexChar(), size << 1, ActiveTSA, DMABits, AutoDMACtrl, (~Regs.ATTR) & 0xffff);
|
||||
|
||||
InputDataProgress = 0;
|
||||
if ((AutoDMACtrl & (Index + 1)) == 0)
|
||||
{
|
||||
TSA = 0x2000 + (Index << 10);
|
||||
ActiveTSA = 0x2000 + (Index << 10);
|
||||
DMAICounter = size * 4;
|
||||
LastClock = *cyclePtr;
|
||||
}
|
||||
|
@ -189,60 +192,8 @@ void V_Core::StartADMAWrite(u16* pMem, u32 sz)
|
|||
TADR = MADR + (size << 1);
|
||||
}
|
||||
|
||||
// HACKFIX: The BIOS breaks if we check the IRQA for both cores when issuing DMA writes. The
|
||||
// breakage is a null psxRegs.pc being loaded form some memory address (haven't traced it deeper
|
||||
// yet). We get around it by only checking the current core's IRQA, instead of doing the
|
||||
// *correct* thing and checking both. This might break some games, but having a working BIOS
|
||||
// is more important for now, until a proper fix can be uncovered.
|
||||
//
|
||||
// This problem might be caused by bad DMA timings in the IOP or a lack of proper IRQ
|
||||
// handling by the Effects Processor. After those are implemented, let's hope it gets
|
||||
// magically fixed?
|
||||
//
|
||||
// Note: This appears to affect DMA Writes only, so DMA Read DMAs are left intact (both core
|
||||
// IRQAs are tested). Very few games use DMA reads tho, so it could just be a case of "works
|
||||
// by the grace of not being used."
|
||||
//
|
||||
// Update: This hack is no longer needed when we don't do a core reset. Guess the null pc was in spu2 memory?
|
||||
#define NO_BIOS_HACKFIX 1 // set to 1 to disable the hackfix
|
||||
|
||||
void V_Core::PlainDMAWrite(u16* pMem, u32 size)
|
||||
{
|
||||
if (cyclePtr != nullptr)
|
||||
TimeUpdate(*cyclePtr);
|
||||
TSA &= 0xfffff;
|
||||
ReadSize = size;
|
||||
IsDMARead = false;
|
||||
LastClock = *cyclePtr;
|
||||
DMAICounter = std::min(ReadSize, (u32)0x100) * 4;
|
||||
Regs.STATX &= ~0x80;
|
||||
Regs.STATX |= 0x400;
|
||||
TADR = MADR + (size << 1);
|
||||
|
||||
if (((psxCounters[6].sCycleT + psxCounters[6].CycleT) - psxRegs.cycle) > DMAICounter)
|
||||
{
|
||||
psxCounters[6].sCycleT = psxRegs.cycle;
|
||||
psxCounters[6].CycleT = DMAICounter;
|
||||
|
||||
psxNextCounter -= (psxRegs.cycle - psxNextsCounter);
|
||||
psxNextsCounter = psxRegs.cycle;
|
||||
if (psxCounters[6].CycleT < psxNextCounter)
|
||||
psxNextCounter = psxCounters[6].CycleT;
|
||||
}
|
||||
|
||||
if (MsgDMA())
|
||||
ConLog("* SPU2: DMA%c Write Transfer of %d bytes to %x (%02x %x %04x). IRQE = %d IRQA = %x \n",
|
||||
GetDmaIndexChar(), size << 1, TSA, DMABits, AutoDMACtrl, Regs.ATTR & 0xffff,
|
||||
Cores[Index].IRQEnable, Cores[Index].IRQA);
|
||||
}
|
||||
|
||||
void V_Core::FinishDMAwrite()
|
||||
{
|
||||
|
||||
// Perform an alignment check.
|
||||
// Not really important. Everything should work regardless,
|
||||
// but it could be indicative of an emulation foopah elsewhere.
|
||||
|
||||
if (MsgToConsole())
|
||||
{
|
||||
// Don't need this anymore. Target may still be good to know though.
|
||||
|
@ -251,20 +202,45 @@ void V_Core::FinishDMAwrite()
|
|||
ConLog("* SPU2 DMA Write > Misaligned source. Core: %d IOP: %p TSA: 0x%x Size: 0x%x\n", Index, (void*)pMem, TSA, size);
|
||||
}*/
|
||||
|
||||
if (TSA & 7)
|
||||
if (ActiveTSA & 7)
|
||||
{
|
||||
ConLog("* SPU2 DMA Write > Misaligned target. Core: %d IOP: %p TSA: 0x%x Size: 0x%x\n", Index, (void*)DMAPtr, TSA, ReadSize);
|
||||
ConLog("* SPU2 DMA Write > Misaligned target. Core: %d IOP: %p TSA: 0x%x Size: 0x%x\n", Index, (void*)DMAPtr, ActiveTSA, ReadSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (cyclePtr != nullptr)
|
||||
TimeUpdate(*cyclePtr);
|
||||
|
||||
ReadSize = size;
|
||||
IsDMARead = false;
|
||||
DMAICounter = 0;
|
||||
LastClock = *cyclePtr;
|
||||
Regs.STATX &= ~0x80;
|
||||
Regs.STATX |= 0x400;
|
||||
TADR = MADR + (size << 1);
|
||||
|
||||
if (MsgDMA())
|
||||
ConLog("* SPU2: DMA%c Write Transfer of %d bytes to %x (%02x %x %04x). IRQE = %d IRQA = %x \n",
|
||||
GetDmaIndexChar(), size << 1, ActiveTSA, DMABits, AutoDMACtrl, Regs.ATTR & 0xffff,
|
||||
Cores[Index].IRQEnable, Cores[Index].IRQA);
|
||||
|
||||
FinishDMAwrite();
|
||||
|
||||
if (ReadSize == 0) //DMA Finished right away so we need a DMAICounter size to trigger the interrupt
|
||||
DMAICounter = size * 4;
|
||||
}
|
||||
|
||||
void V_Core::FinishDMAwrite()
|
||||
{
|
||||
if (ActiveTSA != TSA)
|
||||
ConLog("Write WTF TSA %x Active %x\n", TSA, ActiveTSA);
|
||||
if (Index == 0)
|
||||
DMA4LogWrite(DMAPtr, ReadSize << 1);
|
||||
else
|
||||
DMA7LogWrite(DMAPtr, ReadSize << 1);
|
||||
|
||||
TSA &= 0xfffff;
|
||||
|
||||
u32 buff1end = TSA + std::min(ReadSize, (u32)0x100);
|
||||
u32 buff1end = ActiveTSA + std::min(ReadSize, (u32)0x100 + std::abs(DMAICounter / 4));
|
||||
u32 start = ActiveTSA;
|
||||
u32 buff2end = 0;
|
||||
if (buff1end > 0x100000)
|
||||
{
|
||||
|
@ -272,7 +248,7 @@ void V_Core::FinishDMAwrite()
|
|||
buff1end = 0x100000;
|
||||
}
|
||||
|
||||
const int cacheIdxStart = TSA / pcm_WordsPerBlock;
|
||||
const int cacheIdxStart = ActiveTSA / pcm_WordsPerBlock;
|
||||
const int cacheIdxEnd = (buff1end + pcm_WordsPerBlock - 1) / pcm_WordsPerBlock;
|
||||
PcmCacheEntry* cacheLine = &pcm_cache_data[cacheIdxStart];
|
||||
PcmCacheEntry& cacheEnd = pcm_cache_data[cacheIdxEnd];
|
||||
|
@ -284,14 +260,14 @@ void V_Core::FinishDMAwrite()
|
|||
} while (cacheLine != &cacheEnd);
|
||||
|
||||
//ConLog( "* SPU2: Cache Clear Range! TSA=0x%x, TDA=0x%x (low8=0x%x, high8=0x%x, len=0x%x)\n",
|
||||
// TSA, buff1end, flagTSA, flagTDA, clearLen );
|
||||
// ActiveTSA, buff1end, flagTSA, flagTDA, clearLen );
|
||||
|
||||
|
||||
// First Branch needs cleared:
|
||||
// It starts at TSA and goes to buff1end.
|
||||
|
||||
const u32 buff1size = (buff1end - TSA);
|
||||
memcpy(GetMemPtr(TSA), DMAPtr, buff1size * 2);
|
||||
const u32 buff1size = (buff1end - ActiveTSA);
|
||||
memcpy(GetMemPtr(ActiveTSA), DMAPtr, buff1size * 2);
|
||||
|
||||
u32 TDA;
|
||||
|
||||
|
@ -304,17 +280,20 @@ void V_Core::FinishDMAwrite()
|
|||
// memory below 0x2800 (registers and such)
|
||||
//const u32 endpt2 = (buff2end + roundUp) / indexer_scalar;
|
||||
//memset( pcm_cache_flags, 0, endpt2 );
|
||||
TDA = buff1end;
|
||||
|
||||
DMAPtr += TDA - ActiveTSA;
|
||||
ReadSize -= TDA - ActiveTSA;
|
||||
ActiveTSA = 0;
|
||||
// Emulation Grayarea: Should addresses wrap around to zero, or wrap around to
|
||||
// 0x2800? Hard to know for sure (almost no games depend on this)
|
||||
memcpy(GetMemPtr(0), &DMAPtr[buff1size], buff2end * 2);
|
||||
memcpy(GetMemPtr(0), DMAPtr, buff2end * 2);
|
||||
TDA = (buff2end) & 0xfffff;
|
||||
|
||||
// Flag interrupt? If IRQA occurs between start and dest, flag it.
|
||||
// Important: Test both core IRQ settings for either DMA!
|
||||
// Note: Because this buffer wraps, we use || instead of &&
|
||||
|
||||
#if NO_BIOS_HACKFIX
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
// Start is exclusive and end is inclusive... maybe? The end is documented to be inclusive,
|
||||
|
@ -326,49 +305,34 @@ void V_Core::FinishDMAwrite()
|
|||
// understanding would trigger the interrupt early causing it to switch buffers again immediately
|
||||
// and an interrupt never fires again, leaving the voices looping the same samples forever.
|
||||
|
||||
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA || Cores[i].IRQA <= TDA))
|
||||
if (Cores[i].IRQEnable && (Cores[i].IRQA > start || Cores[i].IRQA <= TDA))
|
||||
{
|
||||
//ConLog("DMAwrite Core %d: IRQ Called (IRQ passed). IRQA = %x Cycles = %d\n", i, Cores[i].IRQA, Cycles );
|
||||
SetIrqCallDMA(i);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if ((IRQEnable && (IRQA > TSA || IRQA <= TDA))
|
||||
{
|
||||
SetIrqCall(Index);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// Buffer doesn't wrap/overflow!
|
||||
// Just set the TDA and check for an IRQ...
|
||||
|
||||
TDA = (buff1end) & 0xfffff;
|
||||
TDA = buff1end;
|
||||
|
||||
// Flag interrupt? If IRQA occurs between start and dest, flag it.
|
||||
// Important: Test both core IRQ settings for either DMA!
|
||||
|
||||
#if NO_BIOS_HACKFIX
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA && Cores[i].IRQA <= TDA))
|
||||
if (Cores[i].IRQEnable && (Cores[i].IRQA > ActiveTSA && Cores[i].IRQA <= TDA))
|
||||
{
|
||||
//ConLog("DMAwrite Core %d: IRQ Called (IRQ passed). IRQA = %x Cycles = %d\n", i, Cores[i].IRQA, Cycles );
|
||||
SetIrqCallDMA(i);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (IRQEnable && (IRQA > TSA) && (IRQA <= TDA))
|
||||
{
|
||||
SetIrqCall(Index);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TSA = TDA;
|
||||
DMAPtr += std::min(ReadSize, (u32)0x100);
|
||||
ReadSize -= std::min(ReadSize, (u32)0x100);
|
||||
DMAPtr += TDA - ActiveTSA;
|
||||
ReadSize -= TDA - ActiveTSA;
|
||||
if (ReadSize == 0)
|
||||
DMAICounter = 0;
|
||||
else
|
||||
|
@ -386,11 +350,17 @@ void V_Core::FinishDMAwrite()
|
|||
psxNextCounter = psxCounters[6].CycleT;
|
||||
}
|
||||
}
|
||||
ActiveTSA = TDA;
|
||||
ActiveTSA &= 0xfffff;
|
||||
TSA = ActiveTSA;
|
||||
}
|
||||
|
||||
void V_Core::FinishDMAread()
|
||||
{
|
||||
u32 buff1end = TSA + std::min(ReadSize, (u32)0x100);
|
||||
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;
|
||||
if (buff1end > 0x100000)
|
||||
{
|
||||
|
@ -398,8 +368,8 @@ void V_Core::FinishDMAread()
|
|||
buff1end = 0x100000;
|
||||
}
|
||||
|
||||
const u32 buff1size = (buff1end - TSA);
|
||||
memcpy(DMARPtr, GetMemPtr(TSA), buff1size * 2);
|
||||
const u32 buff1size = (buff1end - ActiveTSA);
|
||||
memcpy(DMARPtr, GetMemPtr(ActiveTSA), 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.
|
||||
|
@ -407,9 +377,16 @@ void V_Core::FinishDMAread()
|
|||
|
||||
if (buff2end > 0)
|
||||
{
|
||||
|
||||
TDA = buff1end;
|
||||
|
||||
DMARPtr += TDA - ActiveTSA;
|
||||
ReadSize -= TDA - ActiveTSA;
|
||||
ActiveTSA = 0;
|
||||
|
||||
// second branch needs cleared:
|
||||
// It starts at the beginning of memory and moves forward to buff2end
|
||||
memcpy(&DMARPtr[buff1size], GetMemPtr(0), buff2end * 2);
|
||||
memcpy(DMARPtr, GetMemPtr(0), buff2end * 2);
|
||||
|
||||
TDA = (buff2end) & 0xfffff;
|
||||
|
||||
|
@ -419,7 +396,7 @@ void V_Core::FinishDMAread()
|
|||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA || Cores[i].IRQA <= TDA))
|
||||
if (Cores[i].IRQEnable && (Cores[i].IRQA > start || Cores[i].IRQA <= TDA))
|
||||
{
|
||||
SetIrqCallDMA(i);
|
||||
}
|
||||
|
@ -430,23 +407,23 @@ void V_Core::FinishDMAread()
|
|||
// Buffer doesn't wrap/overflow!
|
||||
// Just set the TDA and check for an IRQ...
|
||||
|
||||
TDA = (buff1end) & 0xfffff;
|
||||
TDA = buff1end;
|
||||
|
||||
// Flag interrupt? If IRQA occurs between start and dest, flag it.
|
||||
// Important: Test both core IRQ settings for either DMA!
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (Cores[i].IRQEnable && (Cores[i].IRQA > TSA && Cores[i].IRQA <= TDA))
|
||||
if (Cores[i].IRQEnable && (Cores[i].IRQA > ActiveTSA && Cores[i].IRQA <= TDA))
|
||||
{
|
||||
SetIrqCallDMA(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TSA = TDA;
|
||||
DMARPtr += std::min(ReadSize, (u32)0x100);
|
||||
ReadSize -= std::min(ReadSize, (u32)0x100);
|
||||
|
||||
DMARPtr += TDA - ActiveTSA;
|
||||
ReadSize -= TDA - ActiveTSA;
|
||||
if (ReadSize == 0)
|
||||
{
|
||||
IsDMARead = false;
|
||||
|
@ -467,6 +444,9 @@ void V_Core::FinishDMAread()
|
|||
psxNextCounter = psxCounters[6].CycleT;
|
||||
}
|
||||
}
|
||||
ActiveTSA = TDA;
|
||||
ActiveTSA &= 0xfffff;
|
||||
TSA = ActiveTSA;
|
||||
}
|
||||
|
||||
void V_Core::DoDMAread(u16* pMem, u32 size)
|
||||
|
@ -475,7 +455,7 @@ void V_Core::DoDMAread(u16* pMem, u32 size)
|
|||
TimeUpdate(*cyclePtr);
|
||||
|
||||
DMARPtr = pMem;
|
||||
TSA &= 0xfffff;
|
||||
ActiveTSA = TSA & 0xfffff;
|
||||
ReadSize = size;
|
||||
IsDMARead = true;
|
||||
LastClock = *cyclePtr;
|
||||
|
@ -498,7 +478,7 @@ void V_Core::DoDMAread(u16* pMem, u32 size)
|
|||
|
||||
if (MsgDMA())
|
||||
ConLog("* SPU2: DMA%c Read Transfer of %d bytes from %x (%02x %x %04x). IRQE = %d IRQA = %x \n",
|
||||
GetDmaIndexChar(), size << 1, TSA, DMABits, AutoDMACtrl, Regs.ATTR & 0xffff,
|
||||
GetDmaIndexChar(), size << 1, ActiveTSA, DMABits, AutoDMACtrl, Regs.ATTR & 0xffff,
|
||||
Cores[Index].IRQEnable, Cores[Index].IRQA);
|
||||
}
|
||||
|
||||
|
@ -529,13 +509,12 @@ void V_Core::DoDMAwrite(u16* pMem, u32 size)
|
|||
}
|
||||
}
|
||||
|
||||
TSA &= 0xfffff;
|
||||
ActiveTSA = TSA & 0xfffff;
|
||||
|
||||
bool adma_enable = ((AutoDMACtrl & (Index + 1)) == (Index + 1));
|
||||
|
||||
if (adma_enable)
|
||||
{
|
||||
TSA &= 0x1fff;
|
||||
StartADMAWrite(pMem, size);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -78,8 +78,8 @@ StereoOut32 V_Core::ReadInput_HiFi()
|
|||
#endif
|
||||
AdmaInProgress = 1;
|
||||
|
||||
TSA = (Index << 10) + InputPosRead;
|
||||
|
||||
ActiveTSA = (Index << 10) + InputPosRead;
|
||||
TSA = ActiveTSA;
|
||||
if (InputDataLeft < 0x200)
|
||||
{
|
||||
FileLog("[%10d] %s AutoDMA%c block end.\n", (Index == 1) ? "CDDA" : "SPDIF", Cycles, GetDmaIndexChar());
|
||||
|
@ -142,7 +142,7 @@ StereoOut32 V_Core::ReadInput()
|
|||
|
||||
InputPosRead++;
|
||||
|
||||
if (AutoDMACtrl & (Index + 1) && (InputPosRead == 0x180 || InputPosRead == 0x80))
|
||||
if (((AutoDMACtrl & (Index + 1)) || AdmaInProgress) && (InputPosRead == 0x100 || InputPosRead == 0x200))
|
||||
{
|
||||
AdmaInProgress = 0;
|
||||
if (InputDataLeft >= 0x200)
|
||||
|
@ -152,11 +152,12 @@ StereoOut32 V_Core::ReadInput()
|
|||
AutoDMAReadBuffer(0);
|
||||
|
||||
AdmaInProgress = 1;
|
||||
TSA = (Index << 10) + InputPosRead;
|
||||
|
||||
ActiveTSA = (Index << 10) + InputPosRead;
|
||||
TSA = ActiveTSA;
|
||||
if (InputDataLeft < 0x200)
|
||||
{
|
||||
AutoDMACtrl |= ~3;
|
||||
if((AutoDMACtrl & (Index + 1)))
|
||||
AutoDMACtrl |= ~3;
|
||||
|
||||
if (IsDevBuild)
|
||||
{
|
||||
|
|
|
@ -391,6 +391,7 @@ struct V_Core
|
|||
|
||||
u32 IRQA; // Interrupt Address
|
||||
u32 TSA; // DMA Transfer Start Address
|
||||
u32 ActiveTSA; // Active DMA TSA - Required for NFL 2k5 which overwrites it mid transfer
|
||||
|
||||
bool IRQEnable; // Interrupt Enable
|
||||
bool FxEnable; // Effect Enable
|
||||
|
@ -506,17 +507,19 @@ struct V_Core
|
|||
|
||||
__forceinline u16 DmaRead()
|
||||
{
|
||||
const u16 ret = (u16)spu2M_Read(TSA);
|
||||
++TSA;
|
||||
TSA &= 0xfffff;
|
||||
const u16 ret = (u16)spu2M_Read(ActiveTSA);
|
||||
++ActiveTSA;
|
||||
ActiveTSA &= 0xfffff;
|
||||
TSA = ActiveTSA;
|
||||
return ret;
|
||||
}
|
||||
|
||||
__forceinline void DmaWrite(u16 value)
|
||||
{
|
||||
spu2M_Write(TSA, value);
|
||||
++TSA;
|
||||
TSA &= 0xfffff;
|
||||
spu2M_Write(ActiveTSA, value);
|
||||
++ActiveTSA;
|
||||
ActiveTSA &= 0xfffff;
|
||||
TSA = ActiveTSA;
|
||||
}
|
||||
|
||||
void LogAutoDMA(FILE* fp);
|
||||
|
|
|
@ -134,6 +134,7 @@ void SPU2interruptDMA4()
|
|||
FileLog("[%10d] SPU2 interruptDMA4\n", Cycles);
|
||||
Cores[0].Regs.STATX |= 0x80;
|
||||
Cores[0].Regs.STATX &= ~0x400;
|
||||
Cores[0].TSA = Cores[0].ActiveTSA;
|
||||
}
|
||||
|
||||
void SPU2interruptDMA7()
|
||||
|
@ -141,6 +142,7 @@ void SPU2interruptDMA7()
|
|||
FileLog("[%10d] SPU2 interruptDMA7\n", Cycles);
|
||||
Cores[1].Regs.STATX |= 0x80;
|
||||
Cores[1].Regs.STATX &= ~0x400;
|
||||
Cores[1].TSA = Cores[1].ActiveTSA;
|
||||
}
|
||||
|
||||
void SPU2readDMA7Mem(u16* pMem, u32 size)
|
||||
|
@ -538,6 +540,14 @@ u16 SPU2read(u32 rmem)
|
|||
|
||||
if (omem == 0x1f9001AC)
|
||||
{
|
||||
Cores[core].ActiveTSA = Cores[core].TSA;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (Cores[i].IRQEnable && (Cores[i].IRQA == Cores[core].ActiveTSA))
|
||||
{
|
||||
SetIrqCall(i);
|
||||
}
|
||||
}
|
||||
ret = Cores[core].DmaRead();
|
||||
}
|
||||
else
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "Global.h"
|
||||
#include "Dma.h"
|
||||
#include "IopDma.h"
|
||||
#include "IopCommon.h"
|
||||
|
||||
#include "spu2.h" // needed until I figure out a nice solution for irqcallback dependencies.
|
||||
|
||||
|
@ -410,7 +411,7 @@ __forceinline void TimeUpdate(u32 cClocks)
|
|||
Cores[0].MADR += amt / 2;
|
||||
if (Cores[0].DMAICounter <= 0)
|
||||
{
|
||||
if (((Cores[0].AutoDMACtrl & 1) != 1))
|
||||
if (((Cores[0].AutoDMACtrl & 1) != 1) && Cores[0].ReadSize)
|
||||
{
|
||||
if (Cores[0].IsDMARead)
|
||||
Cores[0].FinishDMAread();
|
||||
|
@ -424,7 +425,7 @@ __forceinline void TimeUpdate(u32 cClocks)
|
|||
{
|
||||
//ConLog("* SPU2: Irq Called (%04x) at cycle %d.\n", Spdif.Info, Cycles);
|
||||
has_to_call_irq_dma[i] = false;
|
||||
if (!(Spdif.Info & (4 << i)))
|
||||
if (!(Spdif.Info & (4 << i)) && Cores[i].IRQEnable)
|
||||
{
|
||||
Spdif.Info |= (4 << i);
|
||||
if (!SPU2_dummy_callback)
|
||||
|
@ -441,6 +442,19 @@ __forceinline void TimeUpdate(u32 cClocks)
|
|||
SPU2interruptDMA4();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((psxCounters[6].sCycleT + psxCounters[6].CycleT) - psxRegs.cycle) > Cores[0].DMAICounter)
|
||||
{
|
||||
psxCounters[6].sCycleT = psxRegs.cycle;
|
||||
psxCounters[6].CycleT = Cores[0].DMAICounter;
|
||||
|
||||
psxNextCounter -= (psxRegs.cycle - psxNextsCounter);
|
||||
psxNextsCounter = psxRegs.cycle;
|
||||
if (psxCounters[6].CycleT < psxNextCounter)
|
||||
psxNextCounter = psxCounters[6].CycleT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Update DMA7 interrupt delay counter
|
||||
|
@ -452,7 +466,7 @@ __forceinline void TimeUpdate(u32 cClocks)
|
|||
Cores[1].MADR += amt / 2;
|
||||
if (Cores[1].DMAICounter <= 0)
|
||||
{
|
||||
if (((Cores[1].AutoDMACtrl & 2) != 2))
|
||||
if (((Cores[1].AutoDMACtrl & 2) != 2) && Cores[1].ReadSize)
|
||||
{
|
||||
if (Cores[1].IsDMARead)
|
||||
Cores[1].FinishDMAread();
|
||||
|
@ -466,7 +480,7 @@ __forceinline void TimeUpdate(u32 cClocks)
|
|||
{
|
||||
//ConLog("* SPU2: Irq Called (%04x) at cycle %d.\n", Spdif.Info, Cycles);
|
||||
has_to_call_irq_dma[i] = false;
|
||||
if (!(Spdif.Info & (4 << i)))
|
||||
if (!(Spdif.Info & (4 << i)) && Cores[i].IRQEnable)
|
||||
{
|
||||
Spdif.Info |= (4 << i);
|
||||
if (!SPU2_dummy_callback)
|
||||
|
@ -484,6 +498,19 @@ __forceinline void TimeUpdate(u32 cClocks)
|
|||
SPU2interruptDMA7();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((psxCounters[6].sCycleT + psxCounters[6].CycleT) - psxRegs.cycle) > Cores[1].DMAICounter)
|
||||
{
|
||||
psxCounters[6].sCycleT = psxRegs.cycle;
|
||||
psxCounters[6].CycleT = Cores[1].DMAICounter;
|
||||
|
||||
psxNextCounter -= (psxRegs.cycle - psxNextsCounter);
|
||||
psxNextsCounter = psxRegs.cycle;
|
||||
if (psxCounters[6].CycleT < psxNextCounter)
|
||||
psxNextCounter = psxCounters[6].CycleT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Update Mixing Progress
|
||||
|
@ -495,7 +522,7 @@ __forceinline void TimeUpdate(u32 cClocks)
|
|||
{
|
||||
//ConLog("* SPU2: Irq Called (%04x) at cycle %d.\n", Spdif.Info, Cycles);
|
||||
has_to_call_irq[i] = false;
|
||||
if (!(Spdif.Info & (4 << i)))
|
||||
if (!(Spdif.Info & (4 << i)) && Cores[i].IRQEnable)
|
||||
{
|
||||
Spdif.Info |= (4 << i);
|
||||
if (!SPU2_dummy_callback)
|
||||
|
@ -755,12 +782,13 @@ void V_Core::WriteRegPS1(u32 mem, u16 value)
|
|||
|
||||
case 0x1da6:
|
||||
TSA = map_spu1to2(value);
|
||||
//ConLog("SPU2 Setting TSA to %x \n", TSA);
|
||||
ConLog("SPU2 Setting TSA to %x \n", TSA);
|
||||
break;
|
||||
|
||||
case 0x1da8: // Spu Write to Memory
|
||||
//ConLog("SPU direct DMA Write. Current TSA = %x\n", TSA);
|
||||
if (Cores[0].IRQEnable && (Cores[0].IRQA <= Cores[0].TSA))
|
||||
Cores[0].ActiveTSA = Cores[0].TSA;
|
||||
if (Cores[0].IRQEnable && (Cores[0].IRQA <= Cores[0].ActiveTSA))
|
||||
{
|
||||
SetIrqCall(0);
|
||||
if (!SPU2_dummy_callback)
|
||||
|
@ -1029,6 +1057,7 @@ u16 V_Core::ReadRegPS1(u32 mem)
|
|||
//ConLog("SPU2 TSA read: 0x1da6 = %x , (TSA = %x)\n", value, TSA);
|
||||
break;
|
||||
case 0x1da8:
|
||||
ActiveTSA = TSA;
|
||||
value = DmaRead();
|
||||
show = false;
|
||||
break;
|
||||
|
@ -1217,10 +1246,10 @@ static void __fastcall RegWrite_Core(u16 value)
|
|||
|
||||
// Performance Note: The PS2 Bios uses this extensively right before booting games,
|
||||
// causing massive slowdown if we don't shortcut it here.
|
||||
|
||||
thiscore.ActiveTSA = thiscore.TSA;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (Cores[i].IRQEnable && (Cores[i].IRQA == thiscore.TSA))
|
||||
if (Cores[i].IRQEnable && (Cores[i].IRQA == thiscore.ActiveTSA))
|
||||
{
|
||||
SetIrqCall(i);
|
||||
}
|
||||
|
@ -1255,11 +1284,13 @@ static void __fastcall RegWrite_Core(u16 value)
|
|||
thiscore.RevBuffers.NeedsUpdated = true;
|
||||
}
|
||||
|
||||
if (!thiscore.DmaMode)
|
||||
if (!thiscore.DmaMode && !(thiscore.Regs.STATX & 0x400))
|
||||
thiscore.Regs.STATX &= ~0x80;
|
||||
else if(!oldDmaMode)
|
||||
else if(!oldDmaMode && thiscore.DmaMode)
|
||||
thiscore.Regs.STATX |= 0x80;
|
||||
|
||||
thiscore.ActiveTSA = thiscore.TSA;
|
||||
|
||||
if (value & 0x000E)
|
||||
{
|
||||
if (MsgToConsole())
|
||||
|
@ -1488,11 +1519,6 @@ static void __fastcall RegWrite_Core(u16 value)
|
|||
return;
|
||||
}
|
||||
thiscore.AutoDMACtrl = value;
|
||||
|
||||
if (value == 0)
|
||||
{
|
||||
thiscore.AdmaInProgress = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -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 = (0x9A16 << 16) | 0x0000;
|
||||
static const u32 g_SaveVersion = (0x9A17 << 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. :)
|
||||
|
|
Loading…
Reference in New Issue