diff --git a/pcsx2/Config.h b/pcsx2/Config.h index dcb3c587a7..51ab13c011 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -430,7 +430,8 @@ struct Pcsx2Config FpuCompareHack :1, // Digimon Rumble Arena 2, fixes spinning/hanging on intro-menu. FpuMulHack :1, // Tales of Destiny hangs. FpuNegDivHack :1, // Gundam games messed up camera-view. - XgKickHack :1; // Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace games and others. + XgKickHack :1, // Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace games and others. + IPUWaitHack :1; BITFIELD_END // all gamefixes are disabled by default. @@ -555,7 +556,7 @@ TraceLogFilters& SetTraceConfig(); #define CHECK_IOPREC (EmuConfig.Cpu.Recompiler.EnableIOP && GetSysCoreAlloc().IsRecAvailable_IOP()) //------------ SPECIAL GAME FIXES!!! --------------- -#define NUM_OF_GAME_FIXES 6 +#define NUM_OF_GAME_FIXES 7 #define CHECK_VUADDSUBHACK (EmuConfig.Gamefixes.VuAddSubHack) // Special Fix for Tri-ace games, they use an encryption algorithm that requires VU addi opcode to be bit-accurate. #define CHECK_FPUCOMPAREHACK (EmuConfig.Gamefixes.FpuCompareHack) // Special Fix for Digimon Rumble Arena 2, fixes spinning/hanging on intro-menu. @@ -563,6 +564,7 @@ TraceLogFilters& SetTraceConfig(); #define CHECK_FPUMULHACK (EmuConfig.Gamefixes.FpuMulHack) // Special Fix for Tales of Destiny hangs. #define CHECK_FPUNEGDIVHACK (EmuConfig.Gamefixes.FpuNegDivHack) // Special Fix for Gundam games messed up camera-view. #define CHECK_XGKICKHACK (EmuConfig.Gamefixes.XgKickHack) // Special Fix for Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics. +#define CHECK_IPUWAITHACK (EmuConfig.Gamefixes.IPUWaitHack) // Special Fix for Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics. //------------ Advanced Options!!! --------------- #define CHECK_VU_OVERFLOW (EmuConfig.Cpu.Recompiler.vuOverflow) diff --git a/pcsx2/Dmac.h b/pcsx2/Dmac.h index 78b8a233d4..ba04bf2abc 100644 --- a/pcsx2/Dmac.h +++ b/pcsx2/Dmac.h @@ -394,7 +394,7 @@ static __forceinline const wxChar* ChcrName(u32 addr) { case D0_CHCR: return L"Vif 0"; case D1_CHCR: return L"Vif 1"; - case D2_CHCR: return L"GS"; + case D2_CHCR: return L"GIF"; case D3_CHCR: return L"Ipu 0"; case D4_CHCR: return L"Ipu 1"; case D5_CHCR: return L"Sif 0"; diff --git a/pcsx2/Gif.cpp b/pcsx2/Gif.cpp index e3a2297ef3..414971f5c0 100644 --- a/pcsx2/Gif.cpp +++ b/pcsx2/Gif.cpp @@ -230,7 +230,7 @@ void GIFdma() 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); + GIF_LOG("PTH3 MASK gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx tadr=%lx", ptag[1]._u32, ptag[0]._u32, gif->qwc, ptag->ID, gif->madr, gif->tadr); //Check TIE bit of CHCR and IRQ bit of tag if (checkTieBit(ptag)) GIF_LOG("PATH3 MSK dmaIrq Set"); @@ -280,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); + GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx tadr=%lx", ptag[1]._u32, ptag[0]._u32, gif->qwc, ptag->ID, gif->madr, gif->tadr); 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) { @@ -314,7 +314,7 @@ void GIFdma() checkTieBit(ptag); - 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); + GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx tadr=%lx", ptag[1]._u32, ptag[0]._u32, gif->qwc, ptag->ID, gif->madr, gif->tadr); CPU_INT(DMAC_GIF, gscycles * BIAS); } else @@ -349,7 +349,7 @@ void dmaGIF() if ((gif->qwc == 0) && (gif->chcr.MOD != NORMAL_MODE)) { tDMA_TAG* ptag = ReadTag2(); - 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); + GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx tadr=%lx", ptag[1]._u32, ptag[0]._u32, gif->qwc, ptag->ID, gif->madr, gif->tadr); checkTieBit(ptag); GIFdma(); diff --git a/pcsx2/HwRead.cpp b/pcsx2/HwRead.cpp index 4db491a33d..3316f98d5b 100644 --- a/pcsx2/HwRead.cpp +++ b/pcsx2/HwRead.cpp @@ -38,8 +38,49 @@ __forceinline mem8_t hwRead8(u32 mem) // TODO re-implement this warning along with a *complete* logging of all hw activity. // (implementation should be modelled after thee iopHWRead/iopHwWrite files) - if( mem >= IPU_CMD && mem < D0_CHCR ) return psHu8(mem); + if( mem >= IPU_CMD && mem < D0_CHCR ) + { +#ifdef PCSX2_DEVBUILD + HW_LOG("8bit Hardware IPU Read at 0x%x, value=0x%x", mem, psHu8(mem) ); +#endif + return psHu8(mem); + } // DevCon.Warning("Unexpected hwRead8 from 0x%x", mem); +#ifdef PCSX2_DEVBUILD + switch((mem >> 12) & 0xf) + { + case 0x03: + if((mem & 0xfff) < 0x800) break; + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + { + const char* regName = "Unknown"; + + switch( mem & 0xf0) + { + case 0x00: regName = "CHCR"; break; + case 0x10: regName = "MADR"; break; + case 0x20: regName = "QWC"; break; + case 0x30: regName = "TADR"; break; + case 0x40: regName = "ASR0"; break; + case 0x50: regName = "ASR1"; break; + case 0x80: regName = "SADDR"; break; + } + + HW_LOG("Hardware Read 8 at 0x%x (%ls %s), value=0x%x", mem, ChcrName(mem & ~0xff), regName, psHu8(mem) ); + ret = psHu8(mem); + return ret; + } +} +#endif switch (mem) { @@ -113,9 +154,51 @@ __forceinline mem16_t hwRead16(u32 mem) // TODO re-implement this warning along with a *complete* logging of all hw activity. // (implementation should be modelled after the iopHWRead/iopHwWrite files) - if( mem >= IPU_CMD && mem < D0_CHCR ) return psHu8(mem); + if( mem >= IPU_CMD && mem < D0_CHCR ) + { +#ifdef PCSX2_DEVBUILD + HW_LOG("16 bit Hardware IPU Read at 0x%x, value=0x%x", mem, psHu16(mem) ); +#endif + return psHu16(mem); + } // Console.Warning("Unexpected hwRead16 from 0x%x", mem); +#ifdef PCSX2_DEVBUILD + switch((mem >> 12) & 0xf) + { + case 0x03: + if((mem & 0xfff) < 0x800) break; + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + { + const char* regName = "Unknown"; + + switch( mem & 0xf0) + { + case 0x00: regName = "CHCR"; break; + case 0x10: regName = "MADR"; break; + case 0x20: regName = "QWC"; break; + case 0x30: regName = "TADR"; break; + case 0x40: regName = "ASR0"; break; + case 0x50: regName = "ASR1"; break; + case 0x80: regName = "SADDR"; break; + } + + HW_LOG("Hardware Read16 at 0x%x (%ls %s), value=0x%x", mem, ChcrName(mem & ~0xff), regName, psHu16(mem) ); + ret = psHu16(mem); + return ret; + } +} +#endif + switch (mem) { case RCNT0_COUNT: ret = (u16)rcntRcount(0); break; @@ -296,8 +379,9 @@ mem32_t __fastcall hwRead32_generic(u32 mem) /////////////////////////////////////////////////////// // Most of the following case handlers are for developer builds only (logging). // It'll all optimize to ziltch in public release builds. - +#ifdef PCSX2_DEVBUILD case 0x03: + if((mem & 0xfff) < 0x800) break; case 0x04: case 0x05: case 0x06: @@ -305,34 +389,34 @@ mem32_t __fastcall hwRead32_generic(u32 mem) case 0x08: case 0x09: case 0x0a: + case 0x0b: + case 0x0c: case 0x0d: { const char* regName = "Unknown"; - switch( mem ) + switch( mem & 0xf0) { - case D2_CHCR: regName = "DMA2_CHCR"; break; - case D2_MADR: regName = "DMA2_MADR"; break; - case D2_QWC: regName = "DMA2_QWC"; break; - case D2_TADR: regName = "DMA2_TADDR"; break; - case D2_ASR0: regName = "DMA2_ASR0"; break; - case D2_ASR1: regName = "DMA2_ASR1"; break; - case D2_SADR: regName = "DMA2_SADDR"; break; + case 0x00: regName = "CHCR"; break; + case 0x10: regName = "MADR"; break; + case 0x20: regName = "QWC"; break; + case 0x30: regName = "TADR"; break; + case 0x40: regName = "ASR0"; break; + case 0x50: regName = "ASR1"; break; + case 0x80: regName = "SADDR"; break; } - HW_LOG( "Hardware Read32 at 0x%x (%s), value=0x%x", mem, regName, psHu32(mem) ); + HW_LOG("Hardware Read32 at 0x%x (%ls %s), value=0x%x", mem, ChcrName(mem & ~0xff), regName, psHu32(mem) ); } break; - - case 0x0b: - if( mem == D4_CHCR ) - HW_LOG("Hardware Read32 at 0x%x (IPU1:DMA4_CHCR), value=0x%x", mem, psHu32(mem)); - break; - - case 0x0c: +#endif case 0x0e: +#ifdef PCSX2_DEVBUILD + HW_LOG("DMAC Control Regs addr=0x%x Read32, value=0x%x", mem, psHu32(mem)); +#else if( mem == DMAC_STAT) HW_LOG("DMAC_STAT Read32, value=0x%x", psHu32(DMAC_STAT)); +#endif break; jNO_DEFAULT; diff --git a/pcsx2/HwWrite.cpp b/pcsx2/HwWrite.cpp index d8cc92dee2..b4c4591c10 100644 --- a/pcsx2/HwWrite.cpp +++ b/pcsx2/HwWrite.cpp @@ -24,167 +24,20 @@ using namespace R5900; ///////////////////////////////////////////////////////////////////////// // DMA Execution Interfaces -// dark cloud2 uses 8 bit DMAs register writes -static __forceinline void DmaExec8( void (*func)(), u32 mem, u8 value ) -{ - Registers::Freeze(); - u32 qwcRegister = (mem | 0x20) & ~0x1; //Need to remove the lower bit else we end up clearing TADR - - //It's invalid for the hardware to write a DMA while it is active, not without Suspending the DMAC - if ((value & 0x1) && ((psHu8(mem) & 0x1) == 0x1) && dmacRegs->ctrl.DMAE) { - DevCon.Warning(L"DMAExec8 Attempt to run DMA while one is already active in %s(%x)", ChcrName(mem), mem); - func(); - Registers::Thaw(); - return; - } - - // Upper 16bits of QWC should not be written since QWC is 16bits in size. - if ((psHu32(qwcRegister) >> 16) != 0) - { - DevCon.Warning("DmaExec8 DMA QWC (%x) upper 16bits set to %x\n", qwcRegister, psHu32(qwcRegister) >> 16); - psHu32(qwcRegister) = 0; - } - - psHu8(mem) = (u8)value; - if ((psHu8(mem) & 0x1) && dmacRegs->ctrl.DMAE && !psHu8(DMAC_ENABLER+2)) - { - /*Console.WriteLn("Running DMA 8 %x", psHu32(mem & ~0x1));*/ - func(); - } - Registers::Thaw(); -} - -static __forceinline void DmaExec16( void (*func)(), u32 mem, u16 value ) -{ - Registers::Freeze(); - - DMACh *reg = &psH_DMACh(mem); - tDMA_CHCR chcr(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) && psHu8(DMAC_ENABLER+2) == 0) //Tried to start another DMA in the same mode - DevCon.Warning(L"DMAExec16 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(); - Registers::Thaw(); - return; // Test with Gust games and fatal frame - } - } - - //This should be more correct, but the FFX video does some WIERD stuff and tries to stop and restart the IPU without suspending - /*if (reg->chcr.STR) { - if(psHu8(DMAC_ENABLER+2) == 0) // DMA Not in suspend mode - { - DevCon.Warning(L"DMAExec16 Attempt to alter DMA While not Suspended %s(%x) Current Val %x New Val %x", ChcrName(mem), mem, reg->chcr._u32, value); - // When DMA is active only STR field is writable, so we just - // call the dma transfer function w/o modifying CHCR contents... - //func(); - Registers::Thaw(); - return; // Test with Gust games and fatal frame - } - }*/ - - // Note: pad is the padding right above qwc, so we're testing whether qwc - // has overflowed into pad. - // Note2: May be only needed for IPU which has this handling in IPU.cpp now. (Fixes GS transfers) - if (reg->pad != 0) - { - DevCon.Warning(L"DmaExec16 DMA QWC (%s) upper 16 bits set to %x\n", - ChcrName(mem), reg->pad); - //reg->qwc = reg->pad = 0; - } - - psHu16(mem) = chcr.lower(); - if (reg->chcr.STR && dmacRegs->ctrl.DMAE && !psHu8(DMAC_ENABLER+2)) - { - //Console.WriteLn("16bit DMA Start"); - func(); - } - Registers::Thaw(); -} - -static void DmaExec( void (*func)(), u32 mem, u32 value ) -{ - Registers::Freeze(); - - DMACh *reg = &psH_DMACh(mem); - tDMA_CHCR chcr(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) && psHu8(DMAC_ENABLER+2) == 0) //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); - cpuClearInt( ChannelNumber(mem) ); // clear any eventual interrupts (Fahrenheit boot, VIF1 active) - } - else //Just trying to change mode without stopping the DMA, so we dont care really :P - { - DevCon.Warning("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(); - Registers::Thaw(); - return; // Test with Gust games and fatal frame - } - } - - //This should be more correct, but the FFX video does some WIERD stuff and tries to stop and restart the IPU without suspending - /*if (reg->chcr.STR) { - if(psHu8(DMAC_ENABLER+2) == 0) // DMA Not in suspend mode - { - DevCon.Warning(L"DMAExec32 Attempt to alter DMA While not Suspended %s(%x) Current Val %x New Val %x", ChcrName(mem), mem, reg->chcr._u32, value); - // When DMA is active only STR field is writable, so we just - // call the dma transfer function w/o modifying CHCR contents... - //func(); - Registers::Thaw(); - return; // Test with Gust games and fatal frame - } - }*/ - - // Note: pad is the padding right above qwc, so we're testing whether qwc - // has overflowed into pad. - // Note2: May be only needed for IPU which has this handling in IPU.cpp now. (Fixes GS transfers) - if (reg->pad != 0) - { - DevCon.Warning(L"DmaExec32 DMA QWC (%s) upper 16 bits set to %x\n", - ChcrName(mem), reg->pad); - //reg->qwc = reg->pad = 0; - //return; - } - - /* Keep the old tag if in chain mode and hw doesn't set it*/ - if ((chcr.MOD == CHAIN_MODE) && (chcr.TAG == 0)) - reg->chcr.set((reg->chcr.TAG << 16) | chcr.lower()); - else /* Else (including Normal mode etc) write whatever the hardware sends*/ - reg->chcr.set(value); - - 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)) { + Registers::Freeze(); func(); + Registers::Thaw(); ret = true; } - Registers::Thaw(); + return ret; } @@ -195,7 +48,7 @@ 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.VIF1) { DMA_LOG("Resuming DMA for VIF1"); if(QuickDmaExec(dmaVIF1, D1_CHCR) == true) QueuedDMA.VIF1 = 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; } @@ -206,6 +59,215 @@ void __fastcall StartQueuedDMA() if (QueuedDMA.SPR1) { DMA_LOG("Resuming DMA for SPR1"); if(QuickDmaExec(dmaSPR1, D9_CHCR) == true) QueuedDMA.SPR1 = false; } } +// dark cloud2 uses 8 bit DMAs register writes +static __forceinline void DmaExec8( void (*func)(), u32 mem, u8 value ) +{ + DMACh *reg = &psH_DMACh(mem & ~0xf); + + //The only thing we can do in an 8bit write is set the CHCR, so lets just do checks for that + + //It's invalid for the hardware to write a DMA while it is active, not without Suspending the DMAC + if (reg->chcr.STR)// && reg->chcr.STR && dmacRegs->ctrl.DMAE) + { + if(psHu8(DMAC_ENABLER+2) == 1) //DMA is suspended so we can allow writes to anything + { + //If it stops the DMA, we need to clear any pending interrupts so the DMA doesnt continue. + if(value == 0) + { + //DevCon.Warning(L"8bit %s DMA Stopped on Suspend", ChcrName(mem & ~0xf)); + cpuClearInt( ChannelNumber(mem & ~0xf) ); + } + //Here we update the lower part of the CHCR, we dont touch the tag as it is only a 16bit value + reg->chcr.STR = value; + return; + } + else //Else the DMA is suspended, so we cant touch it! + { + //As the manual states "Fields other than STR can only be written to when the DMA is stopped" + //Also "The DMA may not stop properly just by writing 0 to STR" + //So the presumption is that STR can be written to (ala force stop the DMA) but nothing else + + if(value == 0) + { + //DevCon.Warning(L"8bit Force Stopping %s (Current CHCR %x) while DMA active", ChcrName(mem & ~0xf), reg->chcr._u32, value); + reg->chcr.STR = value; + } + //else DevCon.Warning(L"8bit Attempted to stop %s DMA without suspend, ignoring", ChcrName(mem & ~0xf)); + return; + } + + } + + reg->chcr.STR = value; + + if (reg->chcr.STR && dmacRegs->ctrl.DMAE && !psHu8(DMAC_ENABLER+2)) + { + Registers::Freeze(); + func(); + Registers::Thaw(); + } + else + { + //DevCon.Warning(L"8bit %s DMA Start while DMAC Disabled\n",ChcrName(mem)); + QueuedDMA._u16 |= (1 << ChannelNumber(mem & ~0xf)); //Queue the DMA up to be started then the DMA's are Enabled and or the Suspend is lifted + } +} + +static __forceinline void DmaExec16( void (*func)(), u32 mem, u16 value ) +{ + + DMACh *reg = &psH_DMACh(mem); + tDMA_CHCR chcr(value); + + //It's invalid for the hardware to write a DMA while it is active, not without Suspending the DMAC + if (reg->chcr.STR)// && reg->chcr.STR && dmacRegs->ctrl.DMAE) + { + if(psHu8(DMAC_ENABLER+2) == 1) //DMA is suspended so we can allow writes to anything + { + //If it stops the DMA, we need to clear any pending interrupts so the DMA doesnt continue. + if(chcr.STR == 0) + { + //DevCon.Warning(L"16bit %s DMA Stopped on Suspend", ChcrName(mem)); + cpuClearInt( ChannelNumber(mem) ); + } + //Here we update the lower part of the CHCR, we dont touch the tag as it is only a 16bit value + reg->chcr.set((reg->chcr.TAG << 16) | chcr.lower()); + return; + } + else //Else the DMA is suspended, so we cant touch it! + { + //As the manual states "Fields other than STR can only be written to when the DMA is stopped" + //Also "The DMA may not stop properly just by writing 0 to STR" + //So the presumption is that STR can be written to (ala force stop the DMA) but nothing else + + if(chcr.STR == 0) + { + //DevCon.Warning(L"16bit Force Stopping %s (Current CHCR %x) while DMA active", ChcrName(mem), reg->chcr._u32, chcr._u32); + reg->chcr.set((reg->chcr.TAG << 16) | chcr.lower()); + } + //else DevCon.Warning(L"16bit Attempted to change %s modes while DMA active, ignoring", ChcrName(mem)); + return; + } + + } + + reg->chcr.set((reg->chcr.TAG << 16) | chcr.lower()); + + if (reg->chcr.STR && dmacRegs->ctrl.DMAE && !psHu8(DMAC_ENABLER+2)) + { + Registers::Freeze(); + func(); + Registers::Thaw(); + } + else + { + //DevCon.Warning(L"16bit %s DMA Start while DMAC Disabled\n",ChcrName(mem)); + QueuedDMA._u16 |= (1 << ChannelNumber(mem)); //Queue the DMA up to be started then the DMA's are Enabled and or the Suspend is lifted + } +} + +static void DmaExec( void (*func)(), u32 mem, u32 value ) +{ + + DMACh *reg = &psH_DMACh(mem); + tDMA_CHCR chcr(value); + + //It's invalid for the hardware to write a DMA while it is active, not without Suspending the DMAC + if (reg->chcr.STR)// && reg->chcr.STR && dmacRegs->ctrl.DMAE) + { + if(psHu8(DMAC_ENABLER+2) == 1) //DMA is suspended so we can allow writes to anything + { + //If it stops the DMA, we need to clear any pending interrupts so the DMA doesnt continue. + if(chcr.STR == 0) + { + //DevCon.Warning(L"32bit %s DMA Stopped on Suspend", ChcrName(mem)); + cpuClearInt( ChannelNumber(mem) ); + } + //Sanity Check for possible future bug fix0rs ;p + if(reg->chcr.TAG != chcr.TAG) DevCon.Warning(L"32bit CHCR Tag on %s changed to %x from %x QWC = %x Channel Active", ChcrName(mem), chcr.TAG, reg->chcr.TAG, reg->qwc); + //Here we update the ENTIRE CHCR, if a chain is stopped half way through, it can be manipulated in to a different mode + reg->chcr.set(value); + return; + } + else //Else the DMA is suspended, so we cant touch it! + { + //As the manual states "Fields other than STR can only be written to when the DMA is stopped" + //Also "The DMA may not stop properly just by writing 0 to STR" + //So the presumption is that STR can be written to (ala force stop the DMA) but nothing else + + if(chcr.STR == 0) + { + //DevCon.Warning(L"32bit Force Stopping %s (Current CHCR %x) while DMA active", ChcrName(mem), reg->chcr._u32, chcr._u32); + reg->chcr.set(value); + } + //else DevCon.Warning(L"32bit Attempted to change %s CHCR (Currently %x) with %x while DMA active, ignoring QWC = %x", ChcrName(mem), reg->chcr._u32, chcr._u32, reg->qwc); + return; + } + + } + + //if(reg->chcr.TAG != chcr.TAG && chcr.MOD == CHAIN_MODE) //DevCon.Warning(L"32bit CHCR Tag on %s changed to %x from %x QWC = %x Channel Not Active", ChcrName(mem), chcr.TAG, reg->chcr.TAG, reg->qwc); + + reg->chcr.set(value); + + if (reg->chcr.STR && dmacRegs->ctrl.DMAE && !psHu8(DMAC_ENABLER+2)) + { + Registers::Freeze(); + func(); + Registers::Thaw(); + } + else if(reg->chcr.STR) + { + ////DevCon.Warning(L"32bit %s DMA Start while DMAC Disabled\n", ChcrName(mem)); + QueuedDMA._u16 |= (1 << ChannelNumber(mem)); //Queue the DMA up to be started then the DMA's are Enabled and or the Suspend is lifted + } //else QueuedDMA._u16 &~= (1 << ChannelNumber(mem)); // + + + /* + if((reg->chcr._u32 & 0xff) == (chcr._u32 & 0xff) && psHu8(DMAC_ENABLER+2) == 0) //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); + cpuClearInt( ChannelNumber(mem) ); // clear any eventual interrupts (Fahrenheit boot, VIF1 active) + } + else //Just trying to change mode without stopping the DMA, so we dont care really :P + { + DevCon.Warning("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(); + Registers::Thaw(); + return; // Test with Gust games and fatal frame + }*/ + //This should be more correct, but the FFX video does some WIERD stuff and tries to stop and restart the IPU without suspending + /*if (reg->chcr.STR) { + if(psHu8(DMAC_ENABLER+2) == 0) // DMA Not in suspend mode + { + //DevCon.Warning(L"DMAExec32 Attempt to alter DMA While not Suspended %s(%x) Current Val %x New Val %x", ChcrName(mem), mem, reg->chcr._u32, value); + // When DMA is active only STR field is writable, so we just + // call the dma transfer function w/o modifying CHCR contents... + //func(); + Registers::Thaw(); + return; // Test with Gust games and fatal frame + } + }*/ + + // Note: pad is the padding right above qwc, so we're testing whether qwc + // has overflowed into pad. + // Note2: May be only needed for IPU which has this handling in IPU.cpp now. (Fixes GS transfers) + /*if (reg->pad != 0) + { + //DevCon.Warning(L"DmaExec32 DMA QWC (%s) upper 16 bits set to %x\n", + ChcrName(mem), reg->pad); + //reg->qwc = reg->pad = 0; + //return; + }*/ + + /* Keep the old tag if in chain mode and hw doesn't set it*/ + /*if ((chcr.MOD == CHAIN_MODE) && (chcr.TAG == 0)) + reg->chcr.set((reg->chcr.TAG << 16) | chcr.lower()); + else*/ /* Else (including Normal mode etc) write whatever the hardware sends*/ +} + ///////////////////////////////////////////////////////////////////////// // Hardware WRITE 8 bit @@ -277,105 +339,91 @@ void hwWrite8(u32 mem, u8 value) // break; case D0_CHCR + 1: // dma0 - vif0 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"); - QueuedDMA.VIF0 = true; - } else QueuedDMA.VIF0 = false; DmaExec8(dmaVIF0, mem, value); break; case D1_CHCR + 1: // dma1 - vif1 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"); - 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; case D2_CHCR + 1: // dma2 - gif 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"); - QueuedDMA.GIF = true; - } else QueuedDMA.GIF = false; DmaExec8(dmaGIF, mem, value); break; case D3_CHCR + 1: // dma3 - fromIPU 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"); - QueuedDMA.IPU0 = true; - } else QueuedDMA.IPU0 = false; DmaExec8(dmaIPU0, mem, value); break; case D4_CHCR + 1: // dma4 - toIPU 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"); - QueuedDMA.IPU1 = true; - } else QueuedDMA.IPU1 = false; DmaExec8(dmaIPU1, mem, value); break; case D5_CHCR + 1: // dma5 - sif0 DMA_LOG("SIF0dma EXECUTE, value=0x%x", value); // if (value == 0) psxSu32(0x30) = 0x40000; - if ((value & 0x1) && !dmacRegs->ctrl.DMAE) - { - //DevCon.Warning("8 bit SIF0 DMA Start while DMAC Disabled\n"); - QueuedDMA.SIF0 = true; - } else QueuedDMA.SIF0 = false; DmaExec8(dmaSIF0, mem, value); break; case D6_CHCR + 1: // dma6 - sif1 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"); - QueuedDMA.SIF1 = true; - } else QueuedDMA.SIF1 = false; DmaExec8(dmaSIF1, mem, value); break; case D7_CHCR + 1: // dma7 - sif2 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"); - QueuedDMA.SIF2 |= true; - } else QueuedDMA.SIF2 = false; DmaExec8(dmaSIF2, mem, value); break; case D8_CHCR + 1: // dma8 - fromSPR 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"); - QueuedDMA.SPR0 = true; - } else QueuedDMA.SPR0 = false; DmaExec8(dmaSPR0, mem, value); break; 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"); - QueuedDMA .SPR1 = true; - } else QueuedDMA.SPR1 = false; DmaExec8(dmaSPR1, mem, value); break; + case D0_CHCR: // dma0 - vif0 + case D1_CHCR: // dma1 - vif1 + case D2_CHCR: // dma2 - gif + case D3_CHCR: // dma3 - fromIPU + case D4_CHCR: // dma4 - toIPU + case D5_CHCR: // dma5 - sif0 + case D6_CHCR: // dma6 - sif1 + case D7_CHCR: // dma7 - sif2 + case D8_CHCR: // dma8 - fromSPR + case D9_CHCR: // dma9 - toSPR + //DevCon.Warning(L"8bit lower CHCR changed to %x from %x on %s DMA", value, psHu32(mem), ChcrName(mem)); + psHu8(mem) = value; + break; + + case D0_CHCR + 2: // dma0 - vif0 + case D0_CHCR + 3: // dma0 - vif0 + case D1_CHCR + 2: // dma1 - vif1 + case D1_CHCR + 3: // dma1 - vif1 + case D2_CHCR + 2: // dma2 - gif + case D2_CHCR + 3: // dma2 - gif + case D3_CHCR + 2: // dma3 - fromIPU + case D3_CHCR + 3: // dma3 - fromIPU + case D4_CHCR + 2: // dma4 - toIPU + case D4_CHCR + 3: // dma4 - toIPU + case D5_CHCR + 2: // dma5 - sif0 + case D5_CHCR + 3: // dma5 - sif0 + case D6_CHCR + 2: // dma6 - sif1 + case D6_CHCR + 3: // dma6 - sif1 + case D7_CHCR + 2: // dma7 - sif2 + case D7_CHCR + 3: // dma7 - sif2 + case D8_CHCR + 2: // dma8 - fromSPR + case D8_CHCR + 3: // dma8 - fromSPR + case D9_CHCR + 2: // dma9 - toSPR + case D9_CHCR + 3: // dma9 - toSPR + //DevCon.Warning(L"8bit CHCR TAG changed to %x from %x on %s DMA", value, psHu32(mem), ChcrName(mem & ~0xf)); + psHu8(mem) = value; + break; case DMAC_ENABLEW + 2: oldvalue = psHu8(DMAC_ENABLEW + 2); @@ -459,23 +507,11 @@ __forceinline void hwWrite16(u32 mem, u16 value) case D0_CHCR: // dma0 - vif0 DMA_LOG("VIF0dma %lx", value); - if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2))) - { - //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 || psHu16(DMAC_ENABLER + 2))) - { - //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); break; @@ -514,11 +550,6 @@ __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 || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("16 bit GIF DMA Start while DMAC Disabled\n"); - QueuedDMA.GIF = true; - } else QueuedDMA.GIF = false; DmaExec16(dmaGIF, mem, value); break; @@ -556,11 +587,6 @@ __forceinline void hwWrite16(u32 mem, u16 value) case D3_CHCR: // dma3 - fromIPU DMA_LOG("IPU0dma %lx", value); - if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("16 bit IPU0 DMA Start while DMAC Disabled\n"); - QueuedDMA.IPU0 = true; - } else QueuedDMA.IPU0 = false; DmaExec16(dmaIPU0, mem, value); break; @@ -588,11 +614,6 @@ __forceinline void hwWrite16(u32 mem, u16 value) case D4_CHCR: // dma4 - toIPU DMA_LOG("IPU1dma %lx", value); - if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("16 bit IPU1 DMA Start while DMAC Disabled\n"); - QueuedDMA.IPU1 = true; - } else QueuedDMA.IPU1 = false; DmaExec16(dmaIPU1, mem, value); break; @@ -619,26 +640,11 @@ __forceinline void hwWrite16(u32 mem, u16 value) #endif case D5_CHCR: // dma5 - sif0 DMA_LOG("SIF0dma %lx", value); -// if (value == 0) psxSu32(0x30) = 0x40000; - if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("16 bit SIF0 DMA Start while DMAC Disabled\n"); - QueuedDMA.SIF0 = true; - } else QueuedDMA.SIF0 = false; DmaExec16(dmaSIF0, mem, value); break; - case D5_CHCR + 2: - //? - break; - case D6_CHCR: // dma6 - sif1 DMA_LOG("SIF1dma %lx", value); - if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("16 bit SIF1 DMA Start while DMAC Disabled\n"); - QueuedDMA.SIF1 = true; - } else QueuedDMA.SIF1 = false; DmaExec16(dmaSIF1, mem, value); break; @@ -666,38 +672,33 @@ __forceinline void hwWrite16(u32 mem, u16 value) case D7_CHCR: // dma7 - sif2 DMA_LOG("SIF2dma %lx", value); - if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("16 bit SIF2 DMA Start while DMAC Disabled\n"); - QueuedDMA.SIF2 = true; - } else QueuedDMA.SIF2 = false; DmaExec16(dmaSIF2, mem, value); break; - case D7_CHCR + 2: - //? - break; - case D8_CHCR: // dma8 - fromSPR DMA_LOG("fromSPRdma %lx", value); - if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("16 bit SPR0 DMA Start while DMAC Disabled\n"); - QueuedDMA.SPR0 = true; - } else QueuedDMA.SPR0 = false; DmaExec16(dmaSPR0, mem, value); break; case D9_CHCR: // dma9 - toSPR DMA_LOG("toSPRdma %lx", value); - if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("16 bit SPR1 DMA Start while DMAC Disabled\n"); - QueuedDMA.SPR1 = true; - } else QueuedDMA.SPR1 = false; DmaExec16(dmaSPR1, mem, value); break; + case D0_CHCR + 2: // dma0 - vif0 + case D1_CHCR + 2: // dma1 - vif1 + case D2_CHCR + 2: // dma2 - gif + case D3_CHCR + 2: // dma3 - fromIPU + case D4_CHCR + 2: // dma4 - toIPU + case D5_CHCR + 2: // dma5 - sif0 + case D6_CHCR + 2: // dma6 - sif1 + case D7_CHCR + 2: // dma7 - sif2 + case D8_CHCR + 2: // dma8 - fromSPR + case D9_CHCR + 2: // dma9 - toSPR + //DevCon.Warning(L"16bit CHCR TAG changed to %x from %x on %s DMA", value, psHu32(mem), ChcrName(mem & ~0xf)); + psHu16(mem) = value; + break; + case DMAC_ENABLEW + 2: oldvalue = psHu8(DMAC_ENABLEW + 2); psHu16(DMAC_ENABLEW + 2) = value; @@ -853,11 +854,6 @@ 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 || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("32 bit IPU0 DMA Start while DMAC Disabled\n"); - QueuedDMA.IPU0 = true; - } else QueuedDMA.IPU0 = false; DmaExec(dmaIPU0, mem, value); return; @@ -870,11 +866,6 @@ 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 || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("32 bit IPU1 DMA Start while DMAC Disabled\n"); - QueuedDMA.IPU1 = true; - } else QueuedDMA.IPU1 = false; DmaExec(dmaIPU1, mem, value); return; @@ -1013,35 +1004,12 @@ 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 || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("32 bit VIF0 DMA Start while DMAC Disabled\n"); - QueuedDMA.VIF0 = true; - } else QueuedDMA.VIF0 = false; - DmaExec(dmaVIF0, mem, value); return; //------------------------------------------------------------------ case D1_CHCR: // dma1 - vif1 - chcr - DMA_LOG("VIF1dma EXECUTE, value=0x%x", value); - - if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("32 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 - } - else - { - cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Tekken tag seems to stop vif and start it again in normal, so we will cancel the mfifo loop - } - + DMA_LOG("VIF1dma EXECUTE, value=0x%x", value); DmaExec(dmaVIF1, mem, value); return; @@ -1055,11 +1023,6 @@ 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 || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("32 bit GIF DMA Start while DMAC Disabled\n"); - QueuedDMA.GIF = true; - } else QueuedDMA.GIF = false; DmaExec(dmaGIF, mem, value); return; @@ -1073,22 +1036,11 @@ 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 || psHu16(DMAC_ENABLER + 2))) - { - //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 || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("32 bit SIF1 DMA Start while DMAC Disabled\n"); - QueuedDMA.SIF1 = true; - } else QueuedDMA.SIF1 = false; DmaExec(dmaSIF1, mem, value); return; @@ -1099,31 +1051,16 @@ 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 || psHu16(DMAC_ENABLER + 2))) - { - //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 || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("32 bit SPR0 DMA Start while DMAC Disabled\n"); - QueuedDMA.SPR0 = true; - } else QueuedDMA.SPR0 = false; DmaExec(dmaSPR0, mem, value); return; //------------------------------------------------------------------ case D9_CHCR: // dma9 - toSPR DMA_LOG("SPR1dma EXECUTE (toSPR), value=0x%x", value); - if (CHCR(value).STR && (!dmacRegs->ctrl.DMAE || psHu16(DMAC_ENABLER + 2))) - { - //DevCon.Warning("32 bit SPR1 DMA Start while DMAC Disabled\n"); - QueuedDMA.SPR1 = true; - } else QueuedDMA.SPR1 = false; DmaExec(dmaSPR1, mem, value); return; } diff --git a/pcsx2/IPU/IPU.cpp b/pcsx2/IPU/IPU.cpp index b021628e59..2650a40143 100644 --- a/pcsx2/IPU/IPU.cpp +++ b/pcsx2/IPU/IPU.cpp @@ -249,6 +249,8 @@ __forceinline u32 ipuRead32(u32 mem) IPU_LOG("Ipu read32: IPU_BP=0x%08X", *(u32*)&g_BP); return ipuRegs->ipubp; + default: + IPU_LOG("Ipu read32: Addr=0x%x Value = 0x%08X", mem, *(u32*)(((u8*)ipuRegs) + mem)); } return *(u32*)(((u8*)ipuRegs) + mem); @@ -1251,49 +1253,52 @@ static __forceinline void ipuDmacSrcChain() { case TAG_REFE: // refe //if(IPU1Status.InProgress == false) ipu1dma->tadr += 16; - if(ipu1dma->qwc == 0 && IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = true; + if(IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = true; break; case TAG_CNT: // cnt // Set the taddr to the next tag ipu1dma->tadr = ipu1dma->madr; - if(ipu1dma->qwc == 0 && IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = false; + if(IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = false; break; case TAG_NEXT: // next ipu1dma->tadr = IPU1Status.NextMem; - if(ipu1dma->qwc == 0 && IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = false; + if(IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = false; break; case TAG_REF: // ref //if(IPU1Status.InProgress == false)ipu1dma->tadr += 16; - if(ipu1dma->qwc == 0 && IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = false; + if(IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = false; break; case TAG_END: // end ipu1dma->tadr = ipu1dma->madr; - if(ipu1dma->qwc == 0 && IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = true; + if(IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = true; break; } } static __forceinline bool WaitGSPaths() { - if(GSTransferStatus.PTH3 < STOPPED_MODE) + if(CHECK_IPUWAITHACK) { - //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.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; + 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; } @@ -1319,19 +1324,20 @@ static __forceinline int IPU1chain() { qwc = ipu_fifo.in.write(pMem, qwc); ipu1dma->madr += qwc << 4; ipu1dma->qwc -= qwc; - totalqwc += qwc; - - if( ipu1dma->qwc == 0 ) - { - //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(4); - } - //No data left - IPU1Status.InProgress = false; - } //If we still have data the commands should pull this across when need be. + totalqwc += qwc; } + if( ipu1dma->qwc == 0) + { + //Update TADR etc + if(IPU1Status.DMAMode == DMA_MODE_CHAIN) ipuDmacSrcChain(); + //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(4); + } + //No data left + IPU1Status.InProgress = false; + } //If we still have data the commands should pull this across when need be. return totalqwc; } @@ -1389,9 +1395,7 @@ int IPU1dma() } IPU_LOG("Processing Chain QWC left %x Finished %d In Progress %d", ipu1dma->qwc, IPU1Status.DMAFinished, IPU1Status.InProgress); totalqwc += IPU1chain(); - //Set the TADR forward - ipuDmacSrcChain(); - + //Set the TADR forward } @@ -1479,13 +1483,13 @@ int IPU1dma() 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 - ipuDmacSrcChain(); } } break; } + 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; } @@ -1684,6 +1688,7 @@ IPU_FORCEINLINE void ipu1Interrupt() return; } + IPU_LOG("ipu1 finish %x:", cpuRegs.cycle); ipu1dma->chcr.STR = false; hwDmacIrq(DMAC_TO_IPU); } diff --git a/pcsx2/IPU/IPU_Fifo.cpp b/pcsx2/IPU/IPU_Fifo.cpp index 9dfd43728e..700fb04b3f 100644 --- a/pcsx2/IPU/IPU_Fifo.cpp +++ b/pcsx2/IPU/IPU_Fifo.cpp @@ -34,6 +34,8 @@ void IPU_Fifo::init() void IPU_Fifo_Input::clear() { memzero(data); + ipu1dma->chcr.STR = 0; //It forcebly ends, so we should clear the dma too (Kingdom Hearts) + ipu1dma->qwc = 0; g_BP.IFC = 0; ipuRegs->ctrl.IFC = 0; readpos = 0; diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 15e5746e8e..d86377999b 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -257,6 +257,7 @@ void Pcsx2Config::GamefixOptions::LoadSave( IniInterface& ini ) IniBitBool( FpuMulHack ); IniBitBool( FpuNegDivHack ); IniBitBool( XgKickHack ); + IniBitBool( IPUWaitHack ); } Pcsx2Config::Pcsx2Config() diff --git a/pcsx2/Vif.cpp b/pcsx2/Vif.cpp index 8e07d95a0f..bf968ff5da 100644 --- a/pcsx2/Vif.cpp +++ b/pcsx2/Vif.cpp @@ -40,7 +40,7 @@ void vif0Reset() vif0Regs->stat.VPS = VPS_IDLE; vif0Regs->stat.FQC = 0; - vif0.done = true; + vif0.done = false; resetNewVif(0); } @@ -57,7 +57,7 @@ void vif1Reset() vif1Regs->stat.VPS = VPS_IDLE; vif1Regs->stat.FQC = 0; // FQC=0 - vif1.done = true; + vif1.done = false; cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's resetNewVif(1); @@ -101,7 +101,7 @@ _f void vif0FBRST(u32 value) { cpuRegs.interrupt &= ~1; //Stop all vif0 DMA's psHu64(VIF0_FIFO) = 0; psHu64(VIF0_FIFO + 8) = 0; - vif0.done = true; + vif0.done = false; vif0Regs->err.reset(); vif0Regs->stat.clear_flags(VIF0_STAT_FQC | VIF0_STAT_INT | VIF0_STAT_VSS | VIF0_STAT_VIS | VIF0_STAT_VFS | VIF0_STAT_VPS); // FQC=0 } @@ -160,7 +160,7 @@ _f void vif1FBRST(u32 value) { vif1ch->qwc = 0; //? psHu64(VIF1_FIFO) = 0; psHu64(VIF1_FIFO + 8) = 0; - vif1.done = true; + vif1.done = false; if(vif1Regs->mskpath3) { diff --git a/pcsx2/Vif1_Dma.cpp b/pcsx2/Vif1_Dma.cpp index 577d697b38..03e45aec55 100644 --- a/pcsx2/Vif1_Dma.cpp +++ b/pcsx2/Vif1_Dma.cpp @@ -99,7 +99,8 @@ bool _VIF1chain() return true; } - if (vif1.dmamode == VIF_NORMAL_FROM_MEM_MODE) + // Clarification - this is TO memory mode, for some reason i used the other way round >.< + if (vif1.dmamode == VIF_NORMAL_TO_MEM_MODE) { vif1TransferFromMemory(); vif1.inprogress = 0; @@ -305,6 +306,7 @@ void dmaVIF1() vif1ch->chcr._u32, vif1ch->madr, vif1ch->qwc, vif1ch->tadr, vif1ch->asr0, vif1ch->asr1); + vif1.done = false; g_vifCycles = 0; vif1.inprogress = 0; @@ -332,9 +334,9 @@ void dmaVIF1() Console.WriteLn("DMA Stall Control on VIF1 normal"); if (vif1ch->chcr.DIR) // to Memory - vif1.dmamode = VIF_NORMAL_TO_MEM_MODE; - else vif1.dmamode = VIF_NORMAL_FROM_MEM_MODE; + else + vif1.dmamode = VIF_NORMAL_TO_MEM_MODE; } else { @@ -344,6 +346,5 @@ void dmaVIF1() vif1Regs->stat.FQC = min((u16)0x10, vif1ch->qwc); // Chain Mode - vif1.done = false; vif1Interrupt(); } \ No newline at end of file diff --git a/pcsx2/Vif1_MFIFO.cpp b/pcsx2/Vif1_MFIFO.cpp index e1f9e43b05..6fa108cc12 100644 --- a/pcsx2/Vif1_MFIFO.cpp +++ b/pcsx2/Vif1_MFIFO.cpp @@ -220,6 +220,7 @@ void mfifoVIF1transfer(int qwc) void vifMFIFOInterrupt() { g_vifCycles = 0; + VIF_LOG("vif mfifo interrupt"); if (schedulepath3msk) Vif1MskPath3(); diff --git a/pcsx2/gui/Panels/GameFixesPanel.cpp b/pcsx2/gui/Panels/GameFixesPanel.cpp index e55522c10e..7ce540b1af 100644 --- a/pcsx2/gui/Panels/GameFixesPanel.cpp +++ b/pcsx2/gui/Panels/GameFixesPanel.cpp @@ -57,6 +57,10 @@ Panels::GameFixesPanel::GameFixesPanel( wxWindow* parent ) : { _("VU XGkick Hack - for Erementar Gerad."), wxEmptyString + }, + { + _("IPU Wait Hack - Fix Ripping/Corrupted videos (FFX, Digital Devil Saga), Causes others to cut short"), + wxEmptyString } };