diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index cdd6361b55..9f4b3cdf72 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -159,6 +159,8 @@ set(pcsx2Sources SaveState.cpp ShiftJisToUnicode.cpp Sif.cpp + Sif0.cpp + Sif1.cpp Sio.cpp SourceLog.cpp SPR.cpp diff --git a/pcsx2/Linux/pcsx2.cbp b/pcsx2/Linux/pcsx2.cbp index 5487cce122..5b4f680f78 100644 --- a/pcsx2/Linux/pcsx2.cbp +++ b/pcsx2/Linux/pcsx2.cbp @@ -295,6 +295,8 @@ + + diff --git a/pcsx2/Sif.cpp b/pcsx2/Sif.cpp index 8e1092095a..6da6f154ba 100644 --- a/pcsx2/Sif.cpp +++ b/pcsx2/Sif.cpp @@ -20,7 +20,7 @@ #include "IopCommon.h" #include "Sif.h" -static _sif sif0, sif1; +_sif sif0, sif1; bool eesifbusy[2] = { false, false }; extern bool iopsifbusy[2]; @@ -33,579 +33,6 @@ void sifInit() memzero(iopsifbusy); } -// Various read/write functions. Could probably be reduced. -static __forceinline bool SifEERead(int &cycles) -{ - const int readSize = min((s32)sif0dma->qwc, sif0.fifo.size >> 2); - //if (readSize <= 0) - //{ - tDMA_TAG *ptag; - - //SIF_LOG(" EE SIF doing transfer %04Xqw to %08X", readSize, sif0dma->madr); - SIF_LOG("----------- %lX of %lX", readSize << 2, sif0dma->qwc << 2); - - ptag = sif0dma->getAddr(sif0dma->madr, DMAC_SIF0); - if (ptag == NULL) - { - DevCon.Warning("SIFEERead: ptag == NULL"); - return false; - } - - sif0.fifo.read((u32*)ptag, readSize << 2); - - // Clearing handled by vtlb memory protection and manual blocks. - //Cpu->Clear(sif0dma->madr, readSize*4); - - sif0dma->madr += readSize << 4; - cycles += readSize; // fixme : BIAS is factored in above - sif0dma->qwc -= readSize; - //} - //else - //{ - //DevCon.Warning("SifEERead readSize is 0"); - // return false; - //} - return true; -} - -static __forceinline bool SifEEWrite(int &cycles) -{ - // There's some data ready to transfer into the fifo.. - - const int writeSize = min((s32)sif1dma->qwc, sif1.fifo.free() >> 2); - //if (writeSize <= 0) - //{ - //DevCon.Warning("SifEEWrite writeSize is 0"); - // return false; - //} - //else - //{ - tDMA_TAG *ptag; - - ptag = sif1dma->getAddr(sif1dma->madr, DMAC_SIF1); - if (ptag == NULL) - { - DevCon.Warning("SIFEEWrite: ptag == NULL"); - return false; - } - - sif1.fifo.write((u32*)ptag, writeSize << 2); - - sif1dma->madr += writeSize << 4; - cycles += writeSize; // fixme : BIAS is factored in above - sif1dma->qwc -= writeSize; - //} - return true; -} - -static __forceinline bool SifIOPWrite(int &psxCycles) -{ - // There's some data ready to transfer into the fifo.. - const int writeSize = min(sif0.counter, sif0.fifo.free()); - - //if (writeSize <= 0) - //{ - //DevCon.Warning("SifIOPWrite writeSize is 0"); - // return false; - //} - //else - //{ - SIF_LOG("+++++++++++ %lX of %lX", writeSize, sif0.counter); - - sif0.fifo.write((u32*)iopPhysMem(hw_dma(9).madr), writeSize); - hw_dma(9).madr += writeSize << 2; - psxCycles += (writeSize >> 2) * BIAS; // fixme : should be >> 4 - sif0.counter -= writeSize; - //} - return true; -} - -static __forceinline bool SifIOPRead(int &psxCycles) -{ - // If we're reading something, continue to do so. - const int readSize = min (sif1.counter, sif1.fifo.size); - //if (readSize <= 0) - //{ - //DevCon.Warning("SifIOPRead readSize is 0"); - // return false; - //} - //else - //{ - SIF_LOG(" IOP SIF doing transfer %04X to %08X", readSize, HW_DMA10_MADR); - - sif1.fifo.read((u32*)iopPhysMem(hw_dma(10).madr), readSize); - psxCpu->Clear(hw_dma(10).madr, readSize); - hw_dma(10).madr += readSize << 2; - psxCycles += readSize >> 2; // fixme: should be / 16 - sif1.counter -= readSize; - //} - return true; -} - -static __forceinline bool SIFEEReadTag() -{ - static __aligned16 u32 tag[4]; - - sif0.fifo.read((u32*)&tag[0], 4); // Tag - SIF_LOG(" EE SIF read tag: %x %x %x %x", tag[0], tag[1], tag[2], tag[3]); - - sif0dma->unsafeTransfer(((tDMA_TAG*)(tag))); - sif0dma->madr = tag[1]; - tDMA_TAG ptag(tag[0]); - - SIF_LOG(" EE SIF dest chain tag madr:%08X qwc:%04X id:%X irq:%d(%08X_%08X)", - sif0dma->madr, sif0dma->qwc, ptag.ID, ptag.IRQ, tag[1], tag[0]); - - if (sif0dma->chcr.TIE && ptag.IRQ) - { - //Console.WriteLn("SIF0 TIE"); - sif0.end = 1; - } - - switch (ptag.ID) - { - case TAG_REFE: - sif0.end = 1; - if (dmacRegs->ctrl.STS != NO_STS) - dmacRegs->stadr.ADDR = sif0dma->madr + (sif0dma->qwc * 16); - break; - - case TAG_REFS: - if (dmacRegs->ctrl.STS != NO_STS) - dmacRegs->stadr.ADDR = sif0dma->madr + (sif0dma->qwc * 16); - break; - - case TAG_END: - sif0.end = 1; - break; - } - return true; -} - -static __forceinline bool SIFEEWriteTag() -{ - // Chain mode - tDMA_TAG *ptag; - - // Process DMA tag at sif1dma->tadr - ptag = sif1dma->DMAtransfer(sif1dma->tadr, DMAC_SIF1); - if (ptag == NULL) - { - Console.WriteLn("SIF1EEDma: ptag = NULL"); - return false; - } - - if (sif1dma->chcr.TTE) - { - Console.WriteLn("SIF1 TTE"); - sif1.fifo.write((u32*)ptag + 2, 2); - } - - if (sif1dma->chcr.TIE && ptag->IRQ) - { - Console.WriteLn("SIF1 TIE"); - sif1.end = 1; - } - - switch (ptag->ID) - { - case TAG_REFE: // refe - SIF_LOG(" REFE %08X", ptag[1]._u32); - sif1.end = 1; - sif1dma->madr = ptag[1]._u32; - sif1dma->tadr += 16; - break; - - case TAG_CNT: // cnt - SIF_LOG(" CNT"); - sif1dma->madr = sif1dma->tadr + 16; - sif1dma->tadr = sif1dma->madr + (sif1dma->qwc << 4); - break; - - case TAG_NEXT: // next - SIF_LOG(" NEXT %08X", ptag[1]._u32); - sif1dma->madr = sif1dma->tadr + 16; - sif1dma->tadr = ptag[1]._u32; - break; - - case TAG_REF: // ref - case TAG_REFS: // refs - SIF_LOG(" REF %08X", ptag[1]._u32); - sif1dma->madr = ptag[1]._u32; - sif1dma->tadr += 16; - break; - - case TAG_END: // end - SIF_LOG(" END"); - sif1.end = 1; - sif1dma->madr = sif1dma->tadr + 16; - sif1dma->tadr = sif1dma->madr + (sif1dma->qwc << 4); - break; - - default: - Console.WriteLn("Bad addr1 source chain"); - } - return true; -} - -static __forceinline bool SIFIOPWriteTag() -{ - // Process DMA tag at HW_DMA9_TADR - sif0.data = *(sifData *)iopPhysMem(hw_dma(9).tadr); - sif0.data.words = (sif0.data.words + 3) & 0xfffffffc; // Round up to nearest 4. - sif0.fifo.write((u32*)iopPhysMem(hw_dma(9).tadr + 8), 4); - - hw_dma(9).tadr += 16; ///hw_dma(9).madr + 16 + sif0.sifData.words << 2; - hw_dma(9).madr = sif0.data.data & 0xFFFFFF; - sif0.counter = sif0.data.words & 0xFFFFFF; - - SIF_LOG(" SIF0 Tag: madr=%lx, tadr=%lx, counter=%lx (%08X_%08X)", HW_DMA9_MADR, HW_DMA9_TADR, sif0.counter, sif0.data.words, sif0.data.data); - - return true; -} - -static __forceinline bool SIFIOPReadTag() -{ - // Read a tag. - sif1.fifo.read((u32*)&sif1.data, 4); - 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, - DMA_TAG(sif1.data.data).IRQ); - - hw_dma(10).madr = sif1.data.data & 0xffffff; - sif1.counter = sif1.data.words; - return true; -} - -static __forceinline void SIF0EEend(int &cycles) -{ - // Stop & signal interrupts on EE - sif0.end = 0; - eesifbusy[0] = false; - if (cycles == 0) DevCon.Warning("EESIF0cycles = 0"); // No transfer happened - else CPU_INT(DMAC_SIF0, cycles*BIAS); // Hence no Interrupt -} - -static __forceinline void SIF1EEend(int &cycles) -{ - // Stop & signal interrupts on EE - sif1.end = 0; - eesifbusy[1] = false; - - // Voodoocycles : Okami wants around 100 cycles when booting up - // 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) - if (cycles == 0) DevCon.Warning("EESIF1cycles = 0"); // No transfer happened - else CPU_INT(DMAC_SIF1, min((int)(cycles*BIAS), 384)); // Hence no Interrupt (fixes Eternal Poison reboot when selecting new game) -} - -static __forceinline void SIF0IOPend(int &psxCycles) -{ - // Stop & signal interrupts on IOP - sif0.data.data = 0; - iopsifbusy[0] = false; - - // 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: - //PSX_INT(IopEvt_SIF0, ( ( psxCycles*BIAS ) / 4 ) / 8); - if (psxCycles == 0) DevCon.Warning("IOPSIF0cycles = 0"); // No transfer happened - else PSX_INT(IopEvt_SIF0, psxCycles); // Hence no Interrupt -} - -static __forceinline void SIF1IOPend(int &psxCycles) -{ - // Stop & signal interrupts on IOP - sif1.data.data = 0; - iopsifbusy[1] = false; - - //Fixme ( voodoocycles ): - //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 - //Total cycles over 1024 makes SIF too slow to keep up the sound stream in so3... - if (psxCycles == 0) DevCon.Warning("IOPSIF1cycles = 0"); // No transfer happened - else PSX_INT(IopEvt_SIF1, min((psxCycles * 26), 1024)); // Hence no Interrupt -} - -//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. - -static __forceinline void SIF0EEDma(int &cycles, bool &done) -{ -#ifdef PCSX2_DEVBUILD - if (dmacRegs->ctrl.STS == STS_SIF0) - { - SIF_LOG("SIF0 stall control"); - } -#endif - - if (sif0dma->qwc <= 0) - { - if ((sif0dma->chcr.MOD == NORMAL_MODE) || sif0.end) - { - done = true; - SIF0EEend(cycles); - } - else if (sif0.fifo.size >= 4) // Read a tag - { - done = false; - SIFEEReadTag(); - } - } - - if (sif0dma->qwc > 0) // If we're reading something continue to do so - { - SifEERead(cycles); - } -} - -static __forceinline void SIF1EEDma(int &cycles, bool &done) -{ -#ifdef PCSX2_DEVBUILD - if (dmacRegs->ctrl.STD == STD_SIF1) - { - SIF_LOG("SIF1 stall control"); // STD == fromSIF1 - } -#endif - - // If there's no more to transfer. - if (sif1dma->qwc <= 0) - { - // If NORMAL mode or end of CHAIN then stop DMA. - if ((sif1dma->chcr.MOD == NORMAL_MODE) || sif1.end) - { - done = true; - SIF1EEend(cycles); - } - else - { - done = false; - if (!SIFEEWriteTag()) return; - } - } - else - { - SifEEWrite(cycles); - } -} - -// Note: Test any changes in this function against Grandia III. -static __forceinline void SIF0IOPDma(int &psxCycles, bool &done) -{ - if (sif0.counter <= 0) // If there's no more to transfer - { - if (sif0_tag.IRQ || (sif0_tag.ID & 4)) - { - done = true; - SIF0IOPend(psxCycles); - } - else // Chain mode - { - done = false; - SIFIOPWriteTag(); - } - } - else - { - SifIOPWrite(psxCycles); - } -} - -static __forceinline void SIF1IOPDma(int &psxCycles, bool &done) -{ - if (sif1.counter > 0) - { - SifIOPRead(psxCycles); - } - - if (sif1.counter <= 0) - { - if (sif1_tag.IRQ || (sif1_tag.ID & 4)) - { - done = true; - SIF1IOPend(psxCycles); - } - else if (sif1.fifo.size >= 4) - { - - done = false; - SIFIOPReadTag(); - } - } -} - -// Tests if iop & ee are busy before the while statement, -// instead of during it, on the premise that anything that -// changes the busy state in here also ends the while statement. -// -// Mostly works, but breaks the Mana Khemia opening movie. -// Not sure if it's worth keeping yet. -//#define NO_BUSY_TEST -__forceinline void SIF0Dma() -{ - bool done = false; - int cycles = 0, psxCycles = 0; - - SIF_LOG("SIF0 DMA start..."); - -#ifdef NO_BUSY_TEST - if ((iopsifbusy[0]) && (eesifbusy[0])) - { - do - { - SIF0IOPDma(psxCycles, done); - SIF0EEDma(cycles, done); - } while (!done); - } - else if (iopsifbusy[0]) - { - do - { - SIF0IOPDma(psxCycles, done); - } while (!done); - } - else - { - do - { - SIF0EEDma(cycles, done); - } while (!done); - } -#else - do - { - if (iopsifbusy[0]) SIF0IOPDma(psxCycles, done); - if (eesifbusy[0]) SIF0EEDma(cycles, done); - } while (!done); -#endif -} - -__forceinline void SIF1Dma() -{ - bool done = false; - int cycles = 0, psxCycles = 0; - -#ifdef NO_BUSY_TEST - if ((iopsifbusy[1]) && (eesifbusy[1])) - { - do - { - SIF1EEDma(cycles, done); - SIF1IOPDma(psxCycles, done); - } while (!done); - } - else if (iopsifbusy[1]) - { - do - { - SIF1IOPDma(psxCycles, done); - } while (!done); - } - else - { - do - { - SIF1EEDma(cycles, done); - } while (!done); - } -#else - do - { - if (eesifbusy[1]) SIF1EEDma(cycles, done); - if (iopsifbusy[1]) SIF1IOPDma(psxCycles, done); - - } while (!done); -#endif -} - -__forceinline void sif0Interrupt() -{ - HW_DMA9_CHCR &= ~0x01000000; - psxDmaInterrupt2(2); -} - -__forceinline void sif1Interrupt() -{ - HW_DMA10_CHCR &= ~0x01000000; //reset TR flag - psxDmaInterrupt2(3); -} - -__forceinline void EEsif0Interrupt() -{ - hwDmacIrq(DMAC_SIF0); - sif0dma->chcr.STR = false; -} - -__forceinline void EEsif1Interrupt() -{ - hwDmacIrq(DMAC_SIF1); - sif1dma->chcr.STR = false; -} - -__forceinline void dmaSIF0() -{ - SIF_LOG(wxString(L"dmaSIF0" + sif0dma->cmqt_to_str()).To8BitData()); - - if (sif0.fifo.readPos != sif0.fifo.writePos) - { - SIF_LOG("warning, sif0.fifoReadPos != sif0.fifoWritePos"); - } - - psHu32(SBUS_F240) |= 0x2000; - eesifbusy[0] = true; - - if (iopsifbusy[0]) - { - XMMRegisters::Freeze(); - hwIntcIrq(INTC_SBUS); - SIF0Dma(); - psHu32(SBUS_F240) &= ~0x20; - psHu32(SBUS_F240) &= ~0x2000; - XMMRegisters::Thaw(); - } -} - -__forceinline void dmaSIF1() -{ - SIF_LOG(wxString(L"dmaSIF1" + sif1dma->cmqt_to_str()).To8BitData()); - - if (sif1.fifo.readPos != sif1.fifo.writePos) - { - SIF_LOG("warning, sif1.fifoReadPos != sif1.fifoWritePos"); - } - - psHu32(SBUS_F240) |= 0x4000; - eesifbusy[1] = true; - - if (iopsifbusy[1]) - { - XMMRegisters::Freeze(); - SIF1Dma(); - psHu32(SBUS_F240) &= ~0x40; - psHu32(SBUS_F240) &= ~0x100; - psHu32(SBUS_F240) &= ~0x4000; - XMMRegisters::Thaw(); - } - -} - __forceinline void dmaSIF2() { SIF_LOG(wxString(L"dmaSIF2" + sif2dma->cmq_to_str()).To8BitData()); diff --git a/pcsx2/Sif.h b/pcsx2/Sif.h index 6487d43fb9..cfbde7c392 100644 --- a/pcsx2/Sif.h +++ b/pcsx2/Sif.h @@ -80,6 +80,10 @@ struct _sif s32 counter; struct sifData data; }; +extern _sif sif0, sif1; + +extern bool eesifbusy[2]; +extern bool iopsifbusy[2]; extern void sifInit(); diff --git a/pcsx2/Sif0.cpp b/pcsx2/Sif0.cpp new file mode 100644 index 0000000000..324736ba5e --- /dev/null +++ b/pcsx2/Sif0.cpp @@ -0,0 +1,255 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2009 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" + +#define _PC_ // disables MIPS opcode macros. + +#include "IopCommon.h" +#include "Sif.h" + +static __forceinline bool SifEERead(int &cycles) +{ + const int readSize = min((s32)sif0dma->qwc, sif0.fifo.size >> 2); + //if (readSize <= 0) + //{ + tDMA_TAG *ptag; + + //SIF_LOG(" EE SIF doing transfer %04Xqw to %08X", readSize, sif0dma->madr); + SIF_LOG("----------- %lX of %lX", readSize << 2, sif0dma->qwc << 2); + + ptag = sif0dma->getAddr(sif0dma->madr, DMAC_SIF0); + if (ptag == NULL) + { + DevCon.Warning("SIFEERead: ptag == NULL"); + return false; + } + + sif0.fifo.read((u32*)ptag, readSize << 2); + + // Clearing handled by vtlb memory protection and manual blocks. + //Cpu->Clear(sif0dma->madr, readSize*4); + + sif0dma->madr += readSize << 4; + cycles += readSize; // fixme : BIAS is factored in above + sif0dma->qwc -= readSize; + //} + //else + //{ + //DevCon.Warning("SifEERead readSize is 0"); + // return false; + //} + return true; +} + +static __forceinline bool SifIOPWrite(int &psxCycles) +{ + // There's some data ready to transfer into the fifo.. + const int writeSize = min(sif0.counter, sif0.fifo.free()); + + //if (writeSize <= 0) + //{ + //DevCon.Warning("SifIOPWrite writeSize is 0"); + // return false; + //} + //else + //{ + SIF_LOG("+++++++++++ %lX of %lX", writeSize, sif0.counter); + + sif0.fifo.write((u32*)iopPhysMem(hw_dma(9).madr), writeSize); + hw_dma(9).madr += writeSize << 2; + psxCycles += (writeSize >> 2) * BIAS; // fixme : should be >> 4 + sif0.counter -= writeSize; + //} + return true; +} + +static __forceinline bool SIFEEReadTag() +{ + static __aligned16 u32 tag[4]; + + sif0.fifo.read((u32*)&tag[0], 4); // Tag + SIF_LOG(" EE SIF read tag: %x %x %x %x", tag[0], tag[1], tag[2], tag[3]); + + sif0dma->unsafeTransfer(((tDMA_TAG*)(tag))); + sif0dma->madr = tag[1]; + tDMA_TAG ptag(tag[0]); + + SIF_LOG(" EE SIF dest chain tag madr:%08X qwc:%04X id:%X irq:%d(%08X_%08X)", + sif0dma->madr, sif0dma->qwc, ptag.ID, ptag.IRQ, tag[1], tag[0]); + + if (sif0dma->chcr.TIE && ptag.IRQ) + { + //Console.WriteLn("SIF0 TIE"); + sif0.end = 1; + } + + switch (ptag.ID) + { + case TAG_REFE: + sif0.end = 1; + if (dmacRegs->ctrl.STS != NO_STS) + dmacRegs->stadr.ADDR = sif0dma->madr + (sif0dma->qwc * 16); + break; + + case TAG_REFS: + if (dmacRegs->ctrl.STS != NO_STS) + dmacRegs->stadr.ADDR = sif0dma->madr + (sif0dma->qwc * 16); + break; + + case TAG_END: + sif0.end = 1; + break; + } + return true; +} + +static __forceinline bool SIFIOPWriteTag() +{ + // Process DMA tag at HW_DMA9_TADR + sif0.data = *(sifData *)iopPhysMem(hw_dma(9).tadr); + sif0.data.words = (sif0.data.words + 3) & 0xfffffffc; // Round up to nearest 4. + sif0.fifo.write((u32*)iopPhysMem(hw_dma(9).tadr + 8), 4); + + hw_dma(9).tadr += 16; ///hw_dma(9).madr + 16 + sif0.sifData.words << 2; + hw_dma(9).madr = sif0.data.data & 0xFFFFFF; + sif0.counter = sif0.data.words & 0xFFFFFF; + + SIF_LOG(" SIF0 Tag: madr=%lx, tadr=%lx, counter=%lx (%08X_%08X)", HW_DMA9_MADR, HW_DMA9_TADR, sif0.counter, sif0.data.words, sif0.data.data); + + return true; +} + +static __forceinline void SIF0EEend(int &cycles) +{ + // Stop & signal interrupts on EE + sif0.end = 0; + eesifbusy[0] = false; + if (cycles == 0) DevCon.Warning("EESIF0cycles = 0"); // No transfer happened + else CPU_INT(DMAC_SIF0, cycles*BIAS); // Hence no Interrupt +} + +static __forceinline void SIF0IOPend(int &psxCycles) +{ + // Stop & signal interrupts on IOP + sif0.data.data = 0; + iopsifbusy[0] = false; + + // 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: + //PSX_INT(IopEvt_SIF0, ( ( psxCycles*BIAS ) / 4 ) / 8); + if (psxCycles == 0) DevCon.Warning("IOPSIF0cycles = 0"); // No transfer happened + else PSX_INT(IopEvt_SIF0, psxCycles); // Hence no Interrupt +} + +static __forceinline void SIF0EEDma(int &cycles, bool &done) +{ +#ifdef PCSX2_DEVBUILD + if (dmacRegs->ctrl.STS == STS_SIF0) + { + SIF_LOG("SIF0 stall control"); + } +#endif + + if (sif0dma->qwc <= 0) + { + if ((sif0dma->chcr.MOD == NORMAL_MODE) || sif0.end) + { + done = true; + SIF0EEend(cycles); + } + else if (sif0.fifo.size >= 4) // Read a tag + { + done = false; + SIFEEReadTag(); + } + } + + if (sif0dma->qwc > 0) // If we're reading something continue to do so + { + SifEERead(cycles); + } +} + +// Note: Test any changes in this function against Grandia III. +static __forceinline void SIF0IOPDma(int &psxCycles, bool &done) +{ + if (sif0.counter <= 0) // If there's no more to transfer + { + if (sif0_tag.IRQ || (sif0_tag.ID & 4)) + { + done = true; + SIF0IOPend(psxCycles); + } + else // Chain mode + { + done = false; + SIFIOPWriteTag(); + } + } + else + { + SifIOPWrite(psxCycles); + } +} + +__forceinline void SIF0Dma() +{ + bool done = false; + int cycles = 0, psxCycles = 0; + + SIF_LOG("SIF0 DMA start..."); + + do + { + if (iopsifbusy[0]) SIF0IOPDma(psxCycles, done); + if (eesifbusy[0]) SIF0EEDma(cycles, done); + } while (!done); +} + +__forceinline void sif0Interrupt() +{ + HW_DMA9_CHCR &= ~0x01000000; + psxDmaInterrupt2(2); +} + +__forceinline void EEsif0Interrupt() +{ + hwDmacIrq(DMAC_SIF0); + sif0dma->chcr.STR = false; +} + +__forceinline void dmaSIF0() +{ + SIF_LOG(wxString(L"dmaSIF0" + sif0dma->cmqt_to_str()).To8BitData()); + + if (sif0.fifo.readPos != sif0.fifo.writePos) + { + SIF_LOG("warning, sif0.fifoReadPos != sif0.fifoWritePos"); + } + + psHu32(SBUS_F240) |= 0x2000; + eesifbusy[0] = true; + + if (iopsifbusy[0]) + { + XMMRegisters::Freeze(); + hwIntcIrq(INTC_SBUS); + SIF0Dma(); + psHu32(SBUS_F240) &= ~0x20; + psHu32(SBUS_F240) &= ~0x2000; + XMMRegisters::Thaw(); + } +} diff --git a/pcsx2/Sif1.cpp b/pcsx2/Sif1.cpp new file mode 100644 index 0000000000..a41e9f1e11 --- /dev/null +++ b/pcsx2/Sif1.cpp @@ -0,0 +1,280 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2009 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" + +#define _PC_ // disables MIPS opcode macros. + +#include "IopCommon.h" +#include "Sif.h" + +static __forceinline bool SifEEWrite(int &cycles) +{ + // There's some data ready to transfer into the fifo.. + + const int writeSize = min((s32)sif1dma->qwc, sif1.fifo.free() >> 2); + //if (writeSize <= 0) + //{ + //DevCon.Warning("SifEEWrite writeSize is 0"); + // return false; + //} + //else + //{ + tDMA_TAG *ptag; + + ptag = sif1dma->getAddr(sif1dma->madr, DMAC_SIF1); + if (ptag == NULL) + { + DevCon.Warning("SIFEEWrite: ptag == NULL"); + return false; + } + + sif1.fifo.write((u32*)ptag, writeSize << 2); + + sif1dma->madr += writeSize << 4; + cycles += writeSize; // fixme : BIAS is factored in above + sif1dma->qwc -= writeSize; + //} + return true; +} + +static __forceinline bool SifIOPRead(int &psxCycles) +{ + // If we're reading something, continue to do so. + const int readSize = min (sif1.counter, sif1.fifo.size); + //if (readSize <= 0) + //{ + //DevCon.Warning("SifIOPRead readSize is 0"); + // return false; + //} + //else + //{ + SIF_LOG(" IOP SIF doing transfer %04X to %08X", readSize, HW_DMA10_MADR); + + sif1.fifo.read((u32*)iopPhysMem(hw_dma(10).madr), readSize); + psxCpu->Clear(hw_dma(10).madr, readSize); + hw_dma(10).madr += readSize << 2; + psxCycles += readSize >> 2; // fixme: should be / 16 + sif1.counter -= readSize; + //} + return true; +} + +static __forceinline bool SIFEEWriteTag() +{ + // Chain mode + tDMA_TAG *ptag; + + // Process DMA tag at sif1dma->tadr + ptag = sif1dma->DMAtransfer(sif1dma->tadr, DMAC_SIF1); + if (ptag == NULL) + { + Console.WriteLn("SIF1EEDma: ptag = NULL"); + return false; + } + + if (sif1dma->chcr.TTE) + { + Console.WriteLn("SIF1 TTE"); + sif1.fifo.write((u32*)ptag + 2, 2); + } + + if (sif1dma->chcr.TIE && ptag->IRQ) + { + Console.WriteLn("SIF1 TIE"); + sif1.end = 1; + } + + switch (ptag->ID) + { + case TAG_REFE: // refe + SIF_LOG(" REFE %08X", ptag[1]._u32); + sif1.end = 1; + sif1dma->madr = ptag[1]._u32; + sif1dma->tadr += 16; + break; + + case TAG_CNT: // cnt + SIF_LOG(" CNT"); + sif1dma->madr = sif1dma->tadr + 16; + sif1dma->tadr = sif1dma->madr + (sif1dma->qwc << 4); + break; + + case TAG_NEXT: // next + SIF_LOG(" NEXT %08X", ptag[1]._u32); + sif1dma->madr = sif1dma->tadr + 16; + sif1dma->tadr = ptag[1]._u32; + break; + + case TAG_REF: // ref + case TAG_REFS: // refs + SIF_LOG(" REF %08X", ptag[1]._u32); + sif1dma->madr = ptag[1]._u32; + sif1dma->tadr += 16; + break; + + case TAG_END: // end + SIF_LOG(" END"); + sif1.end = 1; + sif1dma->madr = sif1dma->tadr + 16; + sif1dma->tadr = sif1dma->madr + (sif1dma->qwc << 4); + break; + + default: + Console.WriteLn("Bad addr1 source chain"); + } + return true; +} + +static __forceinline bool SIFIOPReadTag() +{ + // Read a tag. + sif1.fifo.read((u32*)&sif1.data, 4); + 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, + DMA_TAG(sif1.data.data).IRQ); + + hw_dma(10).madr = sif1.data.data & 0xffffff; + sif1.counter = sif1.data.words; + return true; +} + +static __forceinline void SIF1EEend(int &cycles) +{ + // Stop & signal interrupts on EE + sif1.end = 0; + eesifbusy[1] = false; + + // Voodoocycles : Okami wants around 100 cycles when booting up + // 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) + if (cycles == 0) DevCon.Warning("EESIF1cycles = 0"); // No transfer happened + else CPU_INT(DMAC_SIF1, min((int)(cycles*BIAS), 384)); // Hence no Interrupt (fixes Eternal Poison reboot when selecting new game) +} + +static __forceinline void SIF1IOPend(int &psxCycles) +{ + // Stop & signal interrupts on IOP + sif1.data.data = 0; + iopsifbusy[1] = false; + + //Fixme ( voodoocycles ): + //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 + //Total cycles over 1024 makes SIF too slow to keep up the sound stream in so3... + if (psxCycles == 0) DevCon.Warning("IOPSIF1cycles = 0"); // No transfer happened + else PSX_INT(IopEvt_SIF1, min((psxCycles * 26), 1024)); // Hence no Interrupt +} + +static __forceinline void SIF1EEDma(int &cycles, bool &done) +{ +#ifdef PCSX2_DEVBUILD + if (dmacRegs->ctrl.STD == STD_SIF1) + { + SIF_LOG("SIF1 stall control"); // STD == fromSIF1 + } +#endif + + // If there's no more to transfer. + if (sif1dma->qwc <= 0) + { + // If NORMAL mode or end of CHAIN then stop DMA. + if ((sif1dma->chcr.MOD == NORMAL_MODE) || sif1.end) + { + done = true; + SIF1EEend(cycles); + } + else + { + done = false; + if (!SIFEEWriteTag()) return; + } + } + else + { + SifEEWrite(cycles); + } +} + +static __forceinline void SIF1IOPDma(int &psxCycles, bool &done) +{ + if (sif1.counter > 0) + { + SifIOPRead(psxCycles); + } + + if (sif1.counter <= 0) + { + if (sif1_tag.IRQ || (sif1_tag.ID & 4)) + { + done = true; + SIF1IOPend(psxCycles); + } + else if (sif1.fifo.size >= 4) + { + + done = false; + SIFIOPReadTag(); + } + } +} + +__forceinline void SIF1Dma() +{ + bool done = false; + int cycles = 0, psxCycles = 0; + + do + { + if (eesifbusy[1]) SIF1EEDma(cycles, done); + if (iopsifbusy[1]) SIF1IOPDma(psxCycles, done); + + } while (!done); +} + +__forceinline void sif1Interrupt() +{ + HW_DMA10_CHCR &= ~0x01000000; //reset TR flag + psxDmaInterrupt2(3); +} + +__forceinline void EEsif1Interrupt() +{ + hwDmacIrq(DMAC_SIF1); + sif1dma->chcr.STR = false; +} + +__forceinline void dmaSIF1() +{ + SIF_LOG(wxString(L"dmaSIF1" + sif1dma->cmqt_to_str()).To8BitData()); + + if (sif1.fifo.readPos != sif1.fifo.writePos) + { + SIF_LOG("warning, sif1.fifoReadPos != sif1.fifoWritePos"); + } + + psHu32(SBUS_F240) |= 0x4000; + eesifbusy[1] = true; + + if (iopsifbusy[1]) + { + XMMRegisters::Freeze(); + SIF1Dma(); + psHu32(SBUS_F240) &= ~0x40; + psHu32(SBUS_F240) &= ~0x100; + psHu32(SBUS_F240) &= ~0x4000; + XMMRegisters::Thaw(); + } +} diff --git a/pcsx2/windows/VCprojects/pcsx2.vcxproj b/pcsx2/windows/VCprojects/pcsx2.vcxproj index 7614c0303c..2fcaa671fb 100644 --- a/pcsx2/windows/VCprojects/pcsx2.vcxproj +++ b/pcsx2/windows/VCprojects/pcsx2.vcxproj @@ -222,6 +222,8 @@ + + diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index ef69ec5528..ce09808e7e 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -784,6 +784,14 @@ RelativePath="..\..\Sif.cpp" > + + + +