void __fastcall WriteFIFO_page_6(u32 mem, const mem128_t *value) { jASSUME( (mem >= 0x10006000) && (mem < 0x10007000) ); GIF_LOG("WriteFIFO/GIF, addr=0x%08X\n", mem); //psHu64(mem ) = value[0]; //psHu64(mem+8) = value[1]; psHu64(0x6000) = value[0]; psHu64(0x6008) = value[1]; if( mtgsThread != NULL ) { const uint count = mtgsThread->PrepDataPacket( GIF_PATH_3, value, 1 ); jASSUME( count == 1 ); u64* data = (u64*)mtgsThread->GetDataPacketPtr(); data[0] = value[0]; data[1] = value[1]; mtgsThread->SendDataPacket(); } else { FreezeXMMRegs(1); FreezeMMXRegs(1); GSGIFTRANSFER3((u32*)value, 1); FreezeMMXRegs(0); FreezeXMMRegs(0); } }
static __fi bool checkTieBit(tDMA_TAG* &ptag) { if (gifch.chcr.TIE && ptag->IRQ) { GIF_LOG("dmaIrq Set"); gspath3done = true; return true; } return false; }
static u16 QWCinGIFMFIFO(u32 DrainADDR) { u32 ret; GIF_LOG("GIF MFIFO Requesting %x QWC from the MFIFO Base %x, SPR MADR %x Drain %x", gifch.qwc, dmacRegs.rbor.ADDR, spr0ch.madr, DrainADDR); //Calculate what we have in the fifo. if(DrainADDR <= spr0ch.madr) { //Drain is below the tadr, calculate the difference between them ret = (spr0ch.madr - DrainADDR) >> 4; }
bool CheckPaths() { // Can't do Path 3, so try dma again later... if (!CHECK_GIFFIFOHACK) { if (!gifUnit.CanDoPath3()) { if (!gifUnit.Path3Masked()) { GIF_LOG("Path3 stalled"); GifDMAInt(128); } return false; } } return true; }
void __fastcall WriteFIFO_GIF(const mem128_t *value) { GIF_LOG("WriteFIFO/GIF <- %ls", value->ToString().c_str()); //CopyQWC(&psHu128(GIF_FIFO), value); //CopyQWC(&nloop0_packet, value); GetMTGS().PrepDataPacket(GIF_PATH_3, 1); GIFPath_CopyTag( GIF_PATH_3, value, 1 ); GetMTGS().SendDataPacket(); if(GSTransferStatus.PTH3 == STOPPED_MODE && gifRegs.stat.APATH == GIF_APATH3 ) { if(gifRegs.stat.DIR == 0)gifRegs.stat.OPH = false; gifRegs.stat.APATH = GIF_APATH_IDLE; if(gifRegs.stat.P1Q) gsPath1Interrupt(); } }
void GIFdma() { tDMA_TAG *ptag; gscycles = prevcycles; if (gifRegs.ctrl.PSE) { // temporarily stop Console.WriteLn("Gif dma temp paused? (non MFIFO GIF)"); GifDMAInt(16); return; } if ((dmacRegs.ctrl.STD == STD_GIF) && (prevcycles != 0)) { //Console.WriteLn("GS Stall Control Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3, gifch.madr, psHu32(DMAC_STADR)); if ((gifch.madr + (gifch.qwc * 16)) > dmacRegs.stadr.ADDR) { GifDMAInt(4); gscycles = 0; return; } prevcycles = 0; gifch.qwc = 0; } if ((gifch.chcr.MOD == CHAIN_MODE) && (!gspath3done) && gifch.qwc == 0) // Chain Mode { ptag = ReadTag(); if (ptag == NULL) return; //DevCon.Warning("GIF Reading Tag MSK = %x", vif1Regs.mskpath3); GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx tadr=%lx", ptag[1]._u32, ptag[0]._u32, gifch.qwc, ptag->ID, gifch.madr, gifch.tadr); if (!CHECK_GIFFIFOHACK)gifRegs.stat.FQC = std::min((u16)0x10, gifch.qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3] if (dmacRegs.ctrl.STD == STD_GIF) { // there are still bugs, need to also check if gifch.madr +16*qwc >= stadr, if not, stall if ((ptag->ID == TAG_REFS) && ((gifch.madr + (gifch.qwc * 16)) > dmacRegs.stadr.ADDR)) { // stalled. // We really need to test this. Pay attention to prevcycles, as it used to trigger GIFchains in the code above. (rama) //Console.WriteLn("GS Stall Control start Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3,gifch.madr, psHu32(DMAC_STADR)); prevcycles = gscycles; gifch.tadr -= 16; gifch.qwc = 0; hwDmacIrq(DMAC_STALL_SIS); GifDMAInt(gscycles); gscycles = 0; return; } } checkTieBit(ptag); } else if (dmacRegs.ctrl.STD == STD_GIF && gifch.chcr.MOD == NORMAL_MODE) { Console.WriteLn("GIF DMA Stall in Normal mode not implemented - Report which game to PCSX2 Team"); } if (!CHECK_GIFFIFOHACK) { gifRegs.stat.FQC = std::min((u16)0x10, gifch.qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3] clearFIFOstuff(true); } // Transfer Dn_QWC from Dn_MADR to GIF if (gifch.qwc > 0) // Normal Mode { if (CheckPaths() == false) return; GIFchain(); //Transfers the data set by the switch //if (gscycles < 8) DevCon.Warning("GSCycles = %d", gscycles); GifDMAInt(gscycles); return; } else if(!gspath3done) GIFdma(); //Loop round if there was a blank tag, causes hell otherwise with P3 masking games. //QWC == 0 && gspath3done == true - End of DMA prevcycles = 0; //if (gscycles < 8) DevCon.Warning("1 GSCycles = %d", gscycles); GifDMAInt(16); }
__fi void gifInterrupt() { GIF_LOG("gifInterrupt caught!"); gifCheckPathStatus(); 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. //This must trigger after VIF retriggers as VIf might instantly mask Path3 if (!gifUnit.Path3Masked() || gifch.qwc == 0) { GifDMAInt(16); } return; } } if (dmacRegs.ctrl.MFD == MFD_GIF) { // GIF MFIFO //Console.WriteLn("GIF MFIFO"); gifMFIFOInterrupt(); return; } if (CHECK_GIFFIFOHACK) { if (int amtRead = gif_fifo.read(true)) { if (!gifUnit.Path3Masked() || gifRegs.stat.FQC < 16) { GifDMAInt(amtRead * BIAS); return; } } else { if (!gifUnit.CanDoPath3() && gifRegs.stat.FQC == 16) { if (gifch.qwc > 0 || gspath3done == false) { if (!gifUnit.Path3Masked()) { GifDMAInt(128); } return; } } } } if (gifUnit.gsSIGNAL.queued) { GIF_LOG("Path 3 Paused"); GifDMAInt(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 GifDMAInt( 64 ); return; } GIFdma(); return; } //Double check as we might have read the fifo as it's ending the DMA gifCheckPathStatus(); 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); } } } if (!CHECK_GIFFIFOHACK) { gifRegs.stat.FQC = 0; clearFIFOstuff(false); } gscycles = 0; gspath3done = false; gifch.chcr.STR = false; hwDmacIrq(DMAC_GIF); GIF_LOG("GIF DMA End QWC in fifo %x APATH = %x OPH = %x state = %x", gifRegs.stat.FQC, gifRegs.stat.APATH, gifRegs.stat.OPH, gifUnit.gifPath[GIF_PATH_3].state); }
__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"); }