GameFix: Modify how DMA Busy hack works

In IPU cases, it allows writes depending on what it's doing, in the case of other channels it waits until the transfer has finished.
This commit is contained in:
refractionpcsx2 2021-01-10 14:34:55 +00:00
parent efed4a07ef
commit f21fbc24cf
2 changed files with 49 additions and 19 deletions

View File

@ -12071,16 +12071,10 @@ SLES-53098:
SLES-53099:
name: "Pilot Down - Behind Enemy Lines"
region: "PAL-M5"
gameFixes:
- DMABusyHack # Game has weird DMA handling, this allows required DMA's to finish.
roundModes:
vuRoundMode: 0
patches:
53BB63A0:
content: |-
author=kozarovv
// Patch allow sending VU1 mpg successfully. This fix missing graphic. Thanks to PSI for figuring what is wrong.
// Game need at least -2 EE cyclerate + MTVU on my pc to get full speed.
// To fix shadows set VU rounding to nearest - thx Atomic83
patch=1,EE,00426140,word,00000000
SLES-53100:
name: "Scooby Doo! Unmasked"
region: "PAL-M4"

View File

@ -316,6 +316,53 @@ __fi u32 dmacRead32( u32 mem )
template< uint page >
__fi bool dmacWrite32( u32 mem, mem32_t& value )
{
// DMA Writes are invalid to everything except the STR on CHCR when it is busy
// However this isn't completely confirmed and this might vary depending on if
// using chain or normal modes, DMA's may be handled internally.
// Metal Saga requires the QWC during IPU_FROM to be written but not MADR
// similar happens with Mana Khemia.
// In other cases such as Pilot Down Behind Enemy Lines, it seems to expect the DMA
// to have finished before it writes the new information, otherwise the game breaks.
if (CHECK_DMABUSYHACK && (mem & 0xf0) && mem >= 0x10008000 && mem <= 0x1000E000)
{
if ((psHu32(mem & ~0xff) & 0x100) && dmacRegs.ctrl.DMAE && !psHu8(DMAC_ENABLER + 2))
{
DevCon.Warning("Gamefix: Write to DMA addr %x while STR is busy!", mem);
while (psHu32(mem & ~0xff) & 0x100)
{
switch ((mem >> 8) & 0xFF)
{
case 0x80: // VIF0
vif0Interrupt();
break;
case 0x90: // VIF1
vif1Interrupt();
break;
case 0xA0: // GIF
gifInterrupt();
break;
case 0xB0: // IPUFROM
[[fallthrough]];
case 0xB4: // IPUTO
if ((mem & 0xff) == 0x20)
goto allow_write; // I'm so sorry
else
return false;
break;
case 0xD0: // SPRFROM
SPRFROMinterrupt();
break;
case 0xD4: // SPRTO
SPRTOinterrupt();
break;
default:
return false;
}
}
}
allow_write:;
}
iswitch(mem) {
icase(D0_CHCR) // dma0 - vif0
{
@ -579,17 +626,6 @@ __fi bool dmacWrite32( u32 mem, mem32_t& value )
}
}
// DMA Writes are invalid to everything except the STR on CHCR when it is busy
// There's timing problems with many games. Gamefix time!
if( CHECK_DMABUSYHACK && (mem & 0xf0) )
{
if((psHu32(mem & ~0xff) & 0x100) && dmacRegs.ctrl.DMAE && !psHu8(DMAC_ENABLER+2))
{
DevCon.Warning("Gamefix: Write to DMA addr %x while STR is busy! Ignoring", mem);
return false;
}
}
// fall-through: use the default writeback provided by caller.
return true;
}