From c30f67b76750fa42d060ee7ff6e6355bf353bd6a Mon Sep 17 00:00:00 2001 From: "refraction@gmail.com" Date: Tue, 5 Feb 2013 00:42:44 +0000 Subject: [PATCH] VIF/VU: Fixes for Everblue and Hitman 2 from r5404, details below. Savestate bump needed, sorry. Also fixed a copy/paste bug i noticed along the way in vif0FBRST. Everblue: Slightly messy fix, not as nice as id hope, but it seems to work, we need to remember VU programs written to the VU so we can check if an unpack is modifying it. This retains the behaviour of the Snowblind engines whilst fixing everblue. Hitman 2: Our vif0/1VUFinish() routing which works in conjunction with the delays wasn't paying attention to if the VIF was stalled or not and reran it before the game wanted it to, now fixed. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@5544 96395faa-99c1-11dd-bbfe-3dabce05a288 --- pcsx2/SaveState.h | 2 +- pcsx2/Vif.cpp | 4 +++- pcsx2/Vif0_Dma.cpp | 2 +- pcsx2/Vif1_Dma.cpp | 2 +- pcsx2/Vif_Codes.cpp | 20 ++++++++++++++++++++ pcsx2/Vif_Dma.h | 3 +++ pcsx2/Vif_Unpack.cpp | 21 ++++++++++++++++++++- 7 files changed, 49 insertions(+), 5 deletions(-) diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index 45684b16e1..747708bbd6 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -24,7 +24,7 @@ // the lower 16 bit value. IF the change is breaking of all compatibility with old // states, increment the upper 16 bit value, and clear the lower 16 bits to 0. -static const u32 g_SaveVersion = (0x9A0A << 16) | 0x0000; +static const u32 g_SaveVersion = (0x9A0B << 16) | 0x0000; // this function is meant to be used in the place of GSfreeze, and provides a safe layer // between the GS saving function and the MTGS's needs. :) diff --git a/pcsx2/Vif.cpp b/pcsx2/Vif.cpp index c313a36a51..13db69cf63 100644 --- a/pcsx2/Vif.cpp +++ b/pcsx2/Vif.cpp @@ -98,11 +98,12 @@ __fi void vif0FBRST(u32 value) { psHu64(VIF0_FIFO) = 0; psHu64(VIF0_FIFO + 8) = 0; vif0.vifstalled.enabled = false; - vif1.irqoffset.enabled = false; + vif0.irqoffset.enabled = false; vif0.inprogress = 0; vif0.cmd = 0; vif0.done = true; vif0ch.chcr.STR = false; + vif0.LoadedMicroProgs = 0; 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 } @@ -177,6 +178,7 @@ __fi void vif1FBRST(u32 value) { psHu64(VIF1_FIFO) = 0; psHu64(VIF1_FIFO + 8) = 0; vif1.done = true; + vif1.LoadedMicroProgs = 0; vif1ch.chcr.STR = false; #if USE_OLD_GIF == 1 // ... diff --git a/pcsx2/Vif0_Dma.cpp b/pcsx2/Vif0_Dma.cpp index b540052e42..ecd8a4978c 100644 --- a/pcsx2/Vif0_Dma.cpp +++ b/pcsx2/Vif0_Dma.cpp @@ -162,7 +162,7 @@ __fi void vif0VUFinish() vif0.waitforvu = false; ExecuteVU(0); //Make sure VIF0 isnt already scheduled to spin. - if(!(cpuRegs.interrupt & 0x1) && vif0ch.chcr.STR == true) + if(!(cpuRegs.interrupt & 0x1) && vif0ch.chcr.STR == true && !vif0Regs.stat.INT) vif0Interrupt(); } //DevCon.Warning("VU0 state cleared"); diff --git a/pcsx2/Vif1_Dma.cpp b/pcsx2/Vif1_Dma.cpp index b3388d42d5..0b3724af9b 100644 --- a/pcsx2/Vif1_Dma.cpp +++ b/pcsx2/Vif1_Dma.cpp @@ -235,7 +235,7 @@ __fi void vif1VUFinish() vif1.waitforvu = false; ExecuteVU(1); //Check if VIF is already scheduled to interrupt, if it's waiting, kick it :P - if((cpuRegs.interrupt & (1<> 16); vifX.tag.addr = (u16)(vifXRegs.code << 3) & (idx ? 0x3fff : 0xfff); vifX.tag.size = vifNum ? (vifNum*2) : 512; vifFlush(idx); + + //Make a note of the VU programs we're loading, checked in VIF Unpacks + for( u32 i = 0; i < vifX.LoadedMicroProgs; i++ ) + { + if(vifX.MicroProgAddrS[i] == vifX.tag.addr) + { + bProgramExists = true; + vifX.MicroProgAddrS[i] = vifX.tag.addr; + vifX.MicroProgAddrE[i] = vifX.tag.addr + (vifX.tag.size * 4); + break; + } + } + if(bProgramExists == false) + { + vifX.MicroProgAddrS[vifX.LoadedMicroProgs] = vifX.tag.addr; + vifX.MicroProgAddrE[vifX.LoadedMicroProgs] = vifX.tag.addr + (vifX.tag.size * 4); + vifX.LoadedMicroProgs++; + } + if(vifX.vifstalled.enabled == true) return 0; else { diff --git a/pcsx2/Vif_Dma.h b/pcsx2/Vif_Dma.h index 14d20a1d1d..ac2e6ea25e 100644 --- a/pcsx2/Vif_Dma.h +++ b/pcsx2/Vif_Dma.h @@ -93,6 +93,9 @@ struct vifStruct { bool queued_program; u32 queued_pc; + u32 LoadedMicroProgs; //Note how many microprograms we have on the VU. + u32 MicroProgAddrS[100]; //Start Addresses + u32 MicroProgAddrE[100]; //End Addresses }; extern __aligned16 vifStruct vif0, vif1; diff --git a/pcsx2/Vif_Unpack.cpp b/pcsx2/Vif_Unpack.cpp index bf76364cc7..f6ff281674 100644 --- a/pcsx2/Vif_Unpack.cpp +++ b/pcsx2/Vif_Unpack.cpp @@ -185,7 +185,7 @@ __aligned16 const UNPACKFUNCTYPE VIFfuncTable[2][3][4 * 4 * 2 * 2] = //---------------------------------------------------------------------------- _vifT void vifUnpackSetup(const u32 *data) { - + bool bModifyingVUProg = false; vifStruct& vifX = GetVifX; if ((vifXRegs.cycle.wl == 0) && (vifXRegs.cycle.wl < vifXRegs.cycle.cl)) { @@ -226,6 +226,25 @@ _vifT void vifUnpackSetup(const u32 *data) { if (idx && ((addr>>15)&1)) addr += vif1Regs.tops; vifX.tag.addr = (addr<<4) & (idx ? 0x3ff0 : 0xff0); + //The Snowblind Engine modifies VU programs with unpacks (seemingly), + //however some games (like everblue) don't like the vu waiting until the + //last minute, so as long as the unpack isn't editing a microprogram, we're safe. + if(vifX.queued_program == true && vifX.LoadedMicroProgs > 0) + { + for(u32 i = 0; i < vifX.LoadedMicroProgs; i++) + { + if(vifX.MicroProgAddrS[i] <= vifX.tag.addr && vifX.MicroProgAddrE[i] > vifX.tag.addr) + { + bModifyingVUProg = true; + break; + } + } + if(bModifyingVUProg == false) + vifExecQueue(idx); + } + + + VIF_LOG("Unpack VIF%x, QWC %x tagsize %x", idx, vifNum, vif0.tag.size); vifX.cl = 0;