- Better implementation of Reverse FIFO (Fatal Frame QWC Warning and more!)

- Improved handling of suspended DMA's, Also some traps in case DMA values are changed during suspend (please report if they don't start with 5 or 6)
- Better handling of GS Path priorities, this improves many Path3 Masked games such as Star Wars Episode 3, Gran Turismo 4 (slightly) and Videos like Digital Devil Saga/FFX
- Removed Voodoo Cycles
- Doesn't kill everything this time :P

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2853 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
refraction 2010-04-15 00:32:58 +00:00
parent e170324d51
commit b1954edc3d
20 changed files with 443 additions and 218 deletions

View File

@ -401,7 +401,7 @@ static __forceinline const wxChar* ChcrName(u32 addr)
case D6_CHCR: return L"Sif 1";
case D7_CHCR: return L"Sif 2";
case D8_CHCR: return L"SPR 0";
case SPR1_CHCR: return L"SPR 1";
case D9_CHCR: return L"SPR 1";
default: return L"???";
}
}

View File

@ -60,10 +60,15 @@ void __fastcall ReadFIFO_page_5(u32 mem, u64 *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" );
if(vif1Regs->stat.FQC == 0) Console.Warning("FQC = 0 on VIF FIFO READ!");
if (vif1Regs->stat.FDR)
{
if (--psHu32(D1_QWC) == 0)
vif1Regs->stat.FQC = 0;
if (vif1Regs->stat.FQC > 0)
{
GetMTGS().WaitGS();
GSreadFIFO(&psHu64(VIF1_FIFO));
}
if(vif1Regs->stat.FQC > 0)--vif1Regs->stat.FQC;
}
out[0] = psHu64(VIF1_FIFO);

View File

@ -59,7 +59,7 @@ void gsReset()
GetMTGS().ResetGS();
UpdateVSyncRate();
GSTransferStatus = (STOPPED_MODE<<4) | (STOPPED_MODE<<2) | STOPPED_MODE;
memzero(g_RealGSMem);
GSCSRr = 0x551B4000; // Set the FINISH bit to 1 for now

View File

@ -56,22 +56,7 @@ __forceinline void gsInterrupt()
}
if ((vif1.cmd & 0x7e) == 0x50) // DIRECT/HL
{
//original behaviour here - if (Path3progress != IMAGE_MODE) vif1Regs->stat.VGW = false;
// Transfer in progress on VIF and GIF has finished so let VIF do its bit
if (Path3progress == STOPPED_MODE)
{
vif1Regs->stat.VGW = false;
CPU_INT( DMAC_GIF, 4 );
return;
}
}
if (Path3progress == STOPPED_MODE)
if (GSTransferStatus.PTH3 == STOPPED_MODE)
{
gifRegs->stat.clear_flags(GIF_STAT_APATH3 | GIF_STAT_OPH);
}
@ -90,12 +75,15 @@ __forceinline void gsInterrupt()
return;
}
if((gif->chcr.MOD == CHAIN_MODE) && ((gif->chcr.TAG >> 12) & 0x7) != 0x0 && ((gif->chcr.TAG >> 12) & 0x7) != 0x7 && !((gif->chcr.TAG >> 12) & 0x8))
DevCon.Warning("GIF Ending when refe or end not set! CHCR = %x", gif->chcr._u32);
gspath3done = false;
gscycles = 0;
gif->chcr.STR = false;
vif1Regs->stat.VGW = false;
gifRegs->stat.clear_flags(GIF_STAT_APATH3 | GIF_STAT_OPH | GIF_STAT_P3Q | GIF_STAT_FQC);
gifRegs->stat.clear_flags(GIF_STAT_APATH3 | GIF_STAT_OPH | GIF_STAT_FQC);
clearFIFOstuff(false);
hwDmacIrq(DMAC_GIF);
@ -104,9 +92,6 @@ __forceinline void gsInterrupt()
static u32 WRITERING_DMA(u32 *pMem, u32 qwc)
{
gifRegs->stat.APATH = GIF_APATH3;
gifRegs->stat.OPH = true;
int size = GetMTGS().PrepDataPacket(GIF_PATH_3, pMem, qwc);
u8* pgsmem = GetMTGS().GetDataPacketPtr();
@ -216,16 +201,24 @@ void GIFdma()
}
clearFIFOstuff(true);
gifRegs->stat.FQC |= 0x10;// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // OPH=1 | APATH=3]
gifRegs->stat.FQC = max((u16)0x10, gif->qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // OPH=1 | APATH=3]
//Path2 gets priority in intermittent mode
if ((gifRegs->stat.P1Q || (vif1.cmd & 0x7e) == 0x50) && gifRegs->mode.IMT && (Path3progress == STOPPED_MODE))
if (GSTransferStatus.PTH1 != STOPPED_MODE || GSTransferStatus.PTH2 != STOPPED_MODE)
{
// We are in image mode doing DIRECTHL, Path 1 is in queue, and in intermittant mode.
GIF_LOG("Waiting VU %x, PATH2 %x, GIFMODE %x Progress %x", gifRegs->stat.P1Q, (vif1.cmd & 0x7f), gifRegs->mode._u32, Path3progress);
//GIF_LOG("Waiting VU %x, PATH2 %x, GIFMODE %x Progress %x", gifRegs->stat.P1Q, (vif1.cmd & 0x7f), gifRegs->mode._u32, GSTransferStatus.PTH3);
/*if(GSTransferStatus.PTH3 == STOPPED_MODE)
{
} else Console.Warning("PATH3 Transfer in action while another one path is running, Path3 mode %x", GSTransferStatus.PTH3);*/
gifRegs->stat.set_flags(GIF_STAT_P2Q);
CPU_INT(DMAC_GIF, 16);
return;
}
gifRegs->stat.clear_flags(GIF_STAT_P2Q);
gifRegs->stat.APATH = GIF_APATH3;
gifRegs->stat.OPH = true;
if (vif1Regs->mskpath3 || gifRegs->mode.M3R)
{
@ -234,6 +227,7 @@ void GIFdma()
if ((gif->chcr.MOD == CHAIN_MODE) && gif->chcr.STR)
{
ptag = ReadTag();
gifRegs->stat.FQC = max((u16)0x10, gif->qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // OPH=1 | APATH=3]
if (ptag == NULL) return;
GIF_LOG("PTH3 MASK gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx", ptag[1]._u32, ptag[0]._u32, gif->qwc, ptag->ID, gif->madr);
@ -242,15 +236,17 @@ void GIFdma()
}
}
if (Path3progress == STOPPED_MODE) /*|| (vif1Regs->stat._u32 |= VIF1_STAT_VGW) == 0*/
if (GSTransferStatus.PTH3 == STOPPED_MODE) /*|| (vif1Regs->stat._u32 |= VIF1_STAT_VGW) == 0*/
{
GIF_LOG("PTH3 MASK Continuing VIF");
vif1Regs->stat.VGW = false;
if (gif->qwc == 0) CPU_INT(DMAC_GIF, 16);
return;
}
gifRegs->stat.FQC = max((u16)0x10, gif->qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // OPH=1 | APATH=3]
//Check with Path3 masking games
if (gif->qwc > 0) {
GIF_LOG("PTH3 MASK Transferring", ptag[1]._u32, ptag[0]._u32, gif->qwc, ptag->ID, gif->madr);
GIFchain();
CPU_INT(DMAC_GIF, gscycles * BIAS);
return;
@ -266,7 +262,7 @@ void GIFdma()
{
Console.WriteLn("DMA Stall Control on GIF normal");
}
gifRegs->stat.FQC = max((u16)0x10, gif->qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // OPH=1 | APATH=3]
//Check with Path3 masking games
if (gif->qwc > 0) {
GIFchain(); //Transfers the data set by the switch
@ -284,7 +280,7 @@ void GIFdma()
ptag = ReadTag();
if (ptag == NULL) return;
GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx", ptag[1]._u32, ptag[0]._u32, gif->qwc, ptag->ID, gif->madr);
gifRegs->stat.FQC = max((u16)0x10, gif->qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // OPH=1 | APATH=3]
if (dmacRegs->ctrl.STD == STD_GIF)
{
// there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall
@ -325,6 +321,7 @@ void GIFdma()
CPU_INT(DMAC_GIF, gscycles * BIAS);
gscycles = 0;
}
gifRegs->stat.FQC = max((u16)0x10, gif->qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // OPH=1 | APATH=3]
}
void dmaGIF()
@ -333,7 +330,7 @@ void dmaGIF()
//It takes the time of 24 QW for the BUS to become ready - The Punisher And Streetball
GIF_LOG("dmaGIFstart chcr = %lx, madr = %lx, qwc = %lx\n tadr = %lx, asr0 = %lx, asr1 = %lx", gif->chcr._u32, gif->madr, gif->qwc, gif->tadr, gif->asr0, gif->asr1);
Path3progress = STOPPED_MODE;
GSTransferStatus.PTH3 = STOPPED_MODE;
gspath3done = false; // For some reason this doesn't clear? So when the system starts the thread, we will clear it :)
gifRegs->stat.P3Q = true;
@ -546,7 +543,7 @@ void gifMFIFOInterrupt()
//Console.WriteLn("gifMFIFOInterrupt");
mfifocycles = 0;
if (Path3progress == STOPPED_MODE)
if (GSTransferStatus.PTH3 == STOPPED_MODE)
{
gifRegs->stat.APATH = GIF_APATH_IDLE;
gifRegs->stat.OPH = false;
@ -565,9 +562,9 @@ void gifMFIFOInterrupt()
return;
}
if ((gifRegs->stat.P1Q || (vif1.cmd & 0x7f) == 0x50) && gifRegs->mode.IMT && Path3progress == IMAGE_MODE) //Path2 gets priority in intermittent mode
if ((gifRegs->stat.P1Q || (vif1.cmd & 0x7f) == 0x50) && gifRegs->mode.IMT && GSTransferStatus.PTH3 == IMAGE_MODE) //Path2 gets priority in intermittent mode
{
//GIF_LOG("Waiting VU %x, PATH2 %x, GIFMODE %x Progress %x", psHu32(GIF_STAT) & 0x100, (vif1.cmd & 0x7f), psHu32(GIF_MODE), Path3progress);
//GIF_LOG("Waiting VU %x, PATH2 %x, GIFMODE %x Progress %x", psHu32(GIF_STAT) & 0x100, (vif1.cmd & 0x7f), psHu32(GIF_MODE), GSTransferStatus.PTH3);
CPU_INT(11,mfifocycles);
return;
}

View File

@ -26,13 +26,29 @@ enum gifstate_t
GIF_STATE_EMPTY = 0x10
};
enum Path3Modes //0 = Image Mode (DirectHL), 1 = transferring, 2 = Stopped at End of Packet
enum GSTransferModes //0 = Image Mode (DirectHL), 1 = transferring, 2 = Stopped at End of Packet
{
IMAGE_MODE = 0,
TRANSFER_MODE = 1,
STOPPED_MODE = 2
};
union tGSTransferStatus {
struct {
u32 PTH1 : 2; // Resets Vif(0/1) when written.
u32 PTH2 : 2; // Causes a Forcebreak to Vif((0/1) when true. (Stall)
u32 PTH3 : 2; // Stops after the end of the Vifcode in progress when true. (Stall)
u32 reserved : 26;
};
u32 _u32;
tGSTransferStatus(u32 val) { _u32 = val; }
bool test (u32 flags) const { return !!(_u32 & flags); }
void set_flags (u32 flags) { _u32 |= flags; }
void clear_flags(u32 flags) { _u32 &= ~flags; }
void reset() { _u32 = 0; }
wxString desc() const { return wxsFormat(L"GSTransferStatus.PTH3: 0x%x", _u32); }
};
//GIF_STAT
enum gif_stat_flags
{
@ -262,7 +278,7 @@ struct GIFregisters
#define gifRegs ((GIFregisters*)(PS2MEM_HW+0x3000))
extern Path3Modes Path3progress;
extern tGSTransferStatus GSTransferStatus;
extern void gsInterrupt();
extern int _GIFchain();

View File

@ -186,7 +186,7 @@ enum EERegisterAddresses
D8_MADR = 0x1000D010,
D8_QWC = 0x1000D020,
D8_SADR = 0x1000D080,
SPR1_CHCR = 0x1000D400,
D9_CHCR = 0x1000D400,
DMAC_CTRL = 0x1000E000,
DMAC_STAT = 0x1000E010,

View File

@ -46,7 +46,7 @@ static __forceinline void DmaExec8( void (*func)(), u32 mem, u8 value )
}
psHu8(mem) = (u8)value;
if ((psHu8(mem) & 0x1) && dmacRegs->ctrl.DMAE)
if ((psHu8(mem) & 0x1) && dmacRegs->ctrl.DMAE && !psHu8(DMAC_ENABLER+2))
{
/*Console.WriteLn("Running DMA 8 %x", psHu32(mem & ~0x1));*/
func();
@ -80,7 +80,7 @@ static __forceinline void DmaExec16( void (*func)(), u32 mem, u16 value )
}
psHu16(mem) = chcr.lower();
if (reg->chcr.STR && dmacRegs->ctrl.DMAE)
if (reg->chcr.STR && dmacRegs->ctrl.DMAE && !psHu8(DMAC_ENABLER+2))
{
//Console.WriteLn("16bit DMA Start");
func();
@ -97,10 +97,13 @@ static void DmaExec( void (*func)(), u32 mem, u32 value )
//It's invalid for the hardware to write a DMA while it is active, not without Suspending the DMAC
if (chcr.STR && reg->chcr.STR && dmacRegs->ctrl.DMAE) {
if((reg->chcr._u32 & 0xff) == (chcr._u32 & 0xff)) //Tried to start another DMA in the same mode
DevCon.Warning(L"DMAExec32 Attempt to run DMA while one is already active in %s(%x)", ChcrName(mem), mem);
else //Just trying to change mode without stopping the DMA, so we dont care really :P
HW_LOG("Attempted to change modes while DMA active, ignoring");
// When DMA is active only STR field is writable, so we just
// call the dma transfer function w/o modifying CHCR contents...
func();
//func();
Registers::Thaw();
return; // Test with Gust games and fatal frame
}
@ -122,17 +125,53 @@ static void DmaExec( void (*func)(), u32 mem, u32 value )
else /* Else (including Normal mode etc) write whatever the hardware sends*/
reg->chcr.set(value);
if (reg->chcr.STR && dmacRegs->ctrl.DMAE) func();
if (reg->chcr.STR && dmacRegs->ctrl.DMAE && !psHu8(DMAC_ENABLER+2)) func();
Registers::Thaw();
}
static bool QuickDmaExec( void (*func)(), u32 mem)
{
bool ret = false;
Registers::Freeze();
DMACh *reg = &psH_DMACh(mem);
if (reg->chcr.STR && dmacRegs->ctrl.DMAE && !psHu8(DMAC_ENABLER+2))
{
func();
ret = true;
}
Registers::Thaw();
return ret;
}
tDMAC_QUEUE QueuedDMA(0);
u32 oldvalue = 0;
void __fastcall StartQueuedDMA()
{
if (QueuedDMA.VIF0) { DMA_LOG("Resuming DMA for VIF0"); if(QuickDmaExec(dmaVIF0, D0_CHCR) == true) QueuedDMA.VIF0 = false; }
if (QueuedDMA.VIF1) { DMA_LOG("Resuming DMA for VIF1"); if(QuickDmaExec(dmaVIF1, D1_CHCR) == true) QueuedDMA.VIF0 = false; }
if (QueuedDMA.GIF ) { DMA_LOG("Resuming DMA for GIF" ); if(QuickDmaExec(dmaGIF , D2_CHCR) == true) QueuedDMA.GIF = false; }
if (QueuedDMA.IPU0) { DMA_LOG("Resuming DMA for IPU0"); if(QuickDmaExec(dmaIPU0, D3_CHCR) == true) QueuedDMA.IPU0 = false; }
if (QueuedDMA.IPU1) { DMA_LOG("Resuming DMA for IPU1"); if(QuickDmaExec(dmaIPU1, D4_CHCR) == true) QueuedDMA.IPU1 = false; }
if (QueuedDMA.SIF0) { DMA_LOG("Resuming DMA for SIF0"); if(QuickDmaExec(dmaSIF0, D5_CHCR) == true) QueuedDMA.SIF0 = false; }
if (QueuedDMA.SIF1) { DMA_LOG("Resuming DMA for SIF1"); if(QuickDmaExec(dmaSIF1, D6_CHCR) == true) QueuedDMA.SIF1 = false; }
if (QueuedDMA.SIF2) { DMA_LOG("Resuming DMA for SIF2"); if(QuickDmaExec(dmaSIF2, D7_CHCR) == true) QueuedDMA.SIF2 = false; }
if (QueuedDMA.SPR0) { DMA_LOG("Resuming DMA for SPR0"); if(QuickDmaExec(dmaSPR0, D8_CHCR) == true) QueuedDMA.SPR0 = false; }
if (QueuedDMA.SPR1) { DMA_LOG("Resuming DMA for SPR1"); if(QuickDmaExec(dmaSPR1, D9_CHCR) == true) QueuedDMA.SPR1 = false; }
}
/////////////////////////////////////////////////////////////////////////
// Hardware WRITE 8 bit
char sio_buffer[1024];
int sio_count;
tDMAC_QUEUE QueuedDMA(0);
void hwWrite8(u32 mem, u8 value)
{
@ -200,9 +239,9 @@ void hwWrite8(u32 mem, u8 value)
DMA_LOG("VIF0dma EXECUTE, value=0x%x", value);
if ((value & 0x1) && !dmacRegs->ctrl.DMAE)
{
DevCon.Warning("8 bit VIF0 DMA Start while DMAC Disabled\n");
//DevCon.Warning("8 bit VIF0 DMA Start while DMAC Disabled\n");
QueuedDMA.VIF0 = true;
}
} else QueuedDMA.VIF0 = false;
DmaExec8(dmaVIF0, mem, value);
break;
@ -210,9 +249,9 @@ void hwWrite8(u32 mem, u8 value)
DMA_LOG("VIF1dma EXECUTE, value=0x%x", value);
if ((value & 0x1) && !dmacRegs->ctrl.DMAE)
{
DevCon.Warning("8 bit VIF1 DMA Start while DMAC Disabled\n");
//DevCon.Warning("8 bit VIF1 DMA Start while DMAC Disabled\n");
QueuedDMA.VIF1 = true;
}
} else QueuedDMA.VIF1 = false;
if(value & 0x1) vif1.done = false; //This must be done here! some games (ala Crash of the Titans) pause the dma to start MFIFO
DmaExec8(dmaVIF1, mem, value);
break;
@ -221,9 +260,9 @@ void hwWrite8(u32 mem, u8 value)
DMA_LOG("GSdma EXECUTE, value=0x%x", value);
if ((value & 0x1) && !dmacRegs->ctrl.DMAE)
{
DevCon.Warning("8 bit GIF DMA Start while DMAC Disabled\n");
//DevCon.Warning("8 bit GIF DMA Start while DMAC Disabled\n");
QueuedDMA.GIF = true;
}
} else QueuedDMA.GIF = false;
DmaExec8(dmaGIF, mem, value);
break;
@ -231,9 +270,9 @@ void hwWrite8(u32 mem, u8 value)
DMA_LOG("IPU0dma EXECUTE, value=0x%x", value);
if ((value & 0x1) && !dmacRegs->ctrl.DMAE)
{
DevCon.Warning("8 bit IPU0 DMA Start while DMAC Disabled\n");
//DevCon.Warning("8 bit IPU0 DMA Start while DMAC Disabled\n");
QueuedDMA.IPU0 = true;
}
} else QueuedDMA.IPU0 = false;
DmaExec8(dmaIPU0, mem, value);
break;
@ -241,9 +280,9 @@ void hwWrite8(u32 mem, u8 value)
DMA_LOG("IPU1dma EXECUTE, value=0x%x", value);
if ((value & 0x1) && !dmacRegs->ctrl.DMAE)
{
DevCon.Warning("8 bit IPU1 DMA Start while DMAC Disabled\n");
//DevCon.Warning("8 bit IPU1 DMA Start while DMAC Disabled\n");
QueuedDMA.IPU1 = true;
}
} else QueuedDMA.IPU1 = false;
DmaExec8(dmaIPU1, mem, value);
break;
@ -252,9 +291,9 @@ void hwWrite8(u32 mem, u8 value)
// if (value == 0) psxSu32(0x30) = 0x40000;
if ((value & 0x1) && !dmacRegs->ctrl.DMAE)
{
DevCon.Warning("8 bit SIF0 DMA Start while DMAC Disabled\n");
//DevCon.Warning("8 bit SIF0 DMA Start while DMAC Disabled\n");
QueuedDMA.SIF0 = true;
}
} else QueuedDMA.SIF0 = false;
DmaExec8(dmaSIF0, mem, value);
break;
@ -262,9 +301,9 @@ void hwWrite8(u32 mem, u8 value)
DMA_LOG("SIF1dma EXECUTE, value=0x%x", value);
if ((value & 0x1) && !dmacRegs->ctrl.DMAE)
{
DevCon.Warning("8 bit SIF1 DMA Start while DMAC Disabled\n");
//DevCon.Warning("8 bit SIF1 DMA Start while DMAC Disabled\n");
QueuedDMA.SIF1 = true;
}
} else QueuedDMA.SIF1 = false;
DmaExec8(dmaSIF1, mem, value);
break;
@ -272,9 +311,9 @@ void hwWrite8(u32 mem, u8 value)
DMA_LOG("SIF2dma EXECUTE, value=0x%x", value);
if ((value & 0x1) && !dmacRegs->ctrl.DMAE)
{
DevCon.Warning("8 bit SIF2 DMA Start while DMAC Disabled\n");
//DevCon.Warning("8 bit SIF2 DMA Start while DMAC Disabled\n");
QueuedDMA.SIF2 |= true;
}
} else QueuedDMA.SIF2 = false;
DmaExec8(dmaSIF2, mem, value);
break;
@ -282,25 +321,30 @@ void hwWrite8(u32 mem, u8 value)
DMA_LOG("fromSPRdma8 EXECUTE, value=0x%x", value);
if ((value & 0x1) && !dmacRegs->ctrl.DMAE)
{
DevCon.Warning("8 bit SPR0 DMA Start while DMAC Disabled\n");
//DevCon.Warning("8 bit SPR0 DMA Start while DMAC Disabled\n");
QueuedDMA.SPR0 = true;
}
} else QueuedDMA.SPR0 = false;
DmaExec8(dmaSPR0, mem, value);
break;
case SPR1_CHCR + 1: // dma9 - toSPR
case D9_CHCR + 1: // dma9 - toSPR
DMA_LOG("toSPRdma8 EXECUTE, value=0x%x", value);
if ((value & 0x1) && !dmacRegs->ctrl.DMAE)
{
DevCon.Warning("8 bit SPR1 DMA Start while DMAC Disabled\n");
//DevCon.Warning("8 bit SPR1 DMA Start while DMAC Disabled\n");
QueuedDMA .SPR1 = true;
}
} else QueuedDMA.SPR1 = false;
DmaExec8(dmaSPR1, mem, value);
break;
case DMAC_ENABLEW + 2:
oldvalue = psHu8(DMAC_ENABLEW + 2);
psHu8(DMAC_ENABLEW + 2) = value;
psHu8(DMAC_ENABLER + 2) = value;
if (((oldvalue & 0x1) == 1) && ((value & 0x1) == 0))
{
if (!QueuedDMA.empty()) StartQueuedDMA();
}
break;
case SBUS_F200: // SIF(?)
@ -375,21 +419,21 @@ __forceinline void hwWrite16(u32 mem, u16 value)
case D0_CHCR: // dma0 - vif0
DMA_LOG("VIF0dma %lx", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("16 bit VIF0 DMA Start while DMAC Disabled\n");
//DevCon.Warning("16 bit VIF0 DMA Start while DMAC Disabled\n");
QueuedDMA.VIF0 = true;
}
} else QueuedDMA.VIF0 = false;
DmaExec16(dmaVIF0, mem, value);
break;
case D1_CHCR: // dma1 - vif1 - chcr
DMA_LOG("VIF1dma CHCR %lx", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("16 bit VIF1 DMA Start while DMAC Disabled\n");
//DevCon.Warning("16 bit VIF1 DMA Start while DMAC Disabled\n");
QueuedDMA.VIF1 = true;
}
} else QueuedDMA.VIF1 = false;
if (CHCR(value).STR) vif1.done = false; //This must be done here! some games (ala Crash of the Titans) pause the dma to start MFIFO
DmaExec16(dmaVIF1, mem, value);
@ -430,11 +474,11 @@ __forceinline void hwWrite16(u32 mem, u16 value)
case D2_CHCR: // dma2 - gif
DMA_LOG("0x%8.8x hwWrite32: GSdma %lx", cpuRegs.cycle, value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("16 bit GIF DMA Start while DMAC Disabled\n");
//DevCon.Warning("16 bit GIF DMA Start while DMAC Disabled\n");
QueuedDMA.GIF = true;
}
} else QueuedDMA.GIF = false;
DmaExec16(dmaGIF, mem, value);
break;
@ -472,11 +516,11 @@ __forceinline void hwWrite16(u32 mem, u16 value)
case D3_CHCR: // dma3 - fromIPU
DMA_LOG("IPU0dma %lx", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("16 bit IPU0 DMA Start while DMAC Disabled\n");
//DevCon.Warning("16 bit IPU0 DMA Start while DMAC Disabled\n");
QueuedDMA.IPU0 = true;
}
} else QueuedDMA.IPU0 = false;
DmaExec16(dmaIPU0, mem, value);
break;
@ -504,11 +548,11 @@ __forceinline void hwWrite16(u32 mem, u16 value)
case D4_CHCR: // dma4 - toIPU
DMA_LOG("IPU1dma %lx", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("16 bit IPU1 DMA Start while DMAC Disabled\n");
//DevCon.Warning("16 bit IPU1 DMA Start while DMAC Disabled\n");
QueuedDMA.IPU1 = true;
}
} else QueuedDMA.IPU1 = false;
DmaExec16(dmaIPU1, mem, value);
break;
@ -536,11 +580,11 @@ __forceinline void hwWrite16(u32 mem, u16 value)
case D5_CHCR: // dma5 - sif0
DMA_LOG("SIF0dma %lx", value);
// if (value == 0) psxSu32(0x30) = 0x40000;
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("16 bit SIF0 DMA Start while DMAC Disabled\n");
//DevCon.Warning("16 bit SIF0 DMA Start while DMAC Disabled\n");
QueuedDMA.SIF0 = true;
}
} else QueuedDMA.SIF0 = false;
DmaExec16(dmaSIF0, mem, value);
break;
@ -550,11 +594,11 @@ __forceinline void hwWrite16(u32 mem, u16 value)
case D6_CHCR: // dma6 - sif1
DMA_LOG("SIF1dma %lx", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("16 bit SIF1 DMA Start while DMAC Disabled\n");
//DevCon.Warning("16 bit SIF1 DMA Start while DMAC Disabled\n");
QueuedDMA.SIF1 = true;
}
} else QueuedDMA.SIF1 = false;
DmaExec16(dmaSIF1, mem, value);
break;
@ -582,11 +626,11 @@ __forceinline void hwWrite16(u32 mem, u16 value)
case D7_CHCR: // dma7 - sif2
DMA_LOG("SIF2dma %lx", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("16 bit SIF2 DMA Start while DMAC Disabled\n");
//DevCon.Warning("16 bit SIF2 DMA Start while DMAC Disabled\n");
QueuedDMA.SIF2 = true;
}
} else QueuedDMA.SIF2 = false;
DmaExec16(dmaSIF2, mem, value);
break;
@ -596,27 +640,32 @@ __forceinline void hwWrite16(u32 mem, u16 value)
case D8_CHCR: // dma8 - fromSPR
DMA_LOG("fromSPRdma %lx", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("16 bit SPR0 DMA Start while DMAC Disabled\n");
//DevCon.Warning("16 bit SPR0 DMA Start while DMAC Disabled\n");
QueuedDMA.SPR0 = true;
}
} else QueuedDMA.SPR0 = false;
DmaExec16(dmaSPR0, mem, value);
break;
case SPR1_CHCR: // dma9 - toSPR
case D9_CHCR: // dma9 - toSPR
DMA_LOG("toSPRdma %lx", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("16 bit SPR1 DMA Start while DMAC Disabled\n");
//DevCon.Warning("16 bit SPR1 DMA Start while DMAC Disabled\n");
QueuedDMA.SPR1 = true;
}
} else QueuedDMA.SPR1 = false;
DmaExec16(dmaSPR1, mem, value);
break;
case DMAC_ENABLEW + 2:
oldvalue = psHu8(DMAC_ENABLEW + 2);
psHu16(DMAC_ENABLEW + 2) = value;
psHu16(DMAC_ENABLER + 2) = value;
if (((oldvalue & 0x1) == 1) && ((value & 0x1) == 0))
{
if (!QueuedDMA.empty()) StartQueuedDMA();
}
break;
case SIO_ISR:
@ -764,11 +813,11 @@ void __fastcall hwWrite32_page_0B( u32 mem, u32 value )
{
case D3_CHCR: // dma3 - fromIPU
DMA_LOG("IPU0dma EXECUTE, value=0x%x\n", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("32 bit IPU0 DMA Start while DMAC Disabled\n");
//DevCon.Warning("32 bit IPU0 DMA Start while DMAC Disabled\n");
QueuedDMA.IPU0 = true;
}
} else QueuedDMA.IPU0 = false;
DmaExec(dmaIPU0, mem, value);
return;
@ -781,11 +830,11 @@ void __fastcall hwWrite32_page_0B( u32 mem, u32 value )
case D4_CHCR: // dma4 - toIPU
DMA_LOG("IPU1dma EXECUTE, value=0x%x\n", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("32 bit IPU1 DMA Start while DMAC Disabled\n");
//DevCon.Warning("32 bit IPU1 DMA Start while DMAC Disabled\n");
QueuedDMA.IPU1 = true;
}
} else QueuedDMA.IPU1 = false;
DmaExec(dmaIPU1, mem, value);
return;
@ -799,19 +848,7 @@ void __fastcall hwWrite32_page_0B( u32 mem, u32 value )
psHu32(mem) = value;
}
void __fastcall StartQueuedDMA()
{
if (QueuedDMA.VIF0) { QueuedDMA.VIF0 = false; dmaVIF0(); }
if (QueuedDMA.VIF1) { QueuedDMA.VIF1 = false; dmaVIF1(); }
if (QueuedDMA.GIF ) { QueuedDMA.GIF = false; dmaGIF(); }
if (QueuedDMA.IPU0) { QueuedDMA.IPU0 = false; dmaIPU0(); }
if (QueuedDMA.IPU1) { QueuedDMA.IPU1 = false; dmaIPU1(); }
if (QueuedDMA.SIF0) { QueuedDMA.SIF0 = false; dmaSIF0(); }
if (QueuedDMA.SIF1) { QueuedDMA.SIF1 = false; dmaSIF1(); }
if (QueuedDMA.SIF2) { QueuedDMA.SIF2 = false; dmaSIF2(); }
if (QueuedDMA.SPR0) { QueuedDMA.SPR0 = false; dmaSPR0(); }
if (QueuedDMA.SPR1) { QueuedDMA.SPR1 = false; dmaSPR1(); }
}
void __fastcall hwWrite32_page_0E( u32 mem, u32 value )
{
@ -907,8 +944,13 @@ void __fastcall hwWrite32_page_0F( u32 mem, u32 value )
case HELPSWITCH(DMAC_ENABLEW):
HW_LOG("DMAC_ENABLEW Write 32bit %lx", value);
oldvalue = psHu8(DMAC_ENABLEW + 2);
psHu32(DMAC_ENABLEW) = value;
psHu32(DMAC_ENABLER) = value;
if (((oldvalue & 0x1) == 1) && (((value >> 16) & 0x1) == 0))
{
if (!QueuedDMA.empty()) StartQueuedDMA();
}
break;
//------------------------------------------------------------------
@ -932,11 +974,11 @@ void __fastcall hwWrite32_generic( u32 mem, u32 value )
case D0_CHCR: // dma0 - vif0
DMA_LOG("VIF0dma EXECUTE, value=0x%x", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("32 bit VIF0 DMA Start while DMAC Disabled\n");
//DevCon.Warning("32 bit VIF0 DMA Start while DMAC Disabled\n");
QueuedDMA.VIF0 = true;
}
} else QueuedDMA.VIF0 = false;
DmaExec(dmaVIF0, mem, value);
return;
@ -945,11 +987,11 @@ void __fastcall hwWrite32_generic( u32 mem, u32 value )
case D1_CHCR: // dma1 - vif1 - chcr
DMA_LOG("VIF1dma EXECUTE, value=0x%x", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("32 bit VIF1 DMA Start while DMAC Disabled\n");
//DevCon.Warning("32 bit VIF1 DMA Start while DMAC Disabled\n");
QueuedDMA.VIF1 = true;
}
} else QueuedDMA.VIF1 = false;
if (CHCR(value).STR)
{
@ -973,11 +1015,11 @@ void __fastcall hwWrite32_generic( u32 mem, u32 value )
//------------------------------------------------------------------
case D2_CHCR: // dma2 - gif
DMA_LOG("GIFdma EXECUTE, value=0x%x", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("32 bit GIF DMA Start while DMAC Disabled\n");
//DevCon.Warning("32 bit GIF DMA Start while DMAC Disabled\n");
QueuedDMA.GIF = true;
}
} else QueuedDMA.GIF = false;
DmaExec(dmaGIF, mem, value);
return;
@ -992,21 +1034,21 @@ void __fastcall hwWrite32_generic( u32 mem, u32 value )
case D5_CHCR: // dma5 - sif0
DMA_LOG("SIF0dma EXECUTE, value=0x%x", value);
//if (value == 0) psxSu32(0x30) = 0x40000;
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("32 bit SIF0 DMA Start while DMAC Disabled\n");
//DevCon.Warning("32 bit SIF0 DMA Start while DMAC Disabled\n");
QueuedDMA.SIF0 = true;
}
} else QueuedDMA.SIF0 = false;
DmaExec(dmaSIF0, mem, value);
return;
//------------------------------------------------------------------
case D6_CHCR: // dma6 - sif1
DMA_LOG("SIF1dma EXECUTE, value=0x%x", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("32 bit SIF1 DMA Start while DMAC Disabled\n");
//DevCon.Warning("32 bit SIF1 DMA Start while DMAC Disabled\n");
QueuedDMA.SIF1 = true;
}
} else QueuedDMA.SIF1 = false;
DmaExec(dmaSIF1, mem, value);
return;
@ -1017,31 +1059,31 @@ void __fastcall hwWrite32_generic( u32 mem, u32 value )
//------------------------------------------------------------------
case D7_CHCR: // dma7 - sif2
DMA_LOG("SIF2dma EXECUTE, value=0x%x", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("32 bit SIF2 DMA Start while DMAC Disabled\n");
//DevCon.Warning("32 bit SIF2 DMA Start while DMAC Disabled\n");
QueuedDMA.SIF2 = true;
}
} else QueuedDMA.SIF2 = false;
DmaExec(dmaSIF2, mem, value);
return;
//------------------------------------------------------------------
case D8_CHCR: // dma8 - fromSPR
DMA_LOG("SPR0dma EXECUTE (fromSPR), value=0x%x", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("32 bit SPR0 DMA Start while DMAC Disabled\n");
//DevCon.Warning("32 bit SPR0 DMA Start while DMAC Disabled\n");
QueuedDMA.SPR0 = true;
}
} else QueuedDMA.SPR0 = false;
DmaExec(dmaSPR0, mem, value);
return;
//------------------------------------------------------------------
case SPR1_CHCR: // dma9 - toSPR
case D9_CHCR: // dma9 - toSPR
DMA_LOG("SPR1dma EXECUTE (toSPR), value=0x%x", value);
if (CHCR(value).STR && !dmacRegs->ctrl.DMAE)
if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2)))
{
DevCon.Warning("32 bit SPR1 DMA Start while DMAC Disabled\n");
//DevCon.Warning("32 bit SPR1 DMA Start while DMAC Disabled\n");
QueuedDMA.SPR1 = true;
}
} else QueuedDMA.SPR1 = false;
DmaExec(dmaSPR1, mem, value);
return;
}
@ -1189,8 +1231,13 @@ void __fastcall hwWrite64_generic( u32 mem, const mem64_t* srcval )
break;
case DMAC_ENABLEW: // DMAC_ENABLEW
oldvalue = psHu8(DMAC_ENABLEW + 2);
psHu32(DMAC_ENABLEW) = value;
psHu32(DMAC_ENABLER) = value;
if (((oldvalue & 0x1) == 1) && (((value >> 16) & 0x1) == 0))
{
if (!QueuedDMA.empty()) StartQueuedDMA();
}
break;
default:
@ -1222,8 +1269,13 @@ void __fastcall hwWrite128_generic(u32 mem, const mem128_t *srcval)
break;
case DMAC_ENABLEW: // DMAC_ENABLEW
oldvalue = psHu8(DMAC_ENABLEW + 2);
psHu32(DMAC_ENABLEW) = srcval[0];
psHu32(DMAC_ENABLER) = srcval[0];
if (((oldvalue & 0x1) == 1) && (((srcval[0] >> 16) & 0x1) == 0))
{
if (!QueuedDMA.empty()) StartQueuedDMA();
}
break;
case SIO_ISR:

View File

@ -796,7 +796,7 @@ void IPUCMD_WRITE(u32 val)
// have to resort to the thread
ipu_cmd.current = val >> 28;
ipuRegs->ctrl.BUSY = 1;
hwIntcIrq(INTC_IPU);
if(ipu1dma->qwc == 0) hwIntcIrq(INTC_IPU);
}
void IPUWorker()
@ -808,7 +808,7 @@ void IPUWorker()
case SCE_IPU_VDEC:
if (!ipuVDEC(ipuRegs->cmd.DATA))
{
hwIntcIrq(INTC_IPU);
if(ipu1dma->qwc == 0) hwIntcIrq(INTC_IPU);
return;
}
ipuRegs->cmd.BUSY = 0;
@ -818,7 +818,7 @@ void IPUWorker()
case SCE_IPU_FDEC:
if (!ipuFDEC(ipuRegs->cmd.DATA))
{
hwIntcIrq(INTC_IPU);
if(ipu1dma->qwc == 0) hwIntcIrq(INTC_IPU);
return;
}
ipuRegs->cmd.BUSY = 0;
@ -828,7 +828,7 @@ void IPUWorker()
case SCE_IPU_SETIQ:
if (!ipuSETIQ(ipuRegs->cmd.DATA))
{
hwIntcIrq(INTC_IPU);
if(ipu1dma->qwc == 0) hwIntcIrq(INTC_IPU);
return;
}
break;
@ -836,7 +836,7 @@ void IPUWorker()
case SCE_IPU_SETVQ:
if (!ipuSETVQ(ipuRegs->cmd.DATA))
{
hwIntcIrq(INTC_IPU);
if(ipu1dma->qwc == 0) hwIntcIrq(INTC_IPU);
return;
}
break;
@ -844,7 +844,7 @@ void IPUWorker()
case SCE_IPU_CSC:
if (!ipuCSC(ipuRegs->cmd.DATA))
{
hwIntcIrq(INTC_IPU);
if(ipu1dma->qwc == 0) hwIntcIrq(INTC_IPU);
return;
}
if (ipu0dma->qwc > 0 && ipu0dma->chcr.STR) IPU_INT0_FROM();
@ -853,7 +853,7 @@ void IPUWorker()
case SCE_IPU_PACK:
if (!ipuPACK(ipuRegs->cmd.DATA))
{
hwIntcIrq(INTC_IPU);
if(ipu1dma->qwc == 0) hwIntcIrq(INTC_IPU);
return;
}
break;
@ -862,7 +862,7 @@ void IPUWorker()
so_call(s_routine);
if (!s_RoutineDone)
{
hwIntcIrq(INTC_IPU);
if(ipu1dma->qwc == 0) hwIntcIrq(INTC_IPU);
return;
}
@ -881,7 +881,7 @@ void IPUWorker()
so_call(s_routine);
if (!s_RoutineDone)
{
hwIntcIrq(INTC_IPU);
if(ipu1dma->qwc == 0) hwIntcIrq(INTC_IPU);
return;
}
@ -1276,6 +1276,30 @@ static __forceinline void ipuDmacSrcChain()
}
}
static __forceinline bool WaitGSPaths()
{
if (dmacRegs->ctrl.STD != STD_GIF || (gif->madr + (gif->qwc * 16)) < dmacRegs->stadr.ADDR)
{
if(gif->chcr.STR && (vif1Regs->mskpath3 == 0) && GSTransferStatus.PTH3 != STOPPED_MODE)
{
GIF_LOG("Flushing gif chcr %x tadr %x madr %x qwc %x", gif->chcr._u32, gif->tadr, gif->madr, gif->qwc);
//DevCon.WriteLn("Waiting for GIF");
return false;
}
}
if(GSTransferStatus.PTH2 != STOPPED_MODE)
{
//DevCon.WriteLn("Waiting for VIF");
return false;
}
if(GSTransferStatus.PTH1 != STOPPED_MODE)
{
//DevCon.WriteLn("Waiting for VU");
return false;
}
return true;
}
static __forceinline int IPU1chain() {
int totalqwc = 0;
@ -1304,7 +1328,7 @@ static __forceinline int IPU1chain() {
//If the transfer has finished or we have room in the FIFO, schedule to the interrupt code.
if(IPU1Status.DMAFinished == true || g_BP.IFC < 8)
{
IPU_INT_TO(totalqwc*BIAS);
IPU_INT_TO(4);
}
//No data left
IPU1Status.InProgress = false;
@ -1314,7 +1338,7 @@ static __forceinline int IPU1chain() {
return totalqwc;
}
//static __forceinline bool flushGIF()
//static __forceinline bool WaitGSPaths()
//{
// //Wait for all GS paths to be clear
// if (GSTransferStatus._u32 != 0x2a)
@ -1327,17 +1351,7 @@ static __forceinline int IPU1chain() {
// return true;
//}
static __forceinline void flushGIF()
{
if (dmacRegs->ctrl.STD != STD_GIF || (gif->madr + (gif->qwc * 16)) < dmacRegs->stadr.ADDR)
{
while(gif->chcr.STR && (vif1Regs->mskpath3 == 0) && Path3progress != STOPPED_MODE)
{
GIF_LOG("Flushing gif chcr %x tadr %x madr %x qwc %x", gif->chcr._u32, gif->tadr, gif->madr, gif->qwc);
gsInterrupt();
}
}
}
int IPU1dma()
{
@ -1346,9 +1360,9 @@ int IPU1dma()
int totalqwc = 0;
//We need to make sure GIF has flushed before sending IPU data, it seems to REALLY screw FFX videos
//if(!flushGIF()) return totalqwc;
//if(!WaitGSPaths()) return totalqwc;
flushGIF(); // legacy flushGIF() for now
DMA_LOG("IPU1 DMA Called QWC %x Finished %d In Progress %d tadr %x", ipu1dma->qwc, IPU1Status.DMAFinished, IPU1Status.InProgress, ipu1dma->tadr);
@ -1356,6 +1370,11 @@ int IPU1dma()
{
case DMA_MODE_NORMAL:
{
if(!WaitGSPaths())
{ // legacy WaitGSPaths() for now
if(totalqwc == 0)IPU_INT_TO(4); //Give it a short wait.
return totalqwc;
}
DMA_LOG("Processing Normal QWC left %x Finished %d In Progress %d", ipu1dma->qwc, IPU1Status.DMAFinished, IPU1Status.InProgress);
if(IPU1Status.InProgress == true) totalqwc += IPU1chain();
}
@ -1365,6 +1384,11 @@ int IPU1dma()
{
if(IPU1Status.InProgress == true) //No transfer is ready to go so we need to set one up
{
if(!WaitGSPaths())
{ // legacy WaitGSPaths() for now
if(totalqwc == 0)IPU_INT_TO(4); //Give it a short wait.
return totalqwc;
}
DMA_LOG("Processing Chain QWC left %x Finished %d In Progress %d", ipu1dma->qwc, IPU1Status.DMAFinished, IPU1Status.InProgress);
totalqwc += IPU1chain();
//Set the TADR forward
@ -1449,7 +1473,11 @@ int IPU1dma()
IPU1Status.DMAFinished = true;
if(!WaitGSPaths() && ipu1dma->qwc > 0)
{ // legacy WaitGSPaths() for now
if(totalqwc == 0)IPU_INT_TO(4); //Give it a short wait.
return totalqwc;
}
DMA_LOG("Processing Start Chain QWC left %x Finished %d In Progress %d", ipu1dma->qwc, IPU1Status.DMAFinished, IPU1Status.InProgress);
totalqwc += IPU1chain();
//Set the TADR forward
@ -1469,15 +1497,6 @@ int IPU0dma()
static int totalsize = 0;
tDMA_TAG* pMem;
// Note: pad is the padding right above qwc, so we're testing whether qwc
// has overflowed into pad.
if (ipu0dma->pad != 0)
{
DevCon.Warning(L"IPU0dma's upper 16 bits set to %x\n", ipu0dma->pad);
ipu0dma->qwc = ipu0dma->pad = 0;
//return 0;
}
if ((!(ipu0dma->chcr.STR) || (cpuRegs.interrupt & (1 << DMAC_FROM_IPU))) || (ipu0dma->qwc == 0))
return 0;
@ -1533,6 +1552,16 @@ int IPU0dma()
__forceinline void dmaIPU0() // fromIPU
{
if (ipu0dma->pad != 0)
{
// Note: pad is the padding right above qwc, so we're testing whether qwc
// has overflowed into pad.
DevCon.Warning(L"IPU0dma's upper 16 bits set to %x\n", ipu0dma->pad);
ipu0dma->qwc = ipu0dma->pad = 0;
//If we are going to clear down IPU0, we should end it too. Going to test this scenario on the PS2 mind - Refraction
ipu0dma->chcr.STR = false;
hwDmacIrq(DMAC_FROM_IPU);
}
if (ipuRegs->ctrl.BUSY) IPUWorker();
}
@ -1556,7 +1585,6 @@ __forceinline void dmaIPU1() // toIPU
}
IPU1Status.DMAMode = DMA_MODE_CHAIN;
IPU1dma();
if (ipuRegs->ctrl.BUSY) IPUWorker();
}
@ -1583,8 +1611,6 @@ __forceinline void dmaIPU1() // toIPU
if (ipuRegs->ctrl.BUSY) IPUWorker();
}
}
}
extern void GIFdma();

View File

@ -270,6 +270,11 @@ static __forceinline void TESTINT( u8 n, void (*callback)() )
static __forceinline void _cpuTestInterrupts()
{
if (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2))
{
//Console.Write("DMAC Disabled or suspended");
return;
}
/* These are 'pcsx2 interrupts', they handle asynchronous stuff
that depends on the cycle timings */

View File

@ -251,6 +251,10 @@ void SPRFROMinterrupt()
}
}
if (!spr0finished) return;
if((spr0->chcr.MOD == CHAIN_MODE) && ((spr0->chcr.TAG >> 12) & 0x7) != 0x0 && ((spr0->chcr.TAG >> 12) & 0x7) != 0x7 && !((spr0->chcr.TAG >> 12) & 0x8))
DevCon.Warning("SPR0 Ending when refe or end not set! CHCR = %x", spr0->chcr._u32);
spr0->chcr.STR = false;
hwDmacIrq(DMAC_FROM_SPR);
}
@ -424,6 +428,10 @@ void SPRTOinterrupt()
{
_dmaSPR1();
if (!spr1finished) return;
if((spr1->chcr.MOD == CHAIN_MODE) && ((spr1->chcr.TAG >> 12) & 0x7) != 0x0 && ((spr1->chcr.TAG >> 12) & 0x7) != 0x7 && !((spr1->chcr.TAG >> 12) & 0x8))
DevCon.Warning("SPR1 Ending when refe or end not set! CHCR = %x", spr1->chcr._u32);
spr1->chcr.STR = false;
hwDmacIrq(DMAC_TO_SPR);
}

View File

@ -151,6 +151,9 @@ static __forceinline void EndEE()
SIF_LOG("SIF0 EE: cycles = 0");
sif0.ee.cycles = 1;
}
if((sif0dma->chcr.MOD == CHAIN_MODE) && ((sif0dma->chcr.TAG >> 12) & 0x7) != 0x0 && ((sif0dma->chcr.TAG >> 12) & 0x7) != 0x7 && !((sif0dma->chcr.TAG >> 12) & 0x8))
DevCon.Warning("SIF0 Ending when refe or end not set! CHCR = %x", sif0dma->chcr._u32);
CPU_INT(DMAC_SIF0, sif0.ee.cycles*BIAS);
}

View File

@ -174,6 +174,10 @@ static __forceinline void EndEE()
SIF_LOG("SIF1 EE: cycles = 0");
sif1.ee.cycles = 1;
}
if((sif1dma->chcr.MOD == CHAIN_MODE) && ((sif1dma->chcr.TAG >> 12) & 0x7) != 0x0 && ((sif1dma->chcr.TAG >> 12) & 0x7) != 0x7 && !((sif1dma->chcr.TAG >> 12) & 0x8))
DevCon.Warning("SIF0 Ending when refe or end not set! CHCR = %x", sif1dma->chcr._u32);
CPU_INT(DMAC_SIF1, min((int)(sif1.ee.cycles*BIAS), 384));
}

View File

@ -23,7 +23,7 @@
vifStruct vif0;
vifStruct vif1;
Path3Modes Path3progress = STOPPED_MODE;
tGSTransferStatus GSTransferStatus = (STOPPED_MODE<<4) | (STOPPED_MODE<<2) | STOPPED_MODE;
void vif0Init() { initNewVif(0); }
void vif1Init() { initNewVif(1); }
@ -253,13 +253,20 @@ _f void vif1STAT(u32 value) {
if (vif1Regs->stat.FDR) // Vif transferring to memory.
{
// Hack but it checks this is true before transfer? (fatal frame)
vif1Regs->stat.FQC = 0x1;
// Update Refraction: Use of this function has been investigated and understood.
// Before this ever happens, a DIRECT/HL command takes place sending the transfer info to the GS
// One of the registers told about this is TRXREG which tells us how much data is going to transfer (th x tw) in words
// As far as the GS is concerned, the transfer starts as soon as TRXREG is accessed, which is why fatal frame
// was expecting data, the GS should already be sending it over (buffering in the FIFO)
vif1Regs->stat.FQC = max((u32)16, vif1.GSLastTRXPOS);
//Console.Warning("Reversing VIF Transfer for %x QWC", vif1.GSLastTRXPOS);
}
else // Memory transferring to Vif.
{
vif1ch->qwc = 0;
vif1.vifstalled = false;
vif1.done = true;
//Sometimes the value from the GS is bigger than vif wanted, so it just sets it back and cancels it.
//Other times it can read it off ;)
vif1Regs->stat.FQC = 0;
}
}

View File

@ -152,7 +152,7 @@ __forceinline void vif0Interrupt()
// VIF_NORMAL_FROM_MEM_MODE is a very slow operation.
// Timesplitters 2 depends on this beeing a bit higher than 128.
if (vif0.dmamode == VIF_NORMAL_FROM_MEM_MODE ) CPU_INT(DMAC_VIF0, 1024);
else CPU_INT(DMAC_VIF0, /*g_vifCycles*/ VifCycleVoodoo);
else CPU_INT(DMAC_VIF0, g_vifCycles);
return;
}
@ -167,7 +167,7 @@ __forceinline void vif0Interrupt()
if ((vif0.inprogress & 0x1) == 0) vif0SetupTransfer();
CPU_INT(DMAC_VIF0, /*g_vifCycles*/ VifCycleVoodoo);
CPU_INT(DMAC_VIF0, g_vifCycles);
return;
}
@ -182,6 +182,9 @@ __forceinline void vif0Interrupt()
if (vif0.cmd != 0) Console.WriteLn("vif0.cmd still set %x tag size %x", vif0.cmd, vif0.tag.size);
#endif
/*if(vif0.dmamode == VIF_CHAIN_MODE && ((vif0ch->chcr.TAG >> 12) & 0x7) != 0x0 && ((vif0ch->chcr.TAG >> 12) & 0x7) != 0x7 && !((vif0ch->chcr.TAG >> 12) & 0x8))
DevCon.Warning("VIF0 Ending when refe or end not set! CHCR = %x", vif0ch->chcr._u32);*/
vif0Regs->stat.VPS = VPS_IDLE; //Vif goes idle as the stall happened between commands;
vif0ch->chcr.STR = false;
g_vifCycles = 0;

View File

@ -50,7 +50,7 @@ void vif1TransferFromMemory()
// 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);
XMMRegisters::Freeze();
if (GSreadFIFO2 == NULL)
@ -81,6 +81,11 @@ void vif1TransferFromMemory()
g_vifCycles += vif1ch->qwc * 2;
vif1ch->madr += vif1ch->qwc * 16; // mgs3 scene changes
if(vif1.GSLastTRXPOS > vif1ch->qwc)
vif1Regs->stat.FQC = vif1.GSLastTRXPOS - vif1ch->qwc;
else
vif1Regs->stat.FQC = 0;
vif1ch->qwc = 0;
}
@ -195,12 +200,18 @@ __forceinline void vif1Interrupt()
VIF_LOG("vif1Interrupt: %8.8x", cpuRegs.cycle);
g_vifCycles = 0;
if (vif1ch->chcr.DIR) vif1Regs->stat.FQC = min(vif1ch->qwc, (u16)16);
//Simulated GS transfer time done, clear the flags
if(gifRegs->stat.APATH == GIF_APATH2 && (vif1.cmd & 0x70) != 0x50)
{
gifRegs->stat.clear_flags(GIF_STAT_APATH2|GIF_STAT_OPH);
}
if (schedulepath3msk) Vif1MskPath3();
if ((vif1Regs->stat.VGW))
{
if (gif->chcr.STR && (Path3progress != STOPPED_MODE))
if ((gif->chcr.STR && (GSTransferStatus.PTH3 != STOPPED_MODE)) || (GSTransferStatus.PTH1 != STOPPED_MODE))
{
CPU_INT(DMAC_VIF1, 4);
return;
@ -220,7 +231,7 @@ __forceinline void vif1Interrupt()
--vif1.irq;
if (vif1Regs->stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS))
{
vif1Regs->stat.FQC = 0;
//vif1Regs->stat.FQC = 0;
// One game doesn't like vif stalling at end, can't remember what. Spiderman isn't keen on it tho
vif1ch->chcr.STR = false;
@ -240,8 +251,10 @@ __forceinline void vif1Interrupt()
_VIF1chain();
// VIF_NORMAL_FROM_MEM_MODE is a very slow operation.
// Timesplitters 2 depends on this beeing a bit higher than 128.
if (vif1.dmamode == VIF_NORMAL_FROM_MEM_MODE ) CPU_INT(DMAC_VIF1, 1024);
else CPU_INT(DMAC_VIF1, /*g_vifCycles*/ VifCycleVoodoo);
if (vif1ch->chcr.DIR) vif1Regs->stat.FQC = min(vif1ch->qwc, (u16)16);
// Refraction - Removing voodoo timings for now, completely messes a lot of Path3 masked games.
/*if (vif1.dmamode == VIF_NORMAL_FROM_MEM_MODE ) CPU_INT(DMAC_VIF1, 1024);
else */CPU_INT(DMAC_VIF1, g_vifCycles /*VifCycleVoodoo*/);
return;
}
@ -255,8 +268,8 @@ __forceinline void vif1Interrupt()
}
if ((vif1.inprogress & 0x1) == 0) vif1SetupTransfer();
CPU_INT(DMAC_VIF1, /*g_vifCycles*/ VifCycleVoodoo);
if (vif1ch->chcr.DIR) vif1Regs->stat.FQC = min(vif1ch->qwc, (u16)16);
CPU_INT(DMAC_VIF1, g_vifCycles);
return;
}
@ -276,11 +289,13 @@ __forceinline void vif1Interrupt()
g_vifCycles = 0;
hwDmacIrq(DMAC_VIF1);
/*if(vif1.dmamode == VIF_CHAIN_MODE && ((vif1ch->chcr.TAG >> 12) & 0x7) != 0x0 && ((vif1ch->chcr.TAG >> 12) & 0x7) != 0x7 && !((vif1ch->chcr.TAG >> 12) & 0x8))
DevCon.Warning("VIF1 Ending when refe or end not set! CHCR = %x", vif1ch->chcr._u32);*/
//Im not totally sure why Path3 Masking makes it want to see stuff in the fifo
//Games effected by setting, Fatal Frame, KH2, Shox, Crash N Burn, GT3/4 possibly
//Im guessing due to the full gs fifo before the reverse? (Refraction)
//Note also this is only the condition for reverse fifo mode, normal direction clears it as normal
if (!vif1Regs->mskpath3 || vif1ch->chcr.DIR) vif1Regs->stat.FQC = 0;
//if (!vif1Regs->mskpath3 || vif1ch->chcr.DIR) vif1Regs->stat.FQC = min(vif1ch->qwc, (u16)16);
}
void dmaVIF1()
@ -298,6 +313,7 @@ void dmaVIF1()
//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;
}
@ -325,9 +341,6 @@ void dmaVIF1()
vif1.dmamode = VIF_CHAIN_MODE;
}
if (vif1.dmamode != VIF_NORMAL_FROM_MEM_MODE)
vif1Regs->stat.FQC = 0x10;
else
vif1Regs->stat.FQC = min((u16)0x10, vif1ch->qwc);
// Chain Mode

View File

@ -210,7 +210,7 @@ void mfifoVIF1transfer(int qwc)
vif1.done = true;
}
}
vif1Regs->stat.FQC = min(vif1ch->qwc, (u16)16);
vif1.inprogress |= 1;
SPR_LOG("mfifoVIF1transfer end %x madr %x, tadr %x vifqwc %x", vif1ch->chcr._u32, vif1ch->madr, vif1ch->tadr, vifqwc);
@ -295,6 +295,9 @@ void vifMFIFOInterrupt()
hwDmacIrq(DMAC_MFIFO_EMPTY);
}*/
if(((vif1ch->chcr.TAG >> 12) & 0x7) != 0x0 && ((vif1ch->chcr.TAG >> 12) & 0x7) != 0x7)
DevCon.Warning("VIF1 MFIFO Ending when refe or end not set! CHCR = %x", vif1ch->chcr._u32);
vif1.done = 1;
g_vifCycles = 0;
vif1ch->chcr.STR = false;

View File

@ -78,9 +78,9 @@ void Vif1MskPath3() {
if (!vif1Regs->mskpath3) {
//Let the Gif know it can transfer again (making sure any vif stall isnt unset prematurely)
Path3progress = TRANSFER_MODE;
GSTransferStatus.PTH3 = TRANSFER_MODE;
gifRegs->stat.IMT = false;
CPU_INT(DMAC_GIF, 4);
if(gif->chcr.STR == true) CPU_INT(DMAC_GIF, 4);
}
else gifRegs->stat.M3P = true;
@ -108,10 +108,10 @@ template<int idx> _f int _vifCode_Direct(int pass, u8* data, bool isDirectHL) {
pass2 {
vif1Only();
//return vifTrans_DirectHL<idx>((u32*)data);
gifRegs->stat.P2Q = true;
//Should probably do this for both types of transfer seen as the GS hates taking 2 seperate chunks
//if (isDirectHL) {
if (gif->chcr.STR && (!vif1Regs->mskpath3 && (Path3progress != STOPPED_MODE)))
if ((gif->chcr.STR && (!vif1Regs->mskpath3 && (GSTransferStatus.PTH3 != STOPPED_MODE))) || GSTransferStatus.PTH1 != STOPPED_MODE)
{
/*if(!isDirectHL) DevCon.WriteLn("Direct: Waiting for Path3 to finish!");
else DevCon.WriteLn("DirectHL: Waiting for Path3 to finish!");*/
@ -121,11 +121,14 @@ template<int idx> _f int _vifCode_Direct(int pass, u8* data, bool isDirectHL) {
return 0;
}
//}
gifRegs->stat.clear_flags(GIF_STAT_P2Q);
gifRegs->stat.APATH = GIF_APATH2;
gifRegs->stat.OPH = true;
Registers::Freeze();
nVifStruct& v = nVif[1];
const int ret = aMin(vif1.vifpacketsize, vif1.tag.size);
s32 size = ret << 2;
u32 size = ret << 2;
if (ret == v.vif->tag.size) { // Full Transfer
if (v.bSize) { // Last transfer was partial
@ -180,7 +183,7 @@ vifOp(vifCode_FlushA) {
vif1Only();
pass1 {
// Gif is already transferring so wait for it.
if (((Path3progress != STOPPED_MODE) || !vif1Regs->mskpath3) && gif->chcr.STR) {
if (((GSTransferStatus.PTH3 != STOPPED_MODE) || !vif1Regs->mskpath3) && gif->chcr.STR) {
//DevCon.WriteLn("FlushA path3 Wait!");
vif1Regs->stat.VGW = true;
vifX.vifstalled = true;

View File

@ -24,6 +24,18 @@ struct vifCode {
u16 cl;
};
union tBITBLT {
struct {
u32 reserved : 8;
u32 BLTDIVIDE : 8; // This is the value we want to work out the divider for the reverse transfer
u32 reserved2 : 6;
u32 TRXPOS : 16;
};
u32 _u32;
};
// NOTE, if debugging vif stalls, use sega classics, spyro, gt4, and taito
struct vifStruct {
vifCode tag;
@ -36,6 +48,9 @@ struct vifStruct {
bool done;
bool vifstalled;
bool stallontag;
tBITBLT TRXPOS; //used for reversed fifo operations, sometimes only the GS knows how big (like on HW register fifo read)!
u32 GSLastTRXPOS;
u8 irqoffset; // 32bit offset where next vif code is
u32 savedtag; // need this for backwards compat with save states
@ -47,7 +62,6 @@ struct vifStruct {
extern vifStruct* vif;
extern vifStruct vif0, vif1;
extern u8 schedulepath3msk;
static const int VifCycleVoodoo = 4;
extern void vif0Init();
extern void vif0Interrupt();

View File

@ -18,6 +18,7 @@
#include "GS.h"
#include "Gif.h"
#include "Vif_Dma.h"
#include "vif.h"
// --------------------------------------------------------------------------------------
// GIFpath -- the GIFtag Parser
@ -277,6 +278,40 @@ void SaveStateBase::gifPathFreeze()
static __forceinline void gsHandler(const u8* pMem)
{
const int handler = pMem[8];
if(handler == 0x50)
{
const u16* pMem16 = (const u16*)pMem;
vif1.TRXPOS._u32 = pMem16[1];
//Console.Warning("BLITBUF = %x %x_%x_%x_%x", vif1.TRXPOS.BLTDIVIDE, pMem16[0], pMem16[1], pMem16[2], pMem16[3]);
switch(vif1.TRXPOS.BLTDIVIDE & 0x3)
{
case 0x3:
VIF_LOG("8bit");
vif1.TRXPOS.BLTDIVIDE = 16; //8bit
break;
case 0x2:
VIF_LOG("16bit");
vif1.TRXPOS.BLTDIVIDE = 8; //16bit
break;
case 0x1:
VIF_LOG("24bit");
vif1.TRXPOS.BLTDIVIDE = 5; //24bit
break;
default:
VIF_LOG("32bit");
vif1.TRXPOS.BLTDIVIDE = 4; //32bit
break;
}
}
if(handler == 0x52)
{
const u16* pMem16 = (const u16*)pMem;
VIF_LOG("TRX REG = %x_%x_%x_%x", pMem16[0], pMem16[1], pMem16[2], pMem16[3]);
vif1.GSLastTRXPOS = (pMem16[0] * pMem16[2]) / (u8)vif1.TRXPOS.BLTDIVIDE;
}
if (handler >= 0x60)
{
// Question: What happens if an app writes to uncharted register space on real PS2
@ -310,14 +345,28 @@ __forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
SetTag(pMem);
incTag(16, 1);
if (pathidx == GIF_PATH_3) {
if (tag.FLG&2) Path3progress = IMAGE_MODE;
else Path3progress = TRANSFER_MODE;
//if (pathidx == GIF_PATH_3) {
switch(pathidx)
{
case GIF_PATH_1:
if (tag.FLG&2) GSTransferStatus.PTH1 = IMAGE_MODE;
else GSTransferStatus.PTH1 = TRANSFER_MODE;
break;
case GIF_PATH_2:
if (tag.FLG&2) GSTransferStatus.PTH2 = IMAGE_MODE;
else GSTransferStatus.PTH2 = TRANSFER_MODE;
break;
case GIF_PATH_3:
if (tag.FLG&2) GSTransferStatus.PTH3 = IMAGE_MODE;
else GSTransferStatus.PTH3 = TRANSFER_MODE;
break;
}
//}
}
else {
switch(tag.FLG) {
case GIF_FLG_PACKED:
GIF_LOG("Packed Mode");
PrepPackedRegs();
do {
if (GetReg() == 0xe) {
@ -328,6 +377,7 @@ __forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
break;
case GIF_FLG_REGLIST:
{
GIF_LOG("Reglist Mode");
size *= 2;
do { incTag(8, 1); }
@ -340,6 +390,7 @@ __forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
case GIF_FLG_IMAGE:
case GIF_FLG_IMAGE2:
{
GIF_LOG("IMAGE Mode");
int len = aMin(size, nloop);
incTag(( len * 16 ), len);
nloop -= len;
@ -354,13 +405,28 @@ __forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
}
}
}
/*if(((GSTransferStatus.PTH1 & 0x2) + (GSTransferStatus.PTH2 & 0x2) + ((GSTransferStatus.PTH3 & 0x2) && !vif1Regs->mskpath3)) < 0x4 )
Console.Warning("CHK PTH1 %x, PTH2 %x, PTH3 %x", GSTransferStatus.PTH1, GSTransferStatus.PTH2, GSTransferStatus.PTH3);*/
size = (startSize - size);
if (pathidx == GIF_PATH_3) {
if (tag.EOP && !nloop) {
Path3progress = STOPPED_MODE;
//Console.Warning("Finishing path %x", pathidx);
switch(pathidx)
{
case GIF_PATH_1:
GSTransferStatus.PTH1 = STOPPED_MODE;
break;
case GIF_PATH_2:
GSTransferStatus.PTH2 = STOPPED_MODE;
break;
case GIF_PATH_3:
GSTransferStatus.PTH3 = STOPPED_MODE;
break;
}
}
if (pathidx == GIF_PATH_3) {
gif->madr += size * 16;
gif->qwc -= size;
}