void triggerPgifInt(int subCause) { //For the PGIF on EE side. // Console.WriteLn("TRIGGERRING PGIF IRQ! %08X %08X ", psHu32(INTC_STAT), psHu32(INTC_MASK)); //Left-overs from tests: //iopCycleEE = -1; //0000; //iopBreak = 0; //--cpuTestINTCInts(); //--cpuSetEvent(); hwIntcIrq(15); cpuSetEvent(); return; }
void recMicroVU1::Execute(u32 cycles) { pxAssert(m_Reserved); // please allocate me first! :| if (!THREAD_VU1) { if(!(VU0.VI[REG_VPU_STAT].UL & 0x100)) return; } ((mVUrecCall)microVU1.startFunct)(VU1.VI[REG_TPC].UL, cycles); if(microVU1.regs().flags & 0x4) { microVU1.regs().flags &= ~0x4; hwIntcIrq(7); } }
void recMicroVU0::Execute(u32 cycles) { pxAssert(m_Reserved); // please allocate me first! :| if(!(VU0.VI[REG_VPU_STAT].UL & 1)) return; // Sometimes games spin on vu0, so be careful with this value // woody hangs if too high on sVU (untested on mVU) // Edit: Need to test this again, if anyone ever has a "Woody" game :p ((mVUrecCall)microVU0.startFunct)(VU0.VI[REG_TPC].UL, cycles); if(microVU0.regs().flags & 0x4) { microVU0.regs().flags &= ~0x4; hwIntcIrq(6); } }
static void _vu1Exec(VURegs* VU) { _VURegsNum lregs; _VURegsNum uregs; VECTOR _VF; VECTOR _VFc; REG_VI _VI; REG_VI _VIc; u32 *ptr; int vfreg; int vireg; int discard=0; ptr = (u32*)&VU->Micro[VU->VI[REG_TPC].UL]; VU->VI[REG_TPC].UL+=8; if (ptr[1] & 0x40000000) { /* E flag */ VU->ebit = 2; } if (ptr[1] & 0x10000000) { /* D flag */ if (VU0.VI[REG_FBRST].UL & 0x400) { VU0.VI[REG_VPU_STAT].UL|= 0x200; hwIntcIrq(INTC_VU1); VU->ebit = 1; } } if (ptr[1] & 0x08000000) { /* T flag */ if (VU0.VI[REG_FBRST].UL & 0x800) { VU0.VI[REG_VPU_STAT].UL|= 0x400; hwIntcIrq(INTC_VU1); VU->ebit = 1; } } //VUM_LOG("VU->cycle = %d (flags st=%x;mac=%x;clip=%x,q=%f)", VU->cycle, VU->statusflag, VU->macflag, VU->clipflag, VU->q.F); VU->code = ptr[1]; VU1regs_UPPER_OPCODE[VU->code & 0x3f](&uregs); #ifndef INT_VUSTALLHACK _vuTestUpperStalls(VU, &uregs); #endif /* check upper flags */ if (ptr[1] & 0x80000000) { /* I flag */ _vu1ExecUpper(VU, ptr); VU->VI[REG_I].UL = ptr[0]; //Lower not used, set to 0 to fill in the FMAC stall gap //Could probably get away with just running upper stalls, but lets not tempt fate. memset(&lregs, 0, sizeof(lregs)); } else { VU->code = ptr[0]; VU1regs_LOWER_OPCODE[VU->code >> 25](&lregs); #ifndef INT_VUSTALLHACK _vuTestLowerStalls(VU, &lregs); #endif vu1branch = lregs.pipe == VUPIPE_BRANCH; vfreg = 0; vireg = 0; if (uregs.VFwrite) { if (lregs.VFwrite == uregs.VFwrite) { // Console.Warning("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle"); discard = 1; } if (lregs.VFread0 == uregs.VFwrite || lregs.VFread1 == uregs.VFwrite) { // Console.WriteLn("saving reg %d at pc=%x", i, VU->VI[REG_TPC].UL); _VF = VU->VF[uregs.VFwrite]; vfreg = uregs.VFwrite; } } if (uregs.VIread & (1 << REG_CLIP_FLAG)) { if (lregs.VIwrite & (1 << REG_CLIP_FLAG)) { Console.Warning("*PCSX2*: Warning, VI write to the same reg in both lower/upper cycle"); discard = 1; } if (lregs.VIread & (1 << REG_CLIP_FLAG)) { _VI = VU->VI[REG_CLIP_FLAG]; vireg = REG_CLIP_FLAG; } } _vu1ExecUpper(VU, ptr); if (discard == 0) { if (vfreg) { _VFc = VU->VF[vfreg]; VU->VF[vfreg] = _VF; } if (vireg) { _VIc = VU->VI[vireg]; VU->VI[vireg] = _VI; } _vu1ExecLower(VU, ptr); if (vfreg) { VU->VF[vfreg] = _VFc; } if (vireg) { VU->VI[vireg] = _VIc; } } } _vuAddUpperStalls(VU, &uregs); _vuAddLowerStalls(VU, &lregs); _vuTestPipes(VU); if(VU->VIBackupCycles > 0) VU->VIBackupCycles--; if (VU->branch > 0) { if (VU->branch-- == 1) { VU->VI[REG_TPC].UL = VU->branchpc; if(VU->takedelaybranch) { VU->branch = 2; //DevCon.Warning("VU1 - Branch/Jump in Delay Slot"); VU->branchpc = VU->delaybranchpc; VU->delaybranchpc = 0; VU->takedelaybranch = false; } } } if( VU->ebit > 0 ) { if( VU->ebit-- == 1 ) { VU->VIBackupCycles = 0; _vuFlushAll(VU); VU0.VI[REG_VPU_STAT].UL &= ~0x100; vif1Regs.stat.VEW = false; } } }
static void _vu0Exec(VURegs* VU) { _VURegsNum lregs; _VURegsNum uregs; VECTOR _VF; VECTOR _VFc; REG_VI _VI; REG_VI _VIc; u32 *ptr; int vfreg; int vireg; int discard=0; ptr = (u32*)&VU->Micro[VU->VI[REG_TPC].UL]; VU->VI[REG_TPC].UL+=8; if (ptr[1] & 0x40000000) { VU->ebit = 2; } if (ptr[1] & 0x20000000) { /* M flag */ VU->flags|= VUFLAG_MFLAGSET; // Console.WriteLn("fixme: M flag set"); } if (ptr[1] & 0x10000000) { /* D flag */ if (VU0.VI[REG_FBRST].UL & 0x4) { VU0.VI[REG_VPU_STAT].UL|= 0x2; hwIntcIrq(INTC_VU0); } } if (ptr[1] & 0x08000000) { /* T flag */ if (VU0.VI[REG_FBRST].UL & 0x8) { VU0.VI[REG_VPU_STAT].UL|= 0x4; hwIntcIrq(INTC_VU0); } } VU->code = ptr[1]; VU0regs_UPPER_OPCODE[VU->code & 0x3f](&uregs); #ifndef INT_VUSTALLHACK _vuTestUpperStalls(VU, &uregs); #endif /* check upper flags */ if (ptr[1] & 0x80000000) { /* I flag */ _vu0ExecUpper(VU, ptr); VU->VI[REG_I].UL = ptr[0]; memset(&lregs, 0, sizeof(lregs)); } else { VU->code = ptr[0]; VU0regs_LOWER_OPCODE[VU->code >> 25](&lregs); #ifndef INT_VUSTALLHACK _vuTestLowerStalls(VU, &lregs); #endif vu0branch = lregs.pipe == VUPIPE_BRANCH; vfreg = 0; vireg = 0; if (uregs.VFwrite) { if (lregs.VFwrite == uregs.VFwrite) { // Console.Warning("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle"); discard = 1; } if (lregs.VFread0 == uregs.VFwrite || lregs.VFread1 == uregs.VFwrite) { // Console.WriteLn("saving reg %d at pc=%x", i, VU->VI[REG_TPC].UL); _VF = VU->VF[uregs.VFwrite]; vfreg = uregs.VFwrite; } } if (uregs.VIread & (1 << REG_CLIP_FLAG)) { if (lregs.VIwrite & (1 << REG_CLIP_FLAG)) { Console.Warning("*PCSX2*: Warning, VI write to the same reg in both lower/upper cycle"); discard = 1; } if (lregs.VIread & (1 << REG_CLIP_FLAG)) { _VI = VU0.VI[REG_CLIP_FLAG]; vireg = REG_CLIP_FLAG; } } _vu0ExecUpper(VU, ptr); if (discard == 0) { if (vfreg) { _VFc = VU->VF[vfreg]; VU->VF[vfreg] = _VF; } if (vireg) { _VIc = VU->VI[vireg]; VU->VI[vireg] = _VI; } _vu0ExecLower(VU, ptr); if (vfreg) { VU->VF[vfreg] = _VFc; } if (vireg) { VU->VI[vireg] = _VIc; } } } _vuAddUpperStalls(VU, &uregs); if (!(ptr[1] & 0x80000000)) _vuAddLowerStalls(VU, &lregs); _vuTestPipes(VU); if (VU->branch > 0) { VU->branch--; if (VU->branch == 0) { VU->VI[REG_TPC].UL = VU->branchpc; } } if( VU->ebit > 0 ) { if( VU->ebit-- == 1 ) { _vuFlushAll(VU); VU0.VI[REG_VPU_STAT].UL&= ~0x1; /* E flag */ vif0Regs.stat.VEW = false; } } }
__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"); }