static void StartQueuedDMA() { if (QueuedDMA.VIF0) { DMA_LOG("Resuming DMA for VIF0"); QueuedDMA.VIF0 = !QuickDmaExec(dmaVIF0, D0_CHCR); } if (QueuedDMA.VIF1) { DMA_LOG("Resuming DMA for VIF1"); QueuedDMA.VIF1 = !QuickDmaExec(dmaVIF1, D1_CHCR); } if (QueuedDMA.GIF ) { DMA_LOG("Resuming DMA for GIF" ); QueuedDMA.GIF = !QuickDmaExec(dmaGIF , D2_CHCR); } if (QueuedDMA.IPU0) { DMA_LOG("Resuming DMA for IPU0"); QueuedDMA.IPU0 = !QuickDmaExec(dmaIPU0, D3_CHCR); } if (QueuedDMA.IPU1) { DMA_LOG("Resuming DMA for IPU1"); QueuedDMA.IPU1 = !QuickDmaExec(dmaIPU1, D4_CHCR); } if (QueuedDMA.SIF0) { DMA_LOG("Resuming DMA for SIF0"); QueuedDMA.SIF0 = !QuickDmaExec(dmaSIF0, D5_CHCR); } if (QueuedDMA.SIF1) { DMA_LOG("Resuming DMA for SIF1"); QueuedDMA.SIF1 = !QuickDmaExec(dmaSIF1, D6_CHCR); } if (QueuedDMA.SIF2) { DMA_LOG("Resuming DMA for SIF2"); QueuedDMA.SIF2 = !QuickDmaExec(dmaSIF2, D7_CHCR); } if (QueuedDMA.SPR0) { DMA_LOG("Resuming DMA for SPR0"); QueuedDMA.SPR0 = !QuickDmaExec(dmaSPR0, D8_CHCR); } if (QueuedDMA.SPR1) { DMA_LOG("Resuming DMA for SPR1"); QueuedDMA.SPR1 = !QuickDmaExec(dmaSPR1, D9_CHCR); } }
static __fi void Sif2End() { psHu32(SBUS_F240) &= ~0x80; psHu32(SBUS_F240) &= ~0x8000; DMA_LOG("SIF2 DMA End"); }
static __fi void Sif1End() { psHu32(SBUS_F240) &= ~0x40; psHu32(SBUS_F240) &= ~0x4000; DMA_LOG("SIF1 DMA End"); }
static __fi void Sif0End() { psHu32(SBUS_F240) &= ~0x20; psHu32(SBUS_F240) &= ~0x2000; DMA_LOG("SIF0 DMA End"); }
void SPRTOinterrupt() { SPR_LOG("SPR1 Interrupt"); if (!spr1finished || spr1ch.qwc > 0) { _dmaSPR1(); return; } DMA_LOG("SPR1 DMA End"); spr1ch.chcr.STR = false; spr1lastqwc = false; hwDmacIrq(DMAC_TO_SPR); }
void SPRFROMinterrupt() { if (!spr0finished || spr0ch.qwc > 0) { _dmaSPR0(); //the qwc check is simply because having data still to transfer from the packet can freak games out if they do a d.tadr == s.madr check //and there is still data to come over (FF12 ingame menu) if(mfifotransferred != 0 && spr0ch.qwc == 0) { switch (dmacRegs.ctrl.MFD) { case MFD_VIF1: // Most common case. { if ((spr0ch.madr & ~dmacRegs.rbsr.RMSK) != dmacRegs.rbor.ADDR) Console.WriteLn("VIF MFIFO Write outside MFIFO area"); spr0ch.madr = dmacRegs.rbor.ADDR + (spr0ch.madr & dmacRegs.rbsr.RMSK); //Console.WriteLn("mfifoVIF1transfer %x madr %x, tadr %x", vif1ch.chcr._u32, vif1ch.madr, vif1ch.tadr); mfifoVIF1transfer(mfifotransferred); mfifotransferred = 0; break; } case MFD_GIF: { if ((spr0ch.madr & ~dmacRegs.rbsr.RMSK) != dmacRegs.rbor.ADDR) Console.WriteLn("GIF MFIFO Write outside MFIFO area"); spr0ch.madr = dmacRegs.rbor.ADDR + (spr0ch.madr & dmacRegs.rbsr.RMSK); //Console.WriteLn("mfifoGIFtransfer %x madr %x, tadr %x", gif->chcr._u32, gif->madr, gif->tadr); mfifoGIFtransfer(mfifotransferred); mfifotransferred = 0; break; } default: break; } } return; } spr0lastqwc = false; spr0ch.chcr.STR = false; hwDmacIrq(DMAC_FROM_SPR); DMA_LOG("SPR0 DMA End"); }
__fi void gifInterrupt() { GIF_LOG("gifInterrupt caught!"); if( gifRegs.stat.APATH == 3 ) { gifRegs.stat.APATH = 0; gifRegs.stat.OPH = 0; if(gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_IDLE || gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_WAIT) { if(gifUnit.checkPaths(1,1,0)) gifUnit.Execute(false, true); } } //Required for Path3 Masking timing! if(gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_WAIT) gifUnit.gifPath[GIF_PATH_3].state = GIF_PATH_IDLE; if(gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_IDLE) { if(vif1Regs.stat.VGW) { //Check if VIF is in a cycle or is currently "idle" waiting for GIF to come back. if(!(cpuRegs.interrupt & (1<<DMAC_VIF1))) CPU_INT(DMAC_VIF1, 1); //Make sure it loops if the GIF packet is empty to prepare for the next packet //or end if it was the end of a packet. if(!gifUnit.Path3Masked() || gifch.qwc == 0) CPU_INT(DMAC_GIF, 16); return; } } if (dmacRegs.ctrl.MFD == MFD_GIF) { // GIF MFIFO //Console.WriteLn("GIF MFIFO"); gifMFIFOInterrupt(); return; } if (gifUnit.gsSIGNAL.queued) { //DevCon.WriteLn("Path 3 Paused"); CPU_INT(DMAC_GIF, 128); return; } if (!(gifch.chcr.STR)) return; if ((gifch.qwc > 0) || (!gspath3done)) { if (!dmacRegs.ctrl.DMAE) { Console.Warning("gs dma masked, re-scheduling..."); // re-raise the int shortly in the future CPU_INT( DMAC_GIF, 64 ); return; } GIFdma(); return; } gifRegs.stat.FQC = 0; gscycles = 0; gspath3done = false; gifch.chcr.STR = false; clearFIFOstuff(false); hwDmacIrq(DMAC_GIF); DMA_LOG("GIF DMA End"); }
__fi void vif1Interrupt() { VIF_LOG("vif1Interrupt: %8.8x chcr %x, done %x, qwc %x", cpuRegs.cycle, vif1ch.chcr._u32, vif1.done, vif1ch.qwc); g_vif1Cycles = 0; if( gifRegs.stat.APATH == 2 && gifUnit.gifPath[GIF_PATH_2].isDone()) { gifRegs.stat.APATH = 0; gifRegs.stat.OPH = 0; vif1Regs.stat.VGW = false; //Let vif continue if it's stuck on a flush if(gifUnit.checkPaths(1,0,1)) gifUnit.Execute(false, true); } //Some games (Fahrenheit being one) start vif first, let it loop through blankness while it sets MFIFO mode, so we need to check it here. if (dmacRegs.ctrl.MFD == MFD_VIF1) { //Console.WriteLn("VIFMFIFO\n"); // Test changed because the Final Fantasy 12 opening somehow has the tag in *Undefined* mode, which is not in the documentation that I saw. if (vif1ch.chcr.MOD == NORMAL_MODE) Console.WriteLn("MFIFO mode is normal (which isn't normal here)! %x", vif1ch.chcr._u32); vif1Regs.stat.FQC = min((u16)0x10, vif1ch.qwc); vifMFIFOInterrupt(); return; } // We need to check the direction, if it is downloading // from the GS then we handle that separately (KH2 for testing) if (vif1ch.chcr.DIR) { bool isDirect = (vif1.cmd & 0x7f) == 0x50; bool isDirectHL = (vif1.cmd & 0x7f) == 0x51; if((isDirect && !gifUnit.CanDoPath2()) || (isDirectHL && !gifUnit.CanDoPath2HL())) { GUNIT_WARN("vif1Interrupt() - Waiting for Path 2 to be ready"); CPU_INT(DMAC_VIF1, 128); if(gifRegs.stat.APATH == 3) vif1Regs.stat.VGW = 1; //We're waiting for path 3. Gunslinger II return; } vif1Regs.stat.VGW = 0; //Path 3 isn't busy so we don't need to wait for it. vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16); //Simulated GS transfer time done, clear the flags } if(vif1.waitforvu == true) { //DevCon.Warning("Waiting on VU1"); //CPU_INT(DMAC_VIF1, 16); return; } if (!vif1ch.chcr.STR) Console.WriteLn("Vif1 running when CHCR == %x", vif1ch.chcr._u32); if (vif1.irq && vif1.tag.size == 0 &&vif1.cmd == 0) { VIF_LOG("VIF IRQ Firing"); vif1Regs.stat.INT = true; hwIntcIrq(VIF1intc); --vif1.irq; if (vif1Regs.stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) { //vif1Regs.stat.FQC = 0; //NFSHPS stalls when the whole packet has gone across (it stalls in the last 32bit cmd) //In this case VIF will end vif1Regs.stat.FQC = min((u16)0x10, vif1ch.qwc); if((vif1ch.qwc > 0 || !vif1.done) && !CHECK_VIF1STALLHACK) { VIF_LOG("VIF1 Stalled"); return; } } } vif1.vifstalled.enabled = false; //Mirroring change to VIF0 if (vif1.cmd) { if (vif1.done && (vif1ch.qwc == 0)) vif1Regs.stat.VPS = VPS_WAITING; } else { vif1Regs.stat.VPS = VPS_IDLE; } if (vif1.inprogress & 0x1) { _VIF1chain(); // VIF_NORMAL_FROM_MEM_MODE is a very slow operation. // Timesplitters 2 depends on this beeing a bit higher than 128. if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16); if(!(vif1Regs.stat.VGW && gifUnit.gifPath[GIF_PATH_3].state != GIF_PATH_IDLE)) //If we're waiting on GIF, stop looping, (can be over 1000 loops!) CPU_INT(DMAC_VIF1, g_vif1Cycles); return; } if (!vif1.done) { if (!(dmacRegs.ctrl.DMAE)) { Console.WriteLn("vif1 dma masked"); return; } if ((vif1.inprogress & 0x1) == 0) vif1SetupTransfer(); if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16); if(!(vif1Regs.stat.VGW && gifUnit.gifPath[GIF_PATH_3].state != GIF_PATH_IDLE)) //If we're waiting on GIF, stop looping, (can be over 1000 loops!) CPU_INT(DMAC_VIF1, g_vif1Cycles); return; } if (vif1.vifstalled.enabled && vif1.done) { DevCon.WriteLn("VIF1 looping on stall at end\n"); CPU_INT(DMAC_VIF1, 0); return; //Dont want to end if vif is stalled. } #ifdef PCSX2_DEVBUILD if (vif1ch.qwc > 0) Console.WriteLn("VIF1 Ending with %x QWC left", vif1ch.qwc); if (vif1.cmd != 0) Console.WriteLn("vif1.cmd still set %x tag size %x", vif1.cmd, vif1.tag.size); #endif if((vif1ch.chcr.DIR == VIF_NORMAL_TO_MEM_MODE) && vif1.GSLastDownloadSize <= 16) { //Reverse fifo has finished and nothing is left, so lets clear the outputting flag gifRegs.stat.OPH = false; } if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16); vif1ch.chcr.STR = false; vif1.vifstalled.enabled = false; vif1.irqoffset.enabled = false; if(vif1.queued_program == true) vifExecQueue(1); g_vif1Cycles = 0; DMA_LOG("VIF1 DMA End"); hwDmacIrq(DMAC_VIF1); }
__fi void vif0Interrupt() { VIF_LOG("vif0Interrupt: %8.8x", cpuRegs.cycle); g_vif0Cycles = 0; vif0Regs.stat.FQC = min(vif0ch.qwc, (u16)8); if (!(vif0ch.chcr.STR)) Console.WriteLn("vif0 running when CHCR == %x", vif0ch.chcr._u32); if (vif0.irq && vif0.tag.size == 0 && vif0.cmd == 0) { vif0Regs.stat.INT = true; hwIntcIrq(VIF0intc); --vif0.irq; if (vif0Regs.stat.test(VIF0_STAT_VSS | VIF0_STAT_VIS | VIF0_STAT_VFS)) { //vif0Regs.stat.FQC = 0; // One game doesn't like vif stalling at end, can't remember what. Spiderman isn't keen on it tho //vif0ch.chcr.STR = false; vif0Regs.stat.FQC = min((u16)0x8, vif0ch.qwc); if(vif0ch.qwc > 0 || !vif0.done) { VIF_LOG("VIF0 Stalled"); return; } } } if(vif0.waitforvu == true) { //DevCon.Warning("Waiting on VU0"); //CPU_INT(DMAC_VIF0, 16); return; } vif0.vifstalled.enabled = false; //Must go after the Stall, incase it's still in progress, GTC africa likes to see it still transferring. if (vif0.cmd) { if(vif0.done == true && vif0ch.qwc == 0) vif0Regs.stat.VPS = VPS_WAITING; } else { vif0Regs.stat.VPS = VPS_IDLE; } if (vif0.inprogress & 0x1) { _VIF0chain(); vif0Regs.stat.FQC = min(vif0ch.qwc, (u16)8); CPU_INT(DMAC_VIF0, g_vif0Cycles); return; } if (!vif0.done) { if (!(dmacRegs.ctrl.DMAE)) { Console.WriteLn("vif0 dma masked"); return; } if ((vif0.inprogress & 0x1) == 0) vif0SetupTransfer(); vif0Regs.stat.FQC = min(vif0ch.qwc, (u16)8); CPU_INT(DMAC_VIF0, g_vif0Cycles); return; } if (vif0.vifstalled.enabled && vif0.done) { DevCon.WriteLn("VIF0 looping on stall at end\n"); CPU_INT(DMAC_VIF0, 0); return; //Dont want to end if vif is stalled. } #ifdef PCSX2_DEVBUILD if (vif0ch.qwc > 0) Console.WriteLn("vif0 Ending with %x QWC left"); if (vif0.cmd != 0) Console.WriteLn("vif0.cmd still set %x tag size %x", vif0.cmd, vif0.tag.size); #endif vif0ch.chcr.STR = false; vif0Regs.stat.FQC = min((u16)0x8, vif0ch.qwc); vif0.vifstalled.enabled = false; vif0.irqoffset.enabled = false; if(vif0.queued_program == true) vifExecQueue(0); g_vif0Cycles = 0; hwDmacIrq(DMAC_VIF0); vif0Regs.stat.FQC = 0; DMA_LOG("VIF0 DMA End"); }