void __fastcall WriteFIFO_VIF1(const mem128_t *value) { VIF_LOG("WriteFIFO/VIF1 <- %ls", value->ToString().c_str()); if (vif1Regs.stat.FDR) { DevCon.Warning("writing to fifo when fdr is set!"); } if (vif1Regs.stat.test(VIF1_STAT_INT | VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS) ) { DevCon.Warning("writing to vif1 fifo when stalled"); } if (vif1.irqoffset.value != 0 && vif1.vifstalled.enabled == true) { DevCon.Warning("Offset on VIF1 FIFO start!"); } vif1ch.qwc += 1; bool ret = VIF1transfer((u32*)value, 4); if (vif1.cmd) { if (vif1.done && !vif1ch.qwc) vif1Regs.stat.VPS = VPS_WAITING; } else vif1Regs.stat.VPS = VPS_IDLE; if( gifRegs.stat.APATH == 2 && gifUnit.gifPath[1].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); } pxAssertDev( ret, "vif stall code not implemented" ); }
void __fastcall ReadFIFO_VIF1(mem128_t* out) { if (vif1Regs.stat.test(VIF1_STAT_INT | VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS) ) DevCon.Warning( "Reading from vif1 fifo when stalled" ); pxAssertRel(vif1Regs.stat.FQC != 0, "FQC = 0 on VIF FIFO READ!"); if (vif1Regs.stat.FDR) { if(vif1Regs.stat.FQC > vif1.GSLastDownloadSize) { DevCon.Warning("Warning! GS Download size < FIFO count!"); } if (vif1Regs.stat.FQC > 0) { GetMTGS().WaitGS(); GSreadFIFO((u64*)out); vif1.GSLastDownloadSize--; if (vif1.GSLastDownloadSize <= 16) gifRegs.stat.OPH = false; vif1Regs.stat.FQC = min((u32)16, vif1.GSLastDownloadSize); } } VIF_LOG("ReadFIFO/VIF1 -> %ls", out->ToString().c_str()); }
void __fastcall ReadFIFO_VIF1(mem128_t* out) { if (vif1Regs.stat.test(VIF1_STAT_INT | VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS) ) DevCon.Warning( "Reading from vif1 fifo when stalled" ); ZeroQWC(out); // Clear first in case no data gets written... pxAssertRel(vif1Regs.stat.FQC != 0, "FQC = 0 on VIF FIFO READ!"); if (vif1Regs.stat.FDR) { if (vif1Regs.stat.FQC > vif1.GSLastDownloadSize) { DevCon.Warning("Warning! GS Download size < FIFO count!"); } if (vif1Regs.stat.FQC > 0) { GetMTGS().WaitGS(); if (GSinitReadFIFO) { GetMTGS().SendPointerPacket(GS_RINGTYPE_INIT_READ_FIFO1, 0, out); GetMTGS().WaitGS(false); // wait without reg sync } GSreadFIFO((u64*)out); vif1.GSLastDownloadSize--; GUNIT_LOG("ReadFIFO_VIF1"); if (vif1.GSLastDownloadSize <= 16) gifRegs.stat.OPH = false; vif1Regs.stat.FQC = std::min((u32)16, vif1.GSLastDownloadSize); } } VIF_LOG("ReadFIFO/VIF1 -> %ls", WX_STR(out->ToString())); }
void __fastcall WriteFIFO_VIF1(const mem128_t *value) { VIF_LOG("WriteFIFO/VIF1 <- %ls", value->ToString().c_str()); if (vif1Regs.stat.FDR) { DevCon.Warning("writing to fifo when fdr is set!"); } if (vif1Regs.stat.test(VIF1_STAT_INT | VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS) ) { DevCon.Warning("writing to vif1 fifo when stalled"); } if (vif1.irqoffset != 0 && vif1.vifstalled == true) { DevCon.Warning("Offset on VIF1 FIFO start!"); } vif1ch.qwc += 1; bool ret = VIF1transfer((u32*)value, 4); if (vif1.cmd) { if (vif1.done && !vif1ch.qwc) vif1Regs.stat.VPS = VPS_WAITING; } else vif1Regs.stat.VPS = VPS_IDLE; pxAssertDev( ret, "vif stall code not implemented" ); }
void __fastcall WriteFIFO_VIF1(const mem128_t *value) { VIF_LOG("WriteFIFO/VIF1 <- %ls", value->ToString().c_str()); if (vif1Regs.stat.FDR) DevCon.Warning("writing to fifo when fdr is set!"); if (vif1Regs.stat.test(VIF1_STAT_INT | VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS) ) DevCon.Warning("writing to vif1 fifo when stalled"); vif1ch.qwc += 1; if(vif1.irqoffset != 0 && vif1.vifstalled == true) DevCon.Warning("Offset on VIF1 FIFO start!"); bool ret = VIF1transfer((u32*)value, 4); if(GSTransferStatus.PTH2 == STOPPED_MODE && gifRegs.stat.APATH == GIF_APATH2) { if(gifRegs.stat.DIR == 0)gifRegs.stat.OPH = false; gifRegs.stat.APATH = GIF_APATH_IDLE; if(gifRegs.stat.P1Q) gsPath1Interrupt(); } if (vif1.cmd) { if(vif1.done == true && vif1ch.qwc == 0) vif1Regs.stat.VPS = VPS_WAITING; } else { vif1Regs.stat.VPS = VPS_IDLE; } pxAssertDev( ret, "vif stall code not implemented" ); }
bool _VIF0chain() { u32 *pMem; if (vif0ch.qwc == 0) { vif0.inprogress = 0; return true; } pMem = (u32*)dmaGetAddr(vif0ch.madr, false); if (pMem == NULL) { vif0.cmd = 0; vif0.tag.size = 0; vif0ch.qwc = 0; return true; } VIF_LOG("VIF0chain size=%d, madr=%lx, tadr=%lx", vif0ch.qwc, vif0ch.madr, vif0ch.tadr); if (vif0.irqoffset.enabled) return VIF0transfer(pMem + vif0.irqoffset.value, vif0ch.qwc * 4 - vif0.irqoffset.value); else return VIF0transfer(pMem, vif0ch.qwc * 4); }
__fi void vif1VUFinish() { if (VU0.VI[REG_VPU_STAT].UL & 0x100) { int _cycles = VU1.cycle; //DevCon.Warning("Finishing VU1"); vu1Finish(); CPU_INT(VIF_VU1_FINISH, (VU1.cycle - _cycles) * BIAS); return; } vif1Regs.stat.VEW = false; VIF_LOG("VU1 finished"); if( gifRegs.stat.APATH == 1 ) { VIF_LOG("Clear APATH1"); gifRegs.stat.APATH = 0; gifRegs.stat.OPH = 0; vif1Regs.stat.VGW = false; //Let vif continue if it's stuck on a flush if(!vif1.waitforvu) { if(gifUnit.checkPaths(0,1,1)) gifUnit.Execute(false, true); } } if(vif1.waitforvu == true) { vif1.waitforvu = false; ExecuteVU(1); //Check if VIF is already scheduled to interrupt, if it's waiting, kick it :P if((cpuRegs.interrupt & (1<<DMAC_VIF1 | 1 << DMAC_MFIFO_VIF)) == 0 && vif1ch.chcr.STR == true && !vif1Regs.stat.INT) { if(dmacRegs.ctrl.MFD == MFD_VIF1) vifMFIFOInterrupt(); else vif1Interrupt(); } } //DevCon.Warning("VU1 state cleared"); }
void __fastcall ReadFIFO_page_4(u32 mem, u64 *out) { jASSUME( (mem >= 0x10004000) && (mem < 0x10005000) ); VIF_LOG("ReadFIFO/VIF0 0x%08X\n", mem); //out[0] = psHu64(mem ); //out[1] = psHu64(mem+8); out[0] = psHu64(0x4000); out[1] = psHu64(0x4008); }
void __fastcall WriteFIFO_page_4(u32 mem, const mem128_t *value) { jASSUME( (mem >= 0x10004000) && (mem < 0x10005000) ); VIF_LOG("WriteFIFO/VIF0, addr=0x%08X\n", mem); //psHu64(mem ) = value[0]; //psHu64(mem+8) = value[1]; psHu64(0x4000) = value[0]; psHu64(0x4008) = value[1]; vif0ch->qwc += 1; int ret = VIF0transfer((u32*)value, 4, 0); assert( ret == 0 ); // vif stall code not implemented }
void dmaVIF0() { VIF_LOG("dmaVIF0 chcr = %lx, madr = %lx, qwc = %lx\n" " tadr = %lx, asr0 = %lx, asr1 = %lx", vif0ch.chcr._u32, vif0ch.madr, vif0ch.qwc, vif0ch.tadr, vif0ch.asr0, vif0ch.asr1); g_vif0Cycles = 0; if ((vif0ch.chcr.MOD == NORMAL_MODE) || vif0ch.qwc > 0) // Normal Mode { vif0.dmamode = VIF_NORMAL_TO_MEM_MODE; if(vif0.irqoffset.enabled == true && vif0.done == false) { if(vif0ch.chcr.MOD == NORMAL_MODE)DevCon.Warning("Warning! VIF0 starting a new Normal transfer with vif offset set (Possible force stop?)"); else if(vif0ch.qwc == 0) DevCon.Warning("Warning! VIF0 starting a new Chain transfer with vif offset set (Possible force stop?)"); } vif0.done = false; if(vif0ch.chcr.MOD == CHAIN_MODE && vif0ch.qwc > 0) { vif0.dmamode = VIF_CHAIN_MODE; DevCon.Warning(L"VIF0 QWC on Chain CHCR " + vif0ch.chcr.desc()); if ((vif0ch.chcr.tag().ID == TAG_REFE) || (vif0ch.chcr.tag().ID == TAG_END)) { vif0.done = true; } } } else { vif0.dmamode = VIF_CHAIN_MODE; vif0.done = false; } vif0Regs.stat.FQC = min((u16)0x8, vif0ch.qwc); //Using a delay as Beyond Good and Evil does the DMA twice with 2 different TADR's (no checks in the middle, all one block of code), //the first bit it sends isnt required for it to work. //Also being an end chain it ignores the second lot, this causes infinite loops ;p // Chain Mode CPU_INT(DMAC_VIF0, 4); }
////////////////////////////////////////////////////////////////////////// // WriteFIFO Pages // void __fastcall WriteFIFO_VIF0(const mem128_t *value) { VIF_LOG("WriteFIFO/VIF0 <- %ls", value->ToString().c_str()); vif0ch.qwc += 1; if(vif0.irqoffset.value != 0 && vif0.vifstalled.enabled == true) DevCon.Warning("Offset on VIF0 FIFO start!"); bool ret = VIF0transfer((u32*)value, 4); if (vif0.cmd) { if(vif0.done && vif0ch.qwc == 0) vif0Regs.stat.VPS = VPS_WAITING; } else { vif0Regs.stat.VPS = VPS_IDLE; } pxAssertDev( ret, "vif stall code not implemented" ); }
void __fastcall WriteFIFO_page_5(u32 mem, const mem128_t *value) { jASSUME( (mem >= 0x10005000) && (mem < 0x10006000) ); VIF_LOG("WriteFIFO/VIF1, addr=0x%08X\n", mem); //psHu64(mem ) = value[0]; //psHu64(mem+8) = value[1]; psHu64(0x5000) = value[0]; psHu64(0x5008) = value[1]; if(vif1Regs->stat & VIF1_STAT_FDR) DevCon::Notice("writing to fifo when fdr is set!"); if( vif1Regs->stat & (VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS) ) DevCon::Notice("writing to vif1 fifo when stalled"); vif1ch->qwc += 1; int ret = VIF1transfer((u32*)value, 4, 0); assert( ret == 0 ); // vif stall code not implemented }
void __fastcall ReadFIFO_page_5(u32 mem, u64 *out) { jASSUME( (mem >= 0x10005000) && (mem < 0x10006000) ); VIF_LOG("ReadFIFO/VIF1, addr=0x%08X\n", mem); if( vif1Regs->stat & (VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS) ) DevCon::Notice( "Reading from vif1 fifo when stalled" ); if (vif1Regs->stat & 0x800000) { if (--psHu32(D1_QWC) == 0) vif1Regs->stat&= ~0x1f000000; } //out[0] = psHu64(mem ); //out[1] = psHu64(mem+8); out[0] = psHu64(0x5000); out[1] = psHu64(0x5008); }
// Interprets packet _vifT void vifTransferLoop(u32* &data) { vifStruct& vifX = GetVifX; u32& pSize = vifX.vifpacketsize; int ret = 0; vifXRegs.stat.VPS |= VPS_TRANSFERRING; vifXRegs.stat.ER1 = false; if(!idx)VIF_LOG("Starting VIF0 loop, pSize = %x, stalled = %x", pSize, vifX.vifstalled.enabled ); while (pSize > 0 && !vifX.vifstalled.enabled) { if(!vifX.cmd) { // Get new VifCode if(!vifXRegs.err.MII) { if(vifX.irq && !CHECK_VIF1STALLHACK) break; vifX.irq |= data[0] >> 31; } vifXRegs.code = data[0]; vifX.cmd = data[0] >> 24; //VIF_LOG("New VifCMD %x tagsize %x", vifX.cmd, vifX.tag.size); if (IsDevBuild && SysTrace.EE.VIFcode.IsActive()) { // Pass 2 means "log it" vifCmdHandler[idx][vifX.cmd & 0x7f](2, data); } } ret = vifCmdHandler[idx][vifX.cmd & 0x7f](vifX.pass, data); data += ret; pSize -= ret; } }
bool _VIF1chain() { u32 *pMem; if (vif1ch.qwc == 0) { vif1.inprogress &= ~1; vif1.irqoffset.value = 0; vif1.irqoffset.enabled = false; return true; } // Clarification - this is TO memory mode, for some reason i used the other way round >.< if (vif1.dmamode == VIF_NORMAL_TO_MEM_MODE) { vif1TransferToMemory(); vif1.inprogress &= ~1; return true; } pMem = (u32*)dmaGetAddr(vif1ch.madr, !vif1ch.chcr.DIR); if (pMem == NULL) { vif1.cmd = 0; vif1.tag.size = 0; vif1ch.qwc = 0; return true; } VIF_LOG("VIF1chain size=%d, madr=%lx, tadr=%lx", vif1ch.qwc, vif1ch.madr, vif1ch.tadr); if (vif1.irqoffset.enabled) return VIF1transfer(pMem + vif1.irqoffset.value, vif1ch.qwc * 4 - vif1.irqoffset.value, false); else return VIF1transfer(pMem, vif1ch.qwc * 4, false); }
__fi void vif0VUFinish() { if ((VU0.VI[REG_VPU_STAT].UL & 1)) { int _cycles = VU0.cycle; //DevCon.Warning("Finishing VU0"); vu0Finish(); _cycles = VU0.cycle - _cycles; //DevCon.Warning("Finishing VU0 %d cycles", _cycles); CPU_INT(VIF_VU0_FINISH, _cycles * BIAS); return; } vif0Regs.stat.VEW = false; VIF_LOG("VU0 finished"); if(vif0.waitforvu == true) { vif0.waitforvu = false; ExecuteVU(0); //Make sure VIF0 isnt already scheduled to spin. if(!(cpuRegs.interrupt & 0x1) && vif0ch.chcr.STR == true && !vif0Regs.stat.INT) vif0Interrupt(); } //DevCon.Warning("VU0 state cleared"); }
void dmaVIF1() { VIF_LOG("dmaVIF1 chcr = %lx, madr = %lx, qwc = %lx\n" " tadr = %lx, asr0 = %lx, asr1 = %lx", vif1ch.chcr._u32, vif1ch.madr, vif1ch.qwc, vif1ch.tadr, vif1ch.asr0, vif1ch.asr1); g_vif1Cycles = 0; #ifdef PCSX2_DEVBUILD if (dmacRegs.ctrl.STD == STD_VIF1) { //DevCon.WriteLn("VIF Stall Control Source = %x, Drain = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3); } #endif if (vif1ch.qwc > 0) // Normal Mode { // ignore tag if it's a GS download (Def Jam Fight for NY) if(vif1ch.chcr.MOD == CHAIN_MODE && vif1ch.chcr.DIR) { vif1.dmamode = VIF_CHAIN_MODE; //DevCon.Warning(L"VIF1 QWC on Chain CHCR " + vif1ch.chcr.desc()); if ((vif1ch.chcr.tag().ID == TAG_REFE) || (vif1ch.chcr.tag().ID == TAG_END)) { vif1.done = true; } else { vif1.done = false; } } else //Assume normal mode for reverse FIFO and Normal. { if (dmacRegs.ctrl.STD == STD_VIF1) Console.WriteLn("DMA Stall Control on VIF1 normal"); if (vif1ch.chcr.DIR) // to Memory vif1.dmamode = VIF_NORMAL_FROM_MEM_MODE; else vif1.dmamode = VIF_NORMAL_TO_MEM_MODE; if(vif1.irqoffset.enabled == true && vif1.done == false) DevCon.Warning("Warning! VIF1 starting a Normal transfer with vif offset set (Possible force stop?)"); vif1.done = true; } vif1.inprogress |= 1; } else { if(vif1.irqoffset.enabled == true && vif1.done == false) DevCon.Warning("Warning! VIF1 starting a new Chain transfer with vif offset set (Possible force stop?)"); vif1.dmamode = VIF_CHAIN_MODE; vif1.done = false; vif1.inprogress &= ~0x1; } if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = min((u16)0x10, vif1ch.qwc); // Chain Mode CPU_INT(DMAC_VIF1, 4); }
__fi void vif0SetupTransfer() { tDMA_TAG *ptag; switch (vif0.dmamode) { case VIF_NORMAL_TO_MEM_MODE: vif0.inprogress = 1; vif0.done = true; g_vif0Cycles = 2; break; case VIF_CHAIN_MODE: ptag = dmaGetAddr(vif0ch.tadr, false); //Set memory pointer to TADR if (!(vif0ch.transfer("vif0 Tag", ptag))) return; vif0ch.madr = ptag[1]._u32; //MADR = ADDR field + SPR g_vif0Cycles += 1; // Add 1 g_vifCycles from the QW read for the tag // Transfer dma tag if tte is set VIF_LOG("vif0 Tag %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx", ptag[1]._u32, ptag[0]._u32, vif0ch.qwc, ptag->ID, vif0ch.madr, vif0ch.tadr); vif0.inprogress = 0; if (vif0ch.chcr.TTE) { // Transfer dma tag if tte is set bool ret; static __aligned16 u128 masked_tag; masked_tag._u64[0] = 0; masked_tag._u64[1] = *((u64*)ptag + 1); VIF_LOG("\tVIF0 SrcChain TTE=1, data = 0x%08x.%08x", masked_tag._u32[3], masked_tag._u32[2]); if (vif0.irqoffset.enabled) { ret = VIF0transfer((u32*)&masked_tag + vif0.irqoffset.value, 4 - vif0.irqoffset.value, true); //Transfer Tag on stall //ret = VIF0transfer((u32*)ptag + (2 + vif0.irqoffset), 2 - vif0.irqoffset); //Transfer Tag on stall } else { //Some games (like killzone) do Tags mid unpack, the nops will just write blank data //to the VU's, which breaks stuff, this is where the 128bit packet will fail, so we ignore the first 2 words vif0.irqoffset.value = 2; vif0.irqoffset.enabled = true; ret = VIF0transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag //ret = VIF0transfer((u32*)ptag + 2, 2); //Transfer Tag } if (!ret && vif0.irqoffset.enabled) { vif0.inprogress = 0; //Better clear this so it has to do it again (Jak 1) return; //IRQ set by VIFTransfer } } vif0.irqoffset.value = 0; vif0.irqoffset.enabled = false; vif0.done |= hwDmacSrcChainWithStack(vif0ch, ptag->ID); if(vif0ch.qwc > 0) vif0.inprogress = 1; //Check TIE bit of CHCR and IRQ bit of tag if (vif0ch.chcr.TIE && ptag->IRQ) { VIF_LOG("dmaIrq Set"); //End Transfer vif0.done = true; return; } break; } }
__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 vif1SetupTransfer() { tDMA_TAG *ptag; switch (vif1.dmamode) { case VIF_CHAIN_MODE: ptag = dmaGetAddr(vif1ch.tadr, false); //Set memory pointer to TADR if (!(vif1ch.transfer("Vif1 Tag", ptag))) return; vif1ch.madr = ptag[1]._u32; //MADR = ADDR field + SPR g_vif1Cycles += 1; // Add 1 g_vifCycles from the QW read for the tag VIF_LOG("VIF1 Tag %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx", ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr); if (!vif1.done && ((dmacRegs.ctrl.STD == STD_VIF1) && (ptag->ID == TAG_REFS))) // STD == VIF1 { // there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall if ((vif1ch.madr + vif1ch.qwc * 16) >= dmacRegs.stadr.ADDR) { // stalled hwDmacIrq(DMAC_STALL_SIS); return; } } vif1.inprogress &= ~1; if (vif1ch.chcr.TTE) { // Transfer dma tag if tte is set bool ret; static __aligned16 u128 masked_tag; masked_tag._u64[0] = 0; masked_tag._u64[1] = *((u64*)ptag + 1); VIF_LOG("\tVIF1 SrcChain TTE=1, data = 0x%08x.%08x", masked_tag._u32[3], masked_tag._u32[2]); if (vif1.irqoffset.enabled) { ret = VIF1transfer((u32*)&masked_tag + vif1.irqoffset.value, 4 - vif1.irqoffset.value, true); //Transfer Tag on stall //ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset); //Transfer Tag on stall } else { //Some games (like killzone) do Tags mid unpack, the nops will just write blank data //to the VU's, which breaks stuff, this is where the 128bit packet will fail, so we ignore the first 2 words vif1.irqoffset.value = 2; vif1.irqoffset.enabled = true; ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag //ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag } if (!ret && vif1.irqoffset.enabled) { vif1.inprogress &= ~1; //Better clear this so it has to do it again (Jak 1) return; //IRQ set by VIFTransfer } } vif1.irqoffset.value = 0; vif1.irqoffset.enabled = false; vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID); if(vif1ch.qwc > 0) vif1.inprogress |= 1; //Check TIE bit of CHCR and IRQ bit of tag if (vif1ch.chcr.TIE && ptag->IRQ) { VIF_LOG("dmaIrq Set"); //End Transfer vif1.done = true; return; } break; } }
__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"); }