More fiddling with Sif.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2490 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
arcum42 2010-01-23 04:52:15 +00:00
parent 92ddae17ce
commit 75cdc5b955
1 changed files with 80 additions and 55 deletions

View File

@ -34,35 +34,35 @@ void sifInit()
memzero(iopsifbusy); memzero(iopsifbusy);
} }
//General format of all the SIF#(EE/IOP)Dma functions is this:
//First, SIF#Dma does a while loop, calling SIF#EEDma if EE is active,
//and then calling SIF#IOPDma if IOP is active.
//
//What the EE function does is the following:
//Check if qwc <= 0. If it is, check if we have any data left to pull.
//If we don't, set EE not to be active, call CPU_INT, and get out of the loop.
//If we do, pass data from fifo to ee if sif 0, and to ee from fifo if sif 1.
//And if qwc > 0, we do much the same thing.
//
//The IOP function is similar:
//We check if counter <= 0. If it is, check if we have data left to pull.
//If we don't, set IOP not to be active, call PSX_INT, and get out of the loop.
//If we do, pass data from fifo to iop if sif 0, and to iop from fifo if sif 1.
//And if qwc > 0, we do much the same thing.
//
// And with the IOP function, counter would be 0 initially, so the initialization
// is done in the same section of code as the exit, which is odd.
//
// This is, of course, simplified, and more study of these functions is needed.
__forceinline void SIF0EEDma(int &cycles, int &psxCycles, bool &done) __forceinline void SIF0EEDma(int &cycles, int &psxCycles, bool &done)
{ {
int size = sif0dma->qwc;
if (dmacRegs->ctrl.STS == STS_SIF0) if (dmacRegs->ctrl.STS == STS_SIF0)
{ {
SIF_LOG("SIF0 stall control"); SIF_LOG("SIF0 stall control");
} }
if (size > 0) // If we're reading something continue to do so
{
tDMA_TAG *ptag;
int readSize = min(size, (sif0.fifo.size >> 2));
//SIF_LOG(" EE SIF doing transfer %04Xqw to %08X", readSize, sif0dma->madr); if (sif0dma->qwc <= 0)
SIF_LOG("----------- %lX of %lX", readSize << 2, size << 2);
ptag = safeDmaGetAddr(sif0dma, sif0dma->madr, DMAC_SIF0);
if (ptag == NULL) return;
sif0.fifo.read((u32*)ptag, readSize << 2);
// Clearing handled by vtlb memory protection and manual blocks.
//Cpu->Clear(sif0dma->madr, readSize*4);
cycles += readSize; // fixme : BIAS is factored in below
sif0dma->qwc -= readSize;
sif0dma->madr += readSize << 4;
}
if (sif0dma->qwc == 0)
{ {
// Stop if TIE & the IRQ are set, or at the end. // Stop if TIE & the IRQ are set, or at the end.
// Remind me to look closer at this. (the IRQ tag of a chcr?) // Remind me to look closer at this. (the IRQ tag of a chcr?)
@ -73,9 +73,10 @@ __forceinline void SIF0EEDma(int &cycles, int &psxCycles, bool &done)
else else
SIF_LOG(" EE SIF interrupt"); SIF_LOG(" EE SIF interrupt");
CPU_INT(5, cycles*BIAS);
eesifbusy[0] = false; eesifbusy[0] = false;
done = true; done = true;
CPU_INT(5, cycles*BIAS);
} }
else if (sif0.fifo.size >= 4) // Read a tag else if (sif0.fifo.size >= 4) // Read a tag
{ {
@ -110,6 +111,27 @@ __forceinline void SIF0EEDma(int &cycles, int &psxCycles, bool &done)
done = false; done = false;
} }
} }
if (sif0dma->qwc > 0) // If we're reading something continue to do so
{
tDMA_TAG *ptag;
int readSize = min((s32)sif0dma->qwc, (sif0.fifo.size >> 2));
//SIF_LOG(" EE SIF doing transfer %04Xqw to %08X", readSize, sif0dma->madr);
SIF_LOG("----------- %lX of %lX", readSize << 2, sif0dma->qwc << 2);
ptag = safeDmaGetAddr(sif0dma, sif0dma->madr, DMAC_SIF0);
if (ptag == NULL) return;
sif0.fifo.read((u32*)ptag, readSize << 2);
// Clearing handled by vtlb memory protection and manual blocks.
//Cpu->Clear(sif0dma->madr, readSize*4);
cycles += readSize; // fixme : BIAS is factored in below
sif0dma->qwc -= readSize;
sif0dma->madr += readSize << 4;
}
} }
__forceinline void SIF1EEDma(int &cycles, int &psxCycles, bool &done) __forceinline void SIF1EEDma(int &cycles, int &psxCycles, bool &done)
@ -120,13 +142,15 @@ __forceinline void SIF1EEDma(int &cycles, int &psxCycles, bool &done)
} }
// If there's no more to transfer. // If there's no more to transfer.
if (sif1dma->qwc == 0) if (sif1dma->qwc <= 0)
{ {
// If NORMAL mode or end of CHAIN then stop DMA. // If NORMAL mode or end of CHAIN then stop DMA.
if ((sif1dma->chcr.MOD == NORMAL_MODE) || sif1.end) if ((sif1dma->chcr.MOD == NORMAL_MODE) || sif1.end)
{ {
// Stop & signal interrupts on EE
SIF_LOG("EE SIF1 End %x", sif1.end); SIF_LOG("EE SIF1 End %x", sif1.end);
// Stop & signal interrupts on EE
sif1.end = 0;
eesifbusy[1] = false; eesifbusy[1] = false;
done = true; done = true;
@ -134,7 +158,6 @@ __forceinline void SIF1EEDma(int &cycles, int &psxCycles, bool &done)
// Other games reach like 50k cycles here, but the EE will long have given up by then and just retry. // Other games reach like 50k cycles here, but the EE will long have given up by then and just retry.
// (Cause of double interrupts on the EE) // (Cause of double interrupts on the EE)
CPU_INT(6, min( (int)(cycles*BIAS), 384 ) ); CPU_INT(6, min( (int)(cycles*BIAS), 384 ) );
sif1.end = 0;
} }
else else
{ {
@ -200,7 +223,8 @@ __forceinline void SIF1EEDma(int &cycles, int &psxCycles, bool &done)
} }
} }
} }
else
if (sif1dma->qwc > 0)
{ {
// There's some data ready to transfer into the fifo.. // There's some data ready to transfer into the fifo..
tDMA_TAG *pTag; tDMA_TAG *pTag;
@ -220,10 +244,11 @@ __forceinline void SIF1EEDma(int &cycles, int &psxCycles, bool &done)
__forceinline void SIF0IOPDma(int &cycles, int &psxCycles, bool &done) __forceinline void SIF0IOPDma(int &cycles, int &psxCycles, bool &done)
{ {
if (sif0.counter == 0) // If there's no more to transfer if (sif0.counter <= 0) // If there's no more to transfer
{ {
// What this is supposed to do is stop DMA if it is the end of a chain, an interrupt is called, or in normal mode. // What this is supposed to do is stop DMA if it is the end of a chain, an interrupt is called, or in normal mode.
// It currently doesn't check for normal mode. // It currently doesn't check for normal mode.
// (Further note: I'm not sure that it needs to check for normal mode.)
// //
// The old code for this was: // The old code for this was:
// if (sif0.sifData.data & 0xC0000000) // if (sif0.sifData.data & 0xC0000000)
@ -234,15 +259,14 @@ __forceinline void SIF0IOPDma(int &cycles, int &psxCycles, bool &done)
SIF_LOG(" IOP SIF Stopped"); SIF_LOG(" IOP SIF Stopped");
// Stop & signal interrupts on IOP // Stop & signal interrupts on IOP
sif0.data.data = 0;
iopsifbusy[0] = false; iopsifbusy[0] = false;
done = true;
// iop is 1/8th the clock rate of the EE and psxcycles is in words (not quadwords) // iop is 1/8th the clock rate of the EE and psxcycles is in words (not quadwords)
// So when we're all done, the equation looks like thus: // So when we're all done, the equation looks like thus:
//PSX_INT(IopEvt_SIF0, ( ( psxCycles*BIAS ) / 4 ) / 8); //PSX_INT(IopEvt_SIF0, ( ( psxCycles*BIAS ) / 4 ) / 8);
PSX_INT(IopEvt_SIF0, psxCycles); PSX_INT(IopEvt_SIF0, psxCycles);
sif0.data.data = 0;
done = true;
} }
else // Chain mode else // Chain mode
{ {
@ -266,8 +290,10 @@ __forceinline void SIF0IOPDma(int &cycles, int &psxCycles, bool &done)
done = false; done = false;
} }
} }
else // There's some data ready to transfer into the fifo..
if (sif0.counter > 0)
{ {
// There's some data ready to transfer into the fifo..
int wTransfer = min(sif0.counter, FIFO_SIF_W - sif0.fifo.size); // HW_DMA9_BCR >> 16; int wTransfer = min(sif0.counter, FIFO_SIF_W - sif0.fifo.size); // HW_DMA9_BCR >> 16;
SIF_LOG("+++++++++++ %lX of %lX", wTransfer, sif0.counter /*(HW_DMA9_BCR >> 16)*/); SIF_LOG("+++++++++++ %lX of %lX", wTransfer, sif0.counter /*(HW_DMA9_BCR >> 16)*/);
@ -282,23 +308,6 @@ __forceinline void SIF0IOPDma(int &cycles, int &psxCycles, bool &done)
__forceinline void SIF1IOPDma(int &cycles, int &psxCycles, bool &done) __forceinline void SIF1IOPDma(int &cycles, int &psxCycles, bool &done)
{ {
int size = sif1.counter;
if (size > 0) // If we're reading something, continue to do so.
{
int readSize = size;
if (readSize > sif1.fifo.size) readSize = sif1.fifo.size;
SIF_LOG(" IOP SIF doing transfer %04X to %08X", readSize, HW_DMA10_MADR);
sif1.fifo.read((u32*)iopPhysMem(HW_DMA10_MADR), readSize);
psxCpu->Clear(HW_DMA10_MADR, readSize);
psxCycles += readSize / 4; // fixme: should be / 16
sif1.counter = size - readSize;
HW_DMA10_MADR += readSize << 2;
}
if (sif1.counter <= 0) if (sif1.counter <= 0)
{ {
// Stop on tag IRQ or END // Stop on tag IRQ or END
@ -310,18 +319,20 @@ __forceinline void SIF1IOPDma(int &cycles, int &psxCycles, bool &done)
else else
SIF_LOG(" IOP SIF interrupt"); SIF_LOG(" IOP SIF interrupt");
// Stop & signal interrupts on IOP
sif1.tagMode = 0;
iopsifbusy[1] = false; iopsifbusy[1] = false;
done = true;
//Fixme ( voodoocycles ): //Fixme ( voodoocycles ):
//The *24 are needed for ecco the dolphin (CDVD hangs) and silver surfer (Pad not detected) //The *24 are needed for ecco the dolphin (CDVD hangs) and silver surfer (Pad not detected)
//Greater than *35 break rebooting when trying to play Tekken5 arcade history //Greater than *35 break rebooting when trying to play Tekken5 arcade history
//Total cycles over 1024 makes SIF too slow to keep up the sound stream in so3... //Total cycles over 1024 makes SIF too slow to keep up the sound stream in so3...
PSX_INT(IopEvt_SIF1, min ( (psxCycles * 24), 1024) ); PSX_INT(IopEvt_SIF1, min ( (psxCycles * 24), 1024) );
sif1.tagMode = 0;
done = true;
} }
else if (sif1.fifo.size >= 4) // Read a tag else if (sif1.fifo.size >= 4)
{ {
// Read a tag.
sif1.fifo.read((u32*)&sif1.data, 4); sif1.fifo.read((u32*)&sif1.data, 4);
SIF_LOG(" IOP SIF dest chain tag madr:%08X wc:%04X id:%X irq:%d", SIF_LOG(" IOP SIF dest chain tag madr:%08X wc:%04X id:%X irq:%d",
sif1.data.data & 0xffffff, sif1.data.words, DMA_TAG(sif1.data.data).ID, sif1.data.data & 0xffffff, sif1.data.words, DMA_TAG(sif1.data.data).ID,
@ -333,6 +344,20 @@ __forceinline void SIF1IOPDma(int &cycles, int &psxCycles, bool &done)
done = false; done = false;
} }
} }
if (sif1.counter > 0)
{
// If we're reading something, continue to do so.
const int readSize = min (sif1.counter, sif1.fifo.size);
SIF_LOG(" IOP SIF doing transfer %04X to %08X", readSize, HW_DMA10_MADR);
sif1.fifo.read((u32*)iopPhysMem(HW_DMA10_MADR), readSize);
psxCpu->Clear(HW_DMA10_MADR, readSize);
psxCycles += readSize / 4; // fixme: should be / 16
sif1.counter -= readSize;
HW_DMA10_MADR += readSize << 2;
}
} }
__forceinline void SIF0Dma() __forceinline void SIF0Dma()