Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
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;
}