Exemplo n.º 1
0
void vif1TransferToMemory()
{
	u128* pMem = (u128*)dmaGetAddr(vif1ch.madr, false);

	// VIF from gsMemory
	if (pMem == NULL) { // Is vif0ptag empty?
		Console.WriteLn("Vif1 Tag BUSERR");
		dmacRegs.stat.BEIS = true; // Bus Error
		vif1Regs.stat.FQC = 0;

		vif1ch.qwc = 0;
		vif1.done = true;
		CPU_INT(DMAC_VIF1, 0);
		return; // An error has occurred.
	}

	// MTGS concerns:  The MTGS is inherently disagreeable with the idea of downloading
	// stuff from the GS.  The *only* way to handle this case safely is to flush the GS
	// completely and execute the transfer there-after.
	//Console.Warning("Real QWC %x", vif1ch.qwc);
	const u32   size = min(vif1.GSLastDownloadSize, (u32)vif1ch.qwc);
	const u128* pMemEnd  = vif1.GSLastDownloadSize + pMem;
	
	if (size) {
		// Checking if any crazy game does a partial
		// gs primitive and then does a gs download...
		Gif_Path& p1 = gifUnit.gifPath[GIF_PATH_1];
		Gif_Path& p2 = gifUnit.gifPath[GIF_PATH_2];
		Gif_Path& p3 = gifUnit.gifPath[GIF_PATH_3];
		pxAssert(p1.isDone() || !p1.gifTag.isValid);
		pxAssert(p2.isDone() || !p2.gifTag.isValid);
		pxAssert(p3.isDone() || !p3.gifTag.isValid);
	}

	GetMTGS().WaitGS();
	GSreadFIFO2((u64*)pMem, size);
	pMem += size;

	if(pMem < pMemEnd) {
		//DevCon.Warning("GS Transfer < VIF QWC, Clearing end of space");
		
		__m128 zeroreg = _mm_setzero_ps();
		do {
			_mm_store_ps((float*)pMem, zeroreg);
		} while (++pMem < pMemEnd);
	}

	g_vif1Cycles += vif1ch.qwc * 2;
	vif1ch.madr += vif1ch.qwc * 16; // mgs3 scene changes
	if (vif1.GSLastDownloadSize >= vif1ch.qwc) {
		vif1.GSLastDownloadSize -= vif1ch.qwc;
		vif1Regs.stat.FQC = min((u32)16, vif1.GSLastDownloadSize);
	}
	else {
		vif1Regs.stat.FQC = 0;
		vif1.GSLastDownloadSize = 0;
	}

	vif1ch.qwc = 0;
}
Exemplo n.º 2
0
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)
		{
			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)
		IPU1Status.InProgress = false;

	return totalqwc;
}
Exemplo n.º 3
0
static __fi int IPU1chain() {

	int totalqwc = 0;

	if (ipu1dma.qwc > 0 && IPU1Status.InProgress == true)
	{
		int qwc = ipu1dma.qwc;
		u32 *pMem;

		pMem = (u32*)dmaGetAddr(ipu1dma.madr, false);

		if (pMem == NULL)
		{
			Console.Error("ipu1dma NULL!");
			return totalqwc;
		}

		//Write our data to the fifo
		qwc = ipu_fifo.in.write(pMem, qwc);
		ipu1dma.madr += qwc << 4;
		ipu1dma.qwc -= qwc;
		totalqwc += qwc;
	}

	//Update TADR etc
	if(IPU1Status.DMAMode == DMA_MODE_CHAIN) ipuDmacSrcChain();

	if( ipu1dma.qwc == 0)
		IPU1Status.InProgress = false;

	return totalqwc;
}
Exemplo n.º 4
0
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);
}
Exemplo n.º 5
0
static __fi tDMA_TAG* ReadTag2()
{
	tDMA_TAG* ptag = dmaGetAddr(gifch.tadr, false);  //Set memory pointer to TADR

	gifch.unsafeTransfer(ptag);
	gifch.madr = ptag[1]._u32;

	gspath3done = hwDmacSrcChainWithStack(gifch, ptag->ID);
	return ptag;
}
Exemplo n.º 6
0
static __fi tDMA_TAG* ReadTag()
{
	tDMA_TAG* ptag = dmaGetAddr(gifch.tadr, false);  //Set memory pointer to TADR

	if (!(gifch.transfer("Gif", ptag))) return NULL;

	gifch.madr = ptag[1]._u32;	//MADR = ADDR field + SPR
	gscycles += 2;				// Add 1 cycles from the QW read for the tag

	gspath3done = hwDmacSrcChainWithStack(gifch, ptag->ID);
	return ptag;
}
Exemplo n.º 7
0
tDMA_TAG *DMACh::getAddr(u32 addr, u32 num, bool write)
{
	tDMA_TAG *ptr = dmaGetAddr(addr, write);
	if (ptr == NULL)
	{
		throwBusError("dmaGetAddr");
		setDmacStat(num);
		chcr.STR = false;
	}

	return ptr;
}
Exemplo n.º 8
0
int  _GIFchain()
{
	tDMA_TAG *pMem;

	pMem = dmaGetAddr(gifch.madr, false);
	if (pMem == NULL) {
		//must increment madr and clear qwc, else it loops
		gifch.madr += gifch.qwc * 16;
		gifch.qwc = 0;
		Console.Warning("Hackfix - NULL GIFchain");
		return -1;
	}

	return WRITERING_DMA((u32*)pMem, gifch.qwc);
}
Exemplo n.º 9
0
int  _GIFchain()
{
	tDMA_TAG *pMem;

	pMem = dmaGetAddr(gifch.madr, false);
	if (pMem == NULL) {

#if USE_OLD_GIF == 1 // d
		// reset path3, fixes dark cloud 2
		GIFPath_Clear( GIF_PATH_3 );
#endif
		//must increment madr and clear qwc, else it loops
		gifch.madr += gifch.qwc * 16;
		gifch.qwc = 0;
		Console.Warning("Hackfix - NULL GIFchain");
		return -1;
	}

	return WRITERING_DMA((u32*)pMem, gifch.qwc);
}
Exemplo n.º 10
0
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);
}
Exemplo n.º 11
0
void IPU0dma()
{
	if(!ipuRegs.ctrl.OFC) 
	{
		IPU_INT_FROM( 64 );
		IPUProcessInterrupt();
		return;
	}

	int readsize;
	tDMA_TAG* pMem;

	if ((!(ipu0ch.chcr.STR) || (cpuRegs.interrupt & (1 << DMAC_FROM_IPU))) || (ipu0ch.qwc == 0))
	{
		DevCon.Warning("How??");
		return;
	}

	pxAssert(!(ipu0ch.chcr.TTE));

	IPU_LOG("dmaIPU0 chcr = %lx, madr = %lx, qwc  = %lx",
	        ipu0ch.chcr._u32, ipu0ch.madr, ipu0ch.qwc);

	pxAssert(ipu0ch.chcr.MOD == NORMAL_MODE);

	pMem = dmaGetAddr(ipu0ch.madr, true);

	readsize = std::min(ipu0ch.qwc, (u16)ipuRegs.ctrl.OFC);
	ipu_fifo.out.read(pMem, readsize);

	ipu0ch.madr += readsize << 4;
	ipu0ch.qwc -= readsize; // note: qwc is u16

	
		if (dmacRegs.ctrl.STS == STS_fromIPU)   // STS == fromIPU
		{
			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;
			}
		}
		//Fixme ( voodoocycles ):
		//This was IPU_INT_FROM(readsize*BIAS );
		//This broke vids in Digital Devil Saga
		//Note that interrupting based on totalsize is just guessing..
	
	IPU_INT_FROM( readsize * BIAS );
	if(ipuRegs.ctrl.IFC > 0) IPUProcessInterrupt();

	//return readsize;
}
Exemplo n.º 12
0
int 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 == 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;
	}

	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)
	{
		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;

		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();
				}


				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

					if (!ipu1ch.transfer("IPU1", ptag))
					{
						return totalqwc;
					}
					ipu1ch.madr = ptag[1]._u32;

					ipu1cycles += 1; // Add 1 cycles from the QW read for the tag
					IPU1Status.ChainMode = ptag->ID;

					if(ipu1ch.chcr.TTE) DevCon.Warning("TTE?");
					
					IPU1Status.DMAFinished = hwDmacSrcChain(ipu1ch, ptag->ID);

					
					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;

					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;
	}

	//Do this here to prevent double settings on Chain DMA's
	if(totalqwc > 0 || ipu1ch.qwc == 0)
	{
		IPU_INT_TO(totalqwc * BIAS);
		IPUProcessInterrupt();
	}
	else 
	{
		cpuRegs.eCycle[4] = 0x9999;//IPU_INT_TO(2048);
	}

	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;
}
Exemplo n.º 13
0
int 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(ipu1dma.chcr.STR == false || IPU1Status.DMAMode == 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", ipu1dma.chcr._u32, ipu1dma.qwc);
		return 0;
	}

	IPU_LOG("IPU1 DMA Called QWC %x Finished %d In Progress %d tadr %x", ipu1dma.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress, ipu1dma.tadr);

	switch(IPU1Status.DMAMode)
	{
		case DMA_MODE_NORMAL:
			{
				IPU_LOG("Processing Normal QWC left %x Finished %d In Progress %d", ipu1dma.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress);
				if(IPU1Status.InProgress == true) totalqwc += IPU1chain();
			}
			break;

		case DMA_MODE_CHAIN:
			{
				if(IPU1Status.InProgress == true) //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", ipu1dma.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress);
					totalqwc += IPU1chain();
					//Set the TADR forward
				}


				if(IPU1Status.InProgress == false && IPU1Status.DMAFinished == false) //No transfer is ready to go so we need to set one up
				{
					tDMA_TAG* ptag = dmaGetAddr(ipu1dma.tadr, false);  //Set memory pointer to TADR

					if (!ipu1dma.transfer("IPU1", ptag))
					{
						return totalqwc;
					}

					ipu1cycles += 1; // Add 1 cycles from the QW read for the tag
					IPU1Status.ChainMode = ptag->ID;

					if(ipu1dma.chcr.TTE) DevCon.Warning("TTE?");

					switch (IPU1Status.ChainMode)
					{
						case TAG_REFE: // refe
							// do not change tadr
							//ipu1dma.tadr += 16;
							ipu1dma.tadr += 16;
							ipu1dma.madr = ptag[1]._u32;
							IPU_LOG("Tag should end on %x", ipu1dma.tadr);

							break;

						case TAG_CNT: // cnt
							ipu1dma.tadr += 16;
							ipu1dma.madr = ipu1dma.tadr;
							IPU_LOG("Tag should end on %x", ipu1dma.madr + ipu1dma.qwc * 16);
							//ipu1dma.tadr = ipu1dma.madr + (ipu1dma.qwc * 16);
							// Set the taddr to the next tag
							//IPU1Status.DMAFinished = false;
							break;

						case TAG_NEXT: // next
							ipu1dma.madr = ipu1dma.tadr + 16;
							IPU1Status.NextMem = ptag[1]._u32;
							IPU_LOG("Tag should end on %x", IPU1Status.NextMem);
							//IPU1Status.DMAFinished = false;
							break;

						case TAG_REF: // ref
							ipu1dma.madr = ptag[1]._u32;
							ipu1dma.tadr += 16;
							IPU_LOG("Tag should end on %x", ipu1dma.tadr);
							//IPU1Status.DMAFinished = false;
							break;

						case TAG_END: // end
							// do not change tadr
							ipu1dma.madr = ipu1dma.tadr + 16;
							//ipu1dma.tadr += 16;
							IPU_LOG("Tag should end on %x", ipu1dma.madr + ipu1dma.qwc * 16);

							break;

						default:
							DevCon.Error("IPU ERROR: different transfer mode!, Please report to PCSX2 Team");
							break;
					}

					//if(ipu1dma.qwc == 0) Console.Warning("Blank QWC!");
					if(ipu1dma.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, ipu1dma.qwc, ipu1dma.madr, 8 - g_BP.IFC);

					if (ipu1dma.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", ipu1dma.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress);
					totalqwc += IPU1chain();
					//Set the TADR forward
				}

			}
			break;
	}

	//Do this here to prevent double settings on Chain DMA's
	if(totalqwc > 0 || ipu1dma.qwc == 0)
	{
		IPU_INT_TO(totalqwc * BIAS);
		IPUProcessInterrupt();
	}
	else 
	{
		cpuRegs.eCycle[4] = 0x9999;//IPU_INT_TO(2048);
	}

	IPU_LOG("Completed Call IPU1 DMA QWC Remaining %x Finished %d In Progress %d tadr %x", ipu1dma.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress, ipu1dma.tadr);
	return totalqwc;
}
Exemplo n.º 14
0
__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;
	}
}
Exemplo n.º 15
0
__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;
	}
}