From 66fe03ad0d9b00c0bc5460b8685dbb7730441417 Mon Sep 17 00:00:00 2001 From: refraction Date: Mon, 30 Mar 2009 21:10:22 +0000 Subject: [PATCH] Fix for crash of the titans, unbroke FF12 in my last commit, fixed a couple of other things. Now handles DMAs which are enabled while the DMAC is stopped, so they start when the DMAC is re-enabled. Might need some testing to make sure stuff isnt broke :p git-svn-id: http://pcsx2.googlecode.com/svn/trunk@866 96395faa-99c1-11dd-bbfe-3dabce05a288 --- pcsx2/HwWrite.cpp | 180 +++++++++++++++++++++++++++++++++++++++++++++- pcsx2/Vif.cpp | 9 ++- pcsx2/VifDma.cpp | 26 +++++-- 3 files changed, 204 insertions(+), 11 deletions(-) diff --git a/pcsx2/HwWrite.cpp b/pcsx2/HwWrite.cpp index 7beb7ab58f..d3ef5196dd 100644 --- a/pcsx2/HwWrite.cpp +++ b/pcsx2/HwWrite.cpp @@ -83,8 +83,6 @@ static void DmaExec( void (*func)(), u32 mem, u32 value ) if ((psHu32(mem) & 0x100) && (psHu32(DMAC_CTRL) & 0x1)) func(); - - } @@ -93,6 +91,7 @@ static void DmaExec( void (*func)(), u32 mem, u32 value ) char sio_buffer[1024]; int sio_count; +u16 QueuedDMA = 0; void hwWrite8(u32 mem, u8 value) { @@ -152,53 +151,103 @@ void hwWrite8(u32 mem, u8 value) { // break; case 0x10008001: // dma0 - vif0 DMA_LOG("VIF0dma EXECUTE, value=0x%x", value); + if ((value & 0x1) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("8 bit VIF0 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x1; + } DmaExec8(dmaVIF0, mem, value); break; case 0x10009001: // dma1 - vif1 DMA_LOG("VIF1dma EXECUTE, value=0x%x", value); + if ((value & 0x1) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("8 bit VIF1 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x2; + } if(value & 0x1) vif1.done = 0; //This must be done here! some games (ala Crash of the Titans) pause the dma to start MFIFO DmaExec8(dmaVIF1, mem, value); break; case 0x1000a001: // dma2 - gif DMA_LOG("GSdma EXECUTE, value=0x%x", value); + if ((value & 0x1) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("8 bit GIF DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x4; + } DmaExec8(dmaGIF, mem, value); break; case 0x1000b001: // dma3 - fromIPU DMA_LOG("IPU0dma EXECUTE, value=0x%x", value); + if ((value & 0x1) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("8 bit IPU0 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x8; + } DmaExec8(dmaIPU0, mem, value); break; case 0x1000b401: // dma4 - toIPU DMA_LOG("IPU1dma EXECUTE, value=0x%x", value); + if ((value & 0x1) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("8 bit IPU1 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x10; + } DmaExec8(dmaIPU1, mem, value); break; case 0x1000c001: // dma5 - sif0 DMA_LOG("SIF0dma EXECUTE, value=0x%x", value); // if (value == 0) psxSu32(0x30) = 0x40000; + if ((value & 0x1) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("8 bit SIF0 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x20; + } DmaExec8(dmaSIF0, mem, value); break; case 0x1000c401: // dma6 - sif1 DMA_LOG("SIF1dma EXECUTE, value=0x%x", value); + if ((value & 0x1) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("8 bit SIF1 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x40; + } DmaExec8(dmaSIF1, mem, value); break; case 0x1000c801: // dma7 - sif2 DMA_LOG("SIF2dma EXECUTE, value=0x%x", value); + if ((value & 0x1) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("8 bit SIF2 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x80; + } DmaExec8(dmaSIF2, mem, value); break; case 0x1000d001: // dma8 - fromSPR DMA_LOG("fromSPRdma8 EXECUTE, value=0x%x", value); + if ((value & 0x1) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("8 bit SPR0 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x100; + } DmaExec8(dmaSPR0, mem, value); break; case 0x1000d401: // dma9 - toSPR DMA_LOG("toSPRdma8 EXECUTE, value=0x%x", value); + if ((value & 0x1) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("8 bit SPR1 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x200; + } DmaExec8(dmaSPR1, mem, value); break; @@ -259,11 +308,21 @@ __forceinline void hwWrite16(u32 mem, u16 value) case 0x10008000: // dma0 - vif0 DMA_LOG("VIF0dma %lx", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("16 bit VIF0 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x1; + } DmaExec16(dmaVIF0, mem, value); break; case 0x10009000: // dma1 - vif1 - chcr DMA_LOG("VIF1dma CHCR %lx", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("16 bit VIF1 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x2; + } if(value & 0x100) vif1.done = 0; //This must be done here! some games (ala Crash of the Titans) pause the dma to start MFIFO DmaExec16(dmaVIF1, mem, value); break; @@ -298,6 +357,11 @@ __forceinline void hwWrite16(u32 mem, u16 value) case 0x1000a000: // dma2 - gif DMA_LOG("0x%8.8x hwWrite32: GSdma %lx", cpuRegs.cycle, value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("16 bit GIF DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x4; + } DmaExec16(dmaGIF, mem, value); break; @@ -330,6 +394,11 @@ __forceinline void hwWrite16(u32 mem, u16 value) case 0x1000b000: // dma3 - fromIPU DMA_LOG("IPU0dma %lx", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("16 bit IPU0 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x8; + } DmaExec16(dmaIPU0, mem, value); break; @@ -354,6 +423,11 @@ __forceinline void hwWrite16(u32 mem, u16 value) case 0x1000b400: // dma4 - toIPU DMA_LOG("IPU1dma %lx", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("16 bit IPU1 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x10; + } DmaExec16(dmaIPU1, mem, value); break; @@ -378,6 +452,11 @@ __forceinline void hwWrite16(u32 mem, u16 value) case 0x1000c000: // dma5 - sif0 DMA_LOG("SIF0dma %lx", value); // if (value == 0) psxSu32(0x30) = 0x40000; + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("16 bit SIF0 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x20; + } DmaExec16(dmaSIF0, mem, value); break; @@ -386,6 +465,11 @@ __forceinline void hwWrite16(u32 mem, u16 value) break; case 0x1000c400: // dma6 - sif1 DMA_LOG("SIF1dma %lx", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("16 bit SIF1 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x40; + } DmaExec16(dmaSIF1, mem, value); break; @@ -403,6 +487,11 @@ __forceinline void hwWrite16(u32 mem, u16 value) case 0x1000c800: // dma7 - sif2 DMA_LOG("SIF2dma %lx", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("16 bit SIF2 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x80; + } DmaExec16(dmaSIF2, mem, value); break; case 0x1000c802: @@ -410,11 +499,21 @@ __forceinline void hwWrite16(u32 mem, u16 value) break; case 0x1000d000: // dma8 - fromSPR DMA_LOG("fromSPRdma %lx", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("16 bit SPR0 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x100; + } DmaExec16(dmaSPR0, mem, value); break; case 0x1000d400: // dma9 - toSPR DMA_LOG("toSPRdma %lx", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("16 bit SPR1 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x200; + } DmaExec16(dmaSPR1, mem, value); break; case 0x1000f592: // DMAC_ENABLEW @@ -553,6 +652,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 ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("32 bit IPU0 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x8; + } DmaExec(dmaIPU0, mem, value); return; @@ -565,6 +669,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 ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("32 bit IPU1 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x10; + } DmaExec(dmaIPU1, mem, value); return; @@ -578,11 +687,32 @@ void __fastcall hwWrite32_page_0B( u32 mem, u32 value ) psHu32(mem) = value; } +void __fastcall StartQueuedDMA() +{ + if(QueuedDMA & 0x1) { QueuedDMA &= ~0x1; dmaVIF0(); } + if(QueuedDMA & 0x2) { QueuedDMA &= ~0x2; dmaVIF1(); } + if(QueuedDMA & 0x4) { QueuedDMA &= ~0x4; dmaGIF(); } + if(QueuedDMA & 0x8) { QueuedDMA &= ~0x8; dmaIPU0(); } + if(QueuedDMA & 0x10) { QueuedDMA &= ~0x10; dmaIPU1(); } + if(QueuedDMA & 0x20) { QueuedDMA &= ~0x20; dmaSIF0(); } + if(QueuedDMA & 0x40) { QueuedDMA &= ~0x40; dmaSIF1(); } + if(QueuedDMA & 0x80) { QueuedDMA &= ~0x80; dmaSIF2(); } + if(QueuedDMA & 0x100) { QueuedDMA &= ~0x100; dmaSPR0(); } + if(QueuedDMA & 0x200) { QueuedDMA &= ~0x200; dmaSPR1(); } +} + void __fastcall hwWrite32_page_0E( u32 mem, u32 value ) { if( mem == DMAC_CTRL ) { HW_LOG("DMAC_CTRL Write 32bit %x", value); + //Check for DMAS that were started while the DMAC was disabled + if((psHu32(mem) & 0x1) == 0 && (value & 0x1) == 1) + { + psHu32(mem) = value; + if(QueuedDMA != 0) StartQueuedDMA(); + return; + } } else if( mem == DMAC_STAT ) { @@ -678,12 +808,22 @@ void __fastcall hwWrite32_generic( u32 mem, u32 value ) { case D0_CHCR: // dma0 - vif0 DMA_LOG("VIF0dma EXECUTE, value=0x%x", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("32 bit VIF0 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x1; + } DmaExec(dmaVIF0, mem, value); return; //------------------------------------------------------------------ case D1_CHCR: // dma1 - vif1 - chcr DMA_LOG("VIF1dma EXECUTE, value=0x%x", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("32 bit VIF1 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x2; + } if(value & 0x100) { vif1.done = 0; //This must be done here! some games (ala Crash of the Titans) pause the dma to start MFIFO @@ -701,6 +841,11 @@ void __fastcall hwWrite32_generic( u32 mem, u32 value ) //------------------------------------------------------------------ case D2_CHCR: // dma2 - gif DMA_LOG("GIFdma EXECUTE, value=0x%x", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("32 bit GIF DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x4; + } DmaExec(dmaGIF, mem, value); return; @@ -715,11 +860,21 @@ void __fastcall hwWrite32_generic( u32 mem, u32 value ) case 0x1000c000: // dma5 - sif0 DMA_LOG("SIF0dma EXECUTE, value=0x%x", value); //if (value == 0) psxSu32(0x30) = 0x40000; + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("32 bit SIF0 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x20; + } DmaExec(dmaSIF0, mem, value); return; //------------------------------------------------------------------ case 0x1000c400: // dma6 - sif1 DMA_LOG("SIF1dma EXECUTE, value=0x%x", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("32 bit SIF1 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x40; + } DmaExec(dmaSIF1, mem, value); return; @@ -729,16 +884,31 @@ void __fastcall hwWrite32_generic( u32 mem, u32 value ) //------------------------------------------------------------------ case 0x1000c800: // dma7 - sif2 DMA_LOG("SIF2dma EXECUTE, value=0x%x", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("32 bit SIF2 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x80; + } DmaExec(dmaSIF2, mem, value); return; //------------------------------------------------------------------ case 0x1000d000: // dma8 - fromSPR DMA_LOG("SPR0dma EXECUTE (fromSPR), value=0x%x", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("32 bit SPR0 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x100; + } DmaExec(dmaSPR0, mem, value); return; //------------------------------------------------------------------ case 0x1000d400: // dma9 - toSPR DMA_LOG("SPR1dma EXECUTE (toSPR), value=0x%x", value); + if ((value & 0x100) && !(psHu32(DMAC_CTRL) & 0x1)) + { + DevCon::Notice("32 bit SPR1 DMA Start while DMAC Disabled\n"); + QueuedDMA |= 0x200; + } DmaExec(dmaSPR1, mem, value); return; } @@ -813,6 +983,12 @@ void __fastcall hwWrite64_page_0E( u32 mem, const mem64_t* srcval ) if( mem == DMAC_CTRL ) { HW_LOG("DMAC_CTRL Write 64bit %x", value); + if((psHu32(mem) & 0x1) == 0 && (value & 0x1) == 1) + { + psHu64(mem) = value; + if(QueuedDMA != 0) StartQueuedDMA(); + return; + } } else if( mem == DMAC_STAT ) { diff --git a/pcsx2/Vif.cpp b/pcsx2/Vif.cpp index fcdcef01d7..6d9ec34b9c 100644 --- a/pcsx2/Vif.cpp +++ b/pcsx2/Vif.cpp @@ -640,6 +640,8 @@ void mfifoVIF1transfer(int qwc) CPU_INT(10, min((int)vifqwc, (int)vif1ch->qwc) * BIAS); else CPU_INT(10, vif1ch->qwc * BIAS); + + vif1Regs->stat |= 0x10000000; // FQC=16 } vif1.inprogress &= ~0x10; SPR_LOG("Added %x qw to mfifo, total now %x - Vif CHCR %x Stalled %x done %x", qwc, vifqwc, vif1ch->chcr, vif1.vifstalled, vif1.done); @@ -745,8 +747,9 @@ void vifMFIFOInterrupt() { if (vifqwc <= 0) { - //Console::WriteLn("Empty"); + //Console::WriteLn("Empty 1"); vif1.inprogress |= 0x10; + vif1Regs->stat &= ~0x1F000000; // FQC=0 hwDmacIrq(14); return; } @@ -761,7 +764,9 @@ void vifMFIFOInterrupt() } else if (vifqwc <= 0) { - //Console::WriteLn("Empty"); + //Console::WriteLn("Empty 2"); + vif1.inprogress |= 0x10; + vif1Regs->stat &= ~0x1F000000; // FQC=0 hwDmacIrq(14); } diff --git a/pcsx2/VifDma.cpp b/pcsx2/VifDma.cpp index 11fdd08221..a37fb08db7 100644 --- a/pcsx2/VifDma.cpp +++ b/pcsx2/VifDma.cpp @@ -2039,20 +2039,23 @@ int VIF1transfer(u32 *data, int size, int istag) vif1.irqoffset = transferred % 4; // cannot lose the offset + if (vif1.irq && vif1.cmd == 0) { vif1.vifstalled = 1; if (((vif1Regs->code >> 24) & 0x7f) != 0x7)vif1Regs->stat |= VIF1_STAT_VIS; // Note: commenting this out fixes WALL-E + if (vif1ch->qwc == 0 && (vif1.irqoffset == 0 || istag == 1)) + vif1.inprogress = 0; // spiderman doesn't break on qw boundaries if (istag) return -2; - transferred = transferred >> 2; vif1ch->madr += (transferred << 4); vif1ch->qwc -= transferred; + if (vif1ch->qwc == 0 && vif1.irqoffset == 0) vif1.inprogress = 0; //Console::WriteLn("Stall on vif1, FromSPR = %x, Vif1MADR = %x Sif0MADR = %x STADR = %x", params psHu32(0x1000d010), vif1ch->madr, psHu32(0x1000c010), psHu32(DMAC_STADR)); return -2; @@ -2067,10 +2070,11 @@ int VIF1transfer(u32 *data, int size, int istag) vif1ch->madr += (transferred << 4); vif1ch->qwc -= transferred; } - + if (vif1ch->qwc == 0 && (vif1.irqoffset == 0 || istag == 1)) vif1.inprogress = 0; + return 0; } @@ -2226,8 +2230,11 @@ __forceinline void vif1SetupTransfer() else ret = VIF1transfer(vif1ptag + 2, 2, 1); //Transfer Tag - if (ret == -1) return; //There has been an error - if (ret == -2) return; //IRQ set by VIFTransfer + if (ret < 0) + { + vif1.inprogress = 0; //Better clear this so it has to do it again (Jak 1) + return; //There has been an error or an interrupt + } } @@ -2251,8 +2258,6 @@ __forceinline void vif1Interrupt() if ((vif1ch->chcr & 0x100) == 0) Console::WriteLn("Vif1 running when CHCR == %x", params vif1ch->chcr); - if (vif1.inprogress == 1) _VIF1chain(); - if (vif1.irq && vif1.tag.size == 0) { vif1Regs->stat |= VIF1_STAT_INT; @@ -2275,6 +2280,8 @@ __forceinline void vif1Interrupt() } } + if (vif1.inprogress == 1) _VIF1chain(); + if (vif1.done == 0 || vif1.inprogress == 1) { @@ -2290,6 +2297,11 @@ __forceinline void vif1Interrupt() return; } + if(vif1.vifstalled && vif1.irq) + { + CPU_INT(1, 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"); if (vif1.cmd != 0) Console::WriteLn("vif1.cmd still set %x", params vif1.cmd); @@ -2319,7 +2331,7 @@ void dmaVIF1() if (((psHu32(DMAC_CTRL) & 0xC) == 0x8)) // VIF MFIFO { - //Console::WriteLn("VIFMFIFO\n"); +// Console::WriteLn("VIFMFIFO\n"); if (!(vif1ch->chcr & 0x4)) Console::WriteLn("MFIFO mode != Chain! %x", params vif1ch->chcr); vifMFIFOInterrupt(); return;