-Rewrote the DMA checking functions as per the manual specs so certain situations can alter the DMA's while busy.

-Improved DMA Queuing slightly, less "all over the place" code.
-Jiggled some IPU bits around to clean up some clutter.
-Added the FFX and Digital Devil Saga video fixes as a Gamefix for now. Due to the delay involved, this causes other videos to terminate early, so now disabled by default.
-Added a load of logging for hardware in dev builds (also now label more correctly) and some bits for debugging IPU easier. Some are commented out, but can be enabled for testing.
-Made a small clarification in VIF

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2875 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
refraction 2010-04-20 01:18:31 +00:00
parent 36c9d63495
commit f01e10fc9a
12 changed files with 434 additions and 397 deletions

View File

@ -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)

View File

@ -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";

View File

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

View File

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

View File

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

View File

@ -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,33 +1253,35 @@ 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(CHECK_IPUWAITHACK)
{
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);
@ -1295,6 +1299,7 @@ static __forceinline bool WaitGSPaths()
//DevCon.WriteLn("Waiting for VU");
return false;
}
}
return true;
}
@ -1320,9 +1325,11 @@ static __forceinline int IPU1chain() {
ipu1dma->madr += qwc << 4;
ipu1dma->qwc -= qwc;
totalqwc += qwc;
if( ipu1dma->qwc == 0 )
}
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)
{
@ -1331,7 +1338,6 @@ static __forceinline int IPU1chain() {
//No data left
IPU1Status.InProgress = false;
} //If we still have data the commands should pull this across when need be.
}
return totalqwc;
}
@ -1390,8 +1396,6 @@ 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();
}
@ -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);
}

View File

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

View File

@ -257,6 +257,7 @@ void Pcsx2Config::GamefixOptions::LoadSave( IniInterface& ini )
IniBitBool( FpuMulHack );
IniBitBool( FpuNegDivHack );
IniBitBool( XgKickHack );
IniBitBool( IPUWaitHack );
}
Pcsx2Config::Pcsx2Config()

View File

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

View File

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

View File

@ -220,6 +220,7 @@ void mfifoVIF1transfer(int qwc)
void vifMFIFOInterrupt()
{
g_vifCycles = 0;
VIF_LOG("vif mfifo interrupt");
if (schedulepath3msk) Vif1MskPath3();

View File

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