diff --git a/pcsx2/IPU/IPU.cpp b/pcsx2/IPU/IPU.cpp index afdd6a9191..9594abfec9 100644 --- a/pcsx2/IPU/IPU.cpp +++ b/pcsx2/IPU/IPU.cpp @@ -60,13 +60,6 @@ __fi void IPUProcessInterrupt() { if (ipuRegs.ctrl.BUSY) // && (g_BP.FP || g_BP.IFC || (ipu1ch.chcr.STR && ipu1ch.qwc > 0))) IPUWorker(); - if (ipuRegs.ctrl.BUSY && ipuRegs.cmd.BUSY && ipuRegs.cmd.DATA == 0x000001B7) { - // 0x000001B7 is the MPEG2 sequence end code, signalling the end of a video. - // At the end of a video BUSY values should be automatically set to 0. - // This does not happen for Enthusia - Professional Racing, causing it to get stuck in an endless loop. - ipuRegs.cmd.BUSY = 0; - ipuRegs.ctrl.BUSY = 0; - } } ///////////////////////////////////////////////////////// @@ -287,7 +280,18 @@ __fi RETURNS_R64 ipuRead64(u32 mem) void ipuSoftReset() { + if (ipu1ch.chcr.STR && g_BP.IFC < 8 && IPU1Status.DataRequested) + { + DevCon.Warning("Refill input fifo on reset"); + ipu1Interrupt(); + } + + if (!ipu1ch.chcr.STR) + psHu32(DMAC_STAT) &= ~(1 << DMAC_TO_IPU); + + ipu_fifo.clear(); + memzero(g_BP); coded_block_pattern = 0; @@ -296,7 +300,7 @@ void ipuSoftReset() ipu_cmd.clear(); ipuRegs.cmd.BUSY = 0; ipuRegs.cmd.DATA = 0; // required for Enthusia - Professional Racing after fix, or will freeze at start of next video. - memzero(g_BP); + hwIntcIrq(INTC_IPU); // required for FightBox } diff --git a/pcsx2/IPU/IPU.h b/pcsx2/IPU/IPU.h index 993a07f154..250ede2847 100644 --- a/pcsx2/IPU/IPU.h +++ b/pcsx2/IPU/IPU.h @@ -72,7 +72,7 @@ union tIPU_CTRL { bool test(u32 flags) const { return !!(_u32 & flags); } void set_flags(u32 flags) { _u32 |= flags; } void clear_flags(u32 flags) { _u32 &= ~flags; } - void reset() { _u32 = 0; } + void reset() { _u32 &= 0x7F33F00; } }; struct alignas(16) tIPU_BP { diff --git a/pcsx2/IPU/IPUdma.cpp b/pcsx2/IPU/IPUdma.cpp index a7e3e7d232..eb73eccf7d 100644 --- a/pcsx2/IPU/IPUdma.cpp +++ b/pcsx2/IPU/IPUdma.cpp @@ -20,178 +20,115 @@ #include "mpeg2lib/Mpeg.h" IPUStatus IPU1Status; -static tIPU_DMA g_nDMATransfer; void ipuDmaReset() { IPU1Status.InProgress = false; - IPU1Status.DMAMode = DMA_MODE_NORMAL; IPU1Status.DMAFinished = true; - - g_nDMATransfer.reset(); } void SaveStateBase::ipuDmaFreeze() { FreezeTag( "IPUdma" ); - Freeze(g_nDMATransfer); Freeze(IPU1Status); } -static __fi void ipuDmacSrcChain() -{ - switch (IPU1Status.ChainMode) - { - case TAG_REFE: // refe - //if(!IPU1Status.InProgress) ipu1ch.tadr += 16; - IPU1Status.DMAFinished = true; - break; - case TAG_CNT: // cnt - // Set the taddr to the next tag - ipu1ch.tadr = ipu1ch.madr; - //if(!IPU1Status.DMAFinished) IPU1Status.DMAFinished = false; - break; - - case TAG_NEXT: // next - ipu1ch.tadr = IPU1Status.NextMem; - //if(!IPU1Status.DMAFinished) IPU1Status.DMAFinished = false; - break; - - case TAG_REF: // ref - //if(!IPU1Status.InProgress)ipu1ch.tadr += 16; - //if(!IPU1Status.DMAFinished) IPU1Status.DMAFinished = false; - break; - - case TAG_END: // end - //ipu1ch.tadr = ipu1ch.madr; - //IPU1Status.DMAFinished = true; - break; - } -} - static __fi int IPU1chain() { int totalqwc = 0; - if (ipu1ch.qwc > 0 && IPU1Status.InProgress) + int qwc = ipu1ch.qwc; + u32 *pMem; + + pMem = (u32*)dmaGetAddr(ipu1ch.madr, false); + + if (pMem == NULL) { - int qwc = ipu1ch.qwc; - u32 *pMem; - - pMem = (u32*)dmaGetAddr(ipu1ch.madr, false); - - if (pMem == NULL) - { - Console.Error("ipu1dma NULL!"); - return totalqwc; - } - - //Write our data to the fifo - qwc = ipu_fifo.in.write(pMem, qwc); - ipu1ch.madr += qwc << 4; - ipu1ch.qwc -= qwc; - totalqwc += qwc; + Console.Error("ipu1dma NULL!"); + return totalqwc; } + //Write our data to the fifo + qwc = ipu_fifo.in.write(pMem, qwc); + ipu1ch.madr += qwc << 4; + ipu1ch.qwc -= qwc; + totalqwc += qwc; + //Update TADR etc - - hwDmacSrcTadrInc(ipu1ch); - - if( ipu1ch.qwc == 0) + hwDmacSrcTadrInc(ipu1ch); + + if (!ipu1ch.qwc) IPU1Status.InProgress = false; return totalqwc; } -int IPU1dma() +void IPU1dma() { int ipu1cycles = 0; int totalqwc = 0; - //We need to make sure GIF has flushed before sending IPU data, it seems to REALLY screw FFX videos - - if(!ipu1ch.chcr.STR || IPU1Status.DMAMode == DMA_MODE_INTERLEAVE) + if(!ipu1ch.chcr.STR || ipu1ch.chcr.MOD == 2) { //We MUST stop the IPU from trying to fill the FIFO with more data if the DMA has been suspended //if we don't, we risk causing the data to go out of sync with the fifo and we end up losing some! //This is true for Dragons Quest 8 and probably others which suspend the DMA. DevCon.Warning("IPU1 running when IPU1 DMA disabled! CHCR %x QWC %x", ipu1ch.chcr._u32, ipu1ch.qwc); - return 0; + return; } if (IPU1Status.DataRequested == false) { + // IPU isn't expecting any data, so put it in to wait mode. cpuRegs.eCycle[4] = 0x9999; - return 0; + return; } - IPU_LOG("IPU1 DMA Called QWC %x Finished %d In Progress %d tadr %x", ipu1ch.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress, ipu1ch.tadr); - - switch(IPU1Status.DMAMode) + if (!IPU1Status.InProgress) { - case DMA_MODE_NORMAL: - { - IPU_LOG("Processing Normal QWC left %x Finished %d In Progress %d", ipu1ch.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress); - if(IPU1Status.InProgress) totalqwc += IPU1chain(); - } - break; + if (IPU1Status.DMAFinished) + DevCon.Warning("IPU1 DMA Somehow reading tag when finished??"); - case DMA_MODE_CHAIN: - { - if(IPU1Status.InProgress) //No transfer is ready to go so we need to set one up - { - IPU_LOG("Processing Chain QWC left %x Finished %d In Progress %d", ipu1ch.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress); - totalqwc += IPU1chain(); - } + tDMA_TAG* ptag = dmaGetAddr(ipu1ch.tadr, false); //Set memory pointer to TADR + if (!ipu1ch.transfer("IPU1", ptag)) + { + return; + } + ipu1ch.madr = ptag[1]._u32; - if(!IPU1Status.InProgress && !IPU1Status.DMAFinished) //No transfer is ready to go so we need to set one up - { - tDMA_TAG* ptag = dmaGetAddr(ipu1ch.tadr, false); //Set memory pointer to TADR + ipu1cycles += 1; // Add 1 cycles from the QW read for the tag - if (!ipu1ch.transfer("IPU1", ptag)) - { - return totalqwc; - } - ipu1ch.madr = ptag[1]._u32; + if (ipu1ch.chcr.TTE) DevCon.Warning("TTE?"); - ipu1cycles += 1; // Add 1 cycles from the QW read for the tag - IPU1Status.ChainMode = ptag->ID; + IPU1Status.DMAFinished = hwDmacSrcChain(ipu1ch, ptag->ID); - if(ipu1ch.chcr.TTE) DevCon.Warning("TTE?"); - - IPU1Status.DMAFinished = hwDmacSrcChain(ipu1ch, ptag->ID); + IPU_LOG("dmaIPU1 dmaChain %8.8x_%8.8x size=%d, addr=%lx, fifosize=%x", + ptag[1]._u32, ptag[0]._u32, ipu1ch.qwc, ipu1ch.madr, 8 - g_BP.IFC); - - if(ipu1ch.qwc > 0) IPU1Status.InProgress = true; - IPU_LOG("dmaIPU1 dmaChain %8.8x_%8.8x size=%d, addr=%lx, fifosize=%x", - ptag[1]._u32, ptag[0]._u32, ipu1ch.qwc, ipu1ch.madr, 8 - g_BP.IFC); + if (ipu1ch.chcr.TIE && ptag->IRQ) //Tag Interrupt is set, so schedule the end/interrupt + IPU1Status.DMAFinished = true; - if (ipu1ch.chcr.TIE && ptag->IRQ) //Tag Interrupt is set, so schedule the end/interrupt - IPU1Status.DMAFinished = true; - - IPU_LOG("Processing Start Chain QWC left %x Finished %d In Progress %d", ipu1ch.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress); - totalqwc += IPU1chain(); - //Set the TADR forward - } - - } - break; + if (ipu1ch.qwc) + IPU1Status.InProgress = true; } + if (IPU1Status.InProgress) + totalqwc += IPU1chain(); + //Do this here to prevent double settings on Chain DMA's if(totalqwc == 0 || (IPU1Status.DMAFinished && !IPU1Status.InProgress)) { - totalqwc = std::min(4, totalqwc); - IPU_INT_TO(4); + totalqwc = std::max(4, totalqwc); + IPU_INT_TO(totalqwc); } - else + else { - - if (g_BP.IFC == 8) + IPU1Status.DataRequested = false; + + if (!(IPU1Status.DMAFinished && !IPU1Status.InProgress)) { - IPU1Status.DataRequested = false; cpuRegs.eCycle[4] = 0x9999;//IPU_INT_TO(2048); } else @@ -203,7 +140,6 @@ int IPU1dma() IPUProcessInterrupt(); IPU_LOG("Completed Call IPU1 DMA QWC Remaining %x Finished %d In Progress %d tadr %x", ipu1ch.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress, ipu1ch.tadr); - return totalqwc; } void IPU0dma() @@ -238,27 +174,10 @@ void IPU0dma() ipu0ch.madr += readsize << 4; ipu0ch.qwc -= readsize; - if (dmacRegs.ctrl.STS == STS_fromIPU && ipu0ch.qwc == 0) // STS == fromIPU + if (dmacRegs.ctrl.STS == STS_fromIPU) // STS == fromIPU { //DevCon.Warning("fromIPU Stall Control"); dmacRegs.stadr.ADDR = ipu0ch.madr; - switch (dmacRegs.ctrl.STD) - { - case NO_STD: - break; - case STD_GIF: // GIF - //DevCon.Warning("GIFSTALL"); - g_nDMATransfer.GIFSTALL = true; - break; - case STD_VIF1: // VIF - //DevCon.Warning("VIFSTALL"); - g_nDMATransfer.VIFSTALL = true; - break; - case STD_SIF1: - // DevCon.Warning("SIFSTALL"); - g_nDMATransfer.SIFSTALL = true; - break; - } } IPU_INT_FROM( readsize * BIAS ); @@ -292,11 +211,9 @@ __fi void dmaIPU1() // toIPU IPU1Status.InProgress = false; IPU1Status.DMAFinished = false; } - else - { //Attempting to continue a previous chain + else // Attempting to continue a previous chain + { IPU_LOG("Resuming DMA TAG %x", (ipu1ch.chcr.TAG >> 12)); - //We MUST check the CHCR for the tag it last knew, it can be manipulated! - IPU1Status.ChainMode = (ipu1ch.chcr.TAG >> 12) & 0x7; IPU1Status.InProgress = true; if ((ipu1ch.chcr.tag().ID == TAG_REFE) || (ipu1ch.chcr.tag().ID == TAG_END) || (ipu1ch.chcr.tag().IRQ && ipu1ch.chcr.TIE)) { @@ -308,18 +225,17 @@ __fi void dmaIPU1() // toIPU } } - IPU1Status.DMAMode = DMA_MODE_CHAIN; if(IPU1Status.DataRequested) IPU1dma(); else cpuRegs.eCycle[4] = 0x9999; } - else //Normal Mode + else // Normal Mode { IPU_LOG("Setting up IPU1 Normal mode"); IPU1Status.InProgress = true; IPU1Status.DMAFinished = true; - IPU1Status.DMAMode = DMA_MODE_NORMAL; + if (IPU1Status.DataRequested) IPU1dma(); else @@ -336,43 +252,6 @@ void ipu0Interrupt() IPU0dma(); return; } - if (g_nDMATransfer.FIREINT0) - { - g_nDMATransfer.FIREINT0 = false; - hwIntcIrq(INTC_IPU); - } - - if (g_nDMATransfer.GIFSTALL) - { - // gif - //DevCon.Warning("IPU GIF Stall"); - g_nDMATransfer.GIFSTALL = false; - //if (gif->chcr.STR) GIFdma(); - } - - if (g_nDMATransfer.VIFSTALL) - { - // vif - //DevCon.Warning("IPU VIF Stall"); - g_nDMATransfer.VIFSTALL = false; - //if (vif1ch.chcr.STR) dmaVIF1(); - } - - if (g_nDMATransfer.SIFSTALL) - { - // sif - //DevCon.Warning("IPU SIF Stall"); - g_nDMATransfer.SIFSTALL = false; - - // Not totally sure whether this needs to be done or not, so I'm - // leaving it commented out for the moment. - //if (sif1ch.chcr.STR) SIF1Dma(); - } - - if (g_nDMATransfer.TIE0) - { - g_nDMATransfer.TIE0 = false; - } ipu0ch.chcr.STR = false; hwDmacIrq(DMAC_FROM_IPU); @@ -391,6 +270,5 @@ __fi void ipu1Interrupt() DMA_LOG("IPU1 DMA End"); ipu1ch.chcr.STR = false; - IPU1Status.DMAMode = DMA_MODE_INTERLEAVE; hwDmacIrq(DMAC_TO_IPU); } diff --git a/pcsx2/IPU/IPUdma.h b/pcsx2/IPU/IPUdma.h index 4be61e4261..0c22788a89 100644 --- a/pcsx2/IPU/IPUdma.h +++ b/pcsx2/IPU/IPUdma.h @@ -17,79 +17,19 @@ #include "IPU.h" - - struct IPUStatus { bool InProgress; - u8 DMAMode; bool DMAFinished; - bool IRQTriggered; - u8 TagFollow; - u32 TagAddr; - bool stalled; - u8 ChainMode; - u32 NextMem; bool DataRequested; }; -#define DMA_MODE_NORMAL 0 -#define DMA_MODE_CHAIN 1 -#define DMA_MODE_INTERLEAVE 2 - -#define IPU1_TAG_FOLLOW 0 -#define IPU1_TAG_QWC 1 -#define IPU1_TAG_ADDR 2 -#define IPU1_TAG_NONE 3 - -union tIPU_DMA -{ - struct - { - bool GIFSTALL : 1; - bool TIE0 :1; - bool TIE1 : 1; - bool ACTV1 : 1; - bool DOTIE1 : 1; - bool FIREINT0 : 1; - bool FIREINT1 : 1; - bool VIFSTALL : 1; - bool SIFSTALL : 1; - }; - u32 _u32; - - tIPU_DMA( u32 val ){ _u32 = val; } - tIPU_DMA() { } - - bool test(u32 flags) const { return !!(_u32 & flags); } - void set_flags(u32 flags) { _u32 |= flags; } - void clear_flags(u32 flags) { _u32 &= ~flags; } - void reset() { _u32 = 0; } - wxString desc() const - { - wxString temp(L"g_nDMATransfer["); - - if (GIFSTALL) temp += L" GIFSTALL "; - if (TIE0) temp += L" TIE0 "; - if (TIE1) temp += L" TIE1 "; - if (ACTV1) temp += L" ACTV1 "; - if (DOTIE1) temp += L" DOTIE1 "; - if (FIREINT0) temp += L" FIREINT0 "; - if (FIREINT1) temp += L" FIREINT1 "; - if (VIFSTALL) temp += L" VIFSTALL "; - if (SIFSTALL) temp += L" SIFSTALL "; - - temp += L"]"; - return temp; - } -}; - extern void ipu0Interrupt(); extern void ipu1Interrupt(); extern void dmaIPU0(); extern void dmaIPU1(); extern void IPU0dma(); -extern int IPU1dma(); +extern void IPU1dma(); extern void ipuDmaReset(); extern IPUStatus IPU1Status;