-Path3 Masking Changes, Gif Unit now rolls the DMA back (Path3 only) if it is using the Masking and finishes mid DMA packet.
-Vif modified to be simpler in the transfer loop and fixes issues where Flushes are called at the end of a DMA packet.

Game fixes from changes:
Outrun 2006 - Water textures and general flickering fixed, also SW mode not required for half screen issue. Caused by GIF Path 3 stopping in the wrong place.
Star Wars Episode 3: Revenge of the Sith - DMA timeouts caused by Flush at end of packet.
Had to break savestates (version change!), sorry :(

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@5224 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
refraction 2012-05-24 18:46:00 +00:00
parent e4e2366bce
commit 9bb28d3fec
8 changed files with 94 additions and 79 deletions

View File

@ -249,7 +249,7 @@ void GIFdma()
GIFchain(); //Transfers the data set by the switch
CPU_INT(DMAC_GIF, gscycles);
return;
} else if(gspath3done == false) GIFdma();
} else if(gspath3done == false) GIFdma(); //Loop round if there was a blank tag, causes hell otherwise with P3 masking games.
prevcycles = 0;
CPU_INT(DMAC_GIF, gscycles);

View File

@ -145,6 +145,7 @@ struct Gif_Path {
u32 buffLimit; // Cut off limit to wrap around
u32 curSize; // Used buffer in bytes
u32 curOffset; // Offset of current gifTag
u32 dmaRewind; // Used by path3 when only part of a DMA chain is used
Gif_Tag gifTag; // Current GS Primitive tag
GS_Packet gsPack; // Current GS Packet info
GIF_PATH idx; // Gif Path Index
@ -296,14 +297,29 @@ struct Gif_Path {
GS_Packet t = gsPack;
t.done = 1;
//Path 3 Masking is timing sensitive, we need to simulate its length! (NFSU2)
dmaRewind = 0;
gsPack.Reset();
gsPack.offset = curOffset;
//Path 3 Masking is timing sensitive, we need to simulate its length! (NFSU2/Outrun 2006)
if((gifRegs.stat.APATH-1) == GIF_PATH_3)
{
state = GIF_PATH_WAIT;
if(curSize - curOffset > 0 && (gifRegs.stat.M3R || gifRegs.stat.M3P))
{
//Including breaking packets early (Rewind DMA to pick up where left off)
//but only do this when the path is masked, else we're pointlessly slowing things down.
dmaRewind = curSize - curOffset;
curSize = curOffset;
}
}
else
state = GIF_PATH_IDLE;
gsPack.Reset();
gsPack.offset = curOffset;
return t; // Complete GS packet
}
}
@ -486,7 +502,7 @@ struct Gif_Unit {
}
gifPath[tranType&3].CopyGSPacketData(pMem, size, aligned);
Execute();
size -= Execute();
return size;
}
@ -524,10 +540,12 @@ struct Gif_Unit {
// Processes gif packets and performs path arbitration
// on EOPs or on Path 3 Images when IMT is set.
void Execute() {
if (!CanDoGif()) { DevCon.Error("Gif Unit - Signal or PSE Set or Dir = GS to EE"); return; }
int Execute() {
if (!CanDoGif()) { DevCon.Error("Gif Unit - Signal or PSE Set or Dir = GS to EE"); return 0; }
bool didPath3 = false;
int curPath = stat.APATH-1;
stat.OPH = 1;
gifPath[curPath].dmaRewind = 0;
for(;;) {
if (stat.APATH) { // Some Transfer is happening
Gif_Path& path = gifPath[stat.APATH-1];
@ -568,7 +586,9 @@ struct Gif_Unit {
else { stat.APATH = 0; stat.OPH = 0; break; }
}
Gif_FinishIRQ();
//DevCon.WriteLn("APATH = %d [%d,%d,%d]", stat.APATH, !!checkPaths(1,0,0,0),!!checkPaths(0,1,0,0),!!checkPaths(0,0,1,0));
//Path3 can rewind the DMA, so we send back the amount we go back!
return gifPath[curPath].dmaRewind;
}
// XGkick

View File

@ -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 = (0x9A07 << 16) | 0x0000;
static const u32 g_SaveVersion = (0x9A08 << 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. :)

View File

@ -92,11 +92,13 @@ void ExecuteVU(int idx)
{
vuExecMicro(idx, -1);
vifX.cmd = 0;
vifX.pass = 0;
}
else if((vifX.cmd & 0x7f) == 0x14 || (vifX.cmd & 0x7f) == 0x15)
{
vuExecMicro(idx, (u16)(vifXRegs.code) << 3);
vifX.cmd = 0;
vifX.pass = 0;
}
}
@ -106,9 +108,9 @@ void ExecuteVU(int idx)
vifOp(vifCode_Base) {
vif1Only();
pass1 { vif1Regs.base = vif1Regs.code & 0x3ff; vif1.cmd = 0; }
pass1 { vif1Regs.base = vif1Regs.code & 0x3ff; vif1.cmd = 0; vif1.pass = 0; }
pass3 { VifCodeLog("Base"); }
return 0;
return 1;
}
template<int idx> __fi int _vifCode_Direct(int pass, const u8* data, bool isDirectHL) {
@ -116,7 +118,8 @@ template<int idx> __fi int _vifCode_Direct(int pass, const u8* data, bool isDire
pass1 {
int vifImm = (u16)vif1Regs.code;
vif1.tag.size = vifImm ? (vifImm*4) : (65536*4);
return 0;
vif1.pass = 1;
return 1;
}
pass2 {
const char* name = isDirectHL ? "DirectHL" : "Direct";
@ -134,9 +137,11 @@ template<int idx> __fi int _vifCode_Direct(int pass, const u8* data, bool isDire
//gifUnit.PrintInfo();
vif1.vifstalled = true;
vif1Regs.stat.VGW = true;
return 0;
}
if (vif1.tag.size == 0) {
vif1.cmd = 0;
vif1.pass = 0;
}
return ret / 4;
}
@ -164,11 +169,13 @@ vifOp(vifCode_Flush) {
//gifUnit.PrintInfo();
vif1Regs.stat.VGW = true;
vifX.vifstalled = true;
return 0;
}
else vifX.cmd = 0;
vifX.pass = 0;
}
pass3 { VifCodeLog("Flush"); }
return 0;
return 1;
}
vifOp(vifCode_FlushA) {
@ -207,25 +214,27 @@ vifOp(vifCode_FlushA) {
if (doStall) {
vif1Regs.stat.VGW = true;
vifX.vifstalled = true;
return 0;
}
else vifX.cmd = 0;
vifX.pass = 0;
}
pass3 { VifCodeLog("FlushA"); }
return 0;
return 1;
}
// ToDo: FixMe
vifOp(vifCode_FlushE) {
vifStruct& vifX = GetVifX;
pass1 { vifFlush(idx); vifX.cmd = 0; }
pass1 { vifFlush(idx); vifX.cmd = 0; vifX.pass = 0;}
pass3 { VifCodeLog("FlushE"); }
return 0;
return 1;
}
vifOp(vifCode_ITop) {
pass1 { vifXRegs.itops = vifXRegs.code & 0x3ff; GetVifX.cmd = 0; }
pass1 { vifXRegs.itops = vifXRegs.code & 0x3ff; GetVifX.cmd = 0; GetVifX.pass = 0; }
pass3 { VifCodeLog("ITop"); }
return 0;
return 1;
}
vifOp(vifCode_Mark) {
@ -234,9 +243,10 @@ vifOp(vifCode_Mark) {
vifXRegs.mark = (u16)vifXRegs.code;
vifXRegs.stat.MRK = true;
vifX.cmd = 0;
vifX.pass = 0;
}
pass3 { VifCodeLog("Mark"); }
return 0;
return 1;
}
static __fi void _vifCode_MPG(int idx, u32 addr, const u32 *data, int size) {
@ -262,7 +272,12 @@ vifOp(vifCode_MPG) {
vifX.tag.addr = (u16)(vifXRegs.code << 3) & (idx ? 0x3fff : 0xfff);
vifX.tag.size = vifNum ? (vifNum*2) : 512;
vifFlush(idx);
return 1;
if(vifX.vifstalled == true) return 0;
else
{
vifX.pass = 1;
return 1;
}
}
pass2 {
if (vifX.vifpacketsize < vifX.tag.size) { // Partial Transfer
@ -282,6 +297,7 @@ vifOp(vifCode_MPG) {
int ret = vifX.tag.size;
vifX.tag.size = 0;
vifX.cmd = 0;
vifX.pass = 0;
return ret;
}
}
@ -298,10 +314,11 @@ vifOp(vifCode_MSCAL) {
{
vuExecMicro(idx, (u16)(vifXRegs.code) << 3);
vifX.cmd = 0;
}
vifX.pass = 0;
}
}
pass3 { VifCodeLog("MSCAL"); }
return 0;
return 1;
}
vifOp(vifCode_MSCALF) {
@ -318,10 +335,11 @@ vifOp(vifCode_MSCALF) {
{
vuExecMicro(idx, (u16)(vifXRegs.code) << 3);
vifX.cmd = 0;
vifX.pass = 0;
}
}
pass3 { VifCodeLog("MSCALF"); }
return 0;
return 1;
}
vifOp(vifCode_MSCNT) {
@ -332,10 +350,11 @@ vifOp(vifCode_MSCNT) {
{
vuExecMicro(idx, -1);
vifX.cmd = 0;
vifX.pass = 0;
}
}
pass3 { VifCodeLog("MSCNT"); }
return 0;
return 1;
}
// ToDo: FixMe
@ -352,14 +371,16 @@ vifOp(vifCode_MskPath3) {
//}
}
vif1.cmd = 0;
vif1.pass = 0;
}
pass3 { VifCodeLog("MskPath3"); }
return 0;
return 1;
}
vifOp(vifCode_Nop) {
pass1 {
GetVifX.cmd = 0;
GetVifX.pass = 0;
/*if(idx && vif1ch.chcr.STR == true)
{
//Some games use a huge stream of NOPS to wait for a GIF packet to start, alas the way PCSX2 works it never starts
@ -370,7 +391,7 @@ vifOp(vifCode_Nop) {
}*/
}
pass3 { VifCodeLog("Nop"); }
return 0;
return 1;
}
// ToDo: Review Flags
@ -385,10 +406,11 @@ vifOp(vifCode_Null) {
//vifX.irq++;
}
vifX.cmd = 0;
vifX.pass = 0;
}
pass2 { Console.Error("Vif%d bad vifcode! [CMD = %x]", idx, vifX.cmd); }
pass3 { VifCodeLog("Null"); }
return 0;
return 1;
}
vifOp(vifCode_Offset) {
@ -398,9 +420,10 @@ vifOp(vifCode_Offset) {
vif1Regs.ofst = vif1Regs.code & 0x3ff;
vif1Regs.tops = vif1Regs.base;
vif1.cmd = 0;
vif1.pass = 0;
}
pass3 { VifCodeLog("Offset"); }
return 0;
return 1;
}
template<int idx> static __fi int _vifCode_STColRow(const u32* data, u32* pmem2) {
@ -421,7 +444,13 @@ template<int idx> static __fi int _vifCode_STColRow(const u32* data, u32* pmem2)
vifX.tag.addr += ret;
vifX.tag.size -= ret;
if (!vifX.tag.size) vifX.cmd = 0;
if (!vifX.tag.size)
{
vifX.pass = 0;
vifX.cmd = 0;
}
return ret;
}
@ -431,6 +460,7 @@ vifOp(vifCode_STCol) {
pass1 {
vifX.tag.addr = 0;
vifX.tag.size = 4;
vifX.pass = 1;
return 1;
}
pass2 {
@ -447,6 +477,7 @@ vifOp(vifCode_STRow) {
pass1 {
vifX.tag.addr = 0;
vifX.tag.size = 4;
vifX.pass = 1;
return 1;
}
pass2 {
@ -455,7 +486,7 @@ vifOp(vifCode_STRow) {
return ret;
}
pass3 { VifCodeLog("STRow"); }
return 0;
return 1;
}
vifOp(vifCode_STCycl) {
@ -464,23 +495,24 @@ vifOp(vifCode_STCycl) {
vifXRegs.cycle.cl = (u8)(vifXRegs.code);
vifXRegs.cycle.wl = (u8)(vifXRegs.code >> 8);
vifX.cmd = 0;
vifX.pass = 0;
}
pass3 { VifCodeLog("STCycl"); }
return 0;
return 1;
}
vifOp(vifCode_STMask) {
vifStruct& vifX = GetVifX;
pass1 { vifX.tag.size = 1; }
pass2 { vifXRegs.mask = data[0]; vifX.tag.size = 0; vifX.cmd = 0; }
pass1 { vifX.tag.size = 1; vifX.pass = 1; return 1; }
pass2 { vifXRegs.mask = data[0]; vifX.tag.size = 0; vifX.cmd = 0; vifX.pass = 0;}
pass3 { VifCodeLog("STMask"); }
return 1;
}
vifOp(vifCode_STMod) {
pass1 { vifXRegs.mode = vifXRegs.code & 0x3; GetVifX.cmd = 0; }
pass1 { vifXRegs.mode = vifXRegs.code & 0x3; GetVifX.cmd = 0; GetVifX.pass = 0;}
pass3 { VifCodeLog("STMod"); }
return 0;
return 1;
}
template< uint idx >
@ -496,6 +528,7 @@ static uint calc_addr(bool flg)
vifOp(vifCode_Unpack) {
pass1 {
vifUnpackSetup<idx>(data);
return 1;
}
pass2 {

View File

@ -62,6 +62,7 @@ struct vifStruct {
struct { // These must be together for MTVU
vifCode tag;
int cmd;
int pass;
int cl;
u8 usn;
u8 StructEnd; // Address of this is used to calculate end of struct

View File

@ -38,31 +38,6 @@ _vifT bool analyzeIbit(u32* &data, int iBit) {
//DevCon.WriteLn("Vif I-Bit IRQ");
vifX.irq++;
// Okay did some testing with Max Payne, it does this:
// VifMark value = 0x666 (i know, evil!)
// NOP with I Bit
// VifMark value = 0
//
// If you break after the 2nd Mark has run, the game reports invalid mark 0 and the game dies.
// So it has to occur here, testing a theory that it only doesn't stall if the command with
// the iBit IS mark, but still sends the IRQ to let the cpu know the mark is there. (Refraction)
//
// --------------------------
//
// This is how it probably works: i-bit sets the IRQ flag, and VIF keeps running until it encounters
// a non-MARK instruction. This includes the *current* instruction. ie, execution only continues
// unimpeded if MARK[i] is specified, and keeps executing unimpeded until any non-MARK command.
// Any other command with an I bit should stall immediately.
// Example:
//
// VifMark[i] value = 0x321 (with I bit)
// VifMark value = 0
// VifMark value = 0x333
// NOP
//
// ... the VIF should not stall and raise the interrupt until after the NOP is processed.
// So the final value for MARK as the game sees it will be 0x333. --air
if(CHECK_VIF1STALLHACK) return 0;
else return 1;
}
@ -75,7 +50,8 @@ _vifT void vifTransferLoop(u32* &data) {
u32& pSize = vifX.vifpacketsize;
int iBit = vifX.cmd >> 7;
int ret = 0;
vifXRegs.stat.VPS |= VPS_TRANSFERRING;
vifXRegs.stat.ER1 = false;
@ -92,14 +68,9 @@ _vifT void vifTransferLoop(u32* &data) {
// Pass 2 means "log it"
vifCmdHandler[idx][vifX.cmd & 0x7f](2, data);
}
vifCmdHandler[idx][vifX.cmd & 0x7f](0, data);
data++; pSize--;
if (analyzeIbit<idx>(data, iBit)) break;
continue;
}
int ret = vifCmdHandler[idx][vifX.cmd & 0x7f](1, data);
ret = vifCmdHandler[idx][vifX.cmd & 0x7f](vifX.pass, data);
data += ret;
pSize -= ret;
if (analyzeIbit<idx>(data, iBit)) break;
@ -127,18 +98,6 @@ _vifT static __fi bool vifTransfer(u32 *data, int size, bool TTE) {
if (!idx) g_vif0Cycles += max(1, (int)((transferred * BIAS) >> 2));
else g_vif1Cycles += max(1, (int)((transferred * BIAS) >> 2));
/*
if(!idx && g_vu0Cycles > 0) {
if (g_vif0Cycles < g_vu0Cycles) g_vu0Cycles -= g_vif0Cycles;
elif(g_vif0Cycles >= g_vu0Cycles) g_vu0Cycles = 0;
}
if (idx && g_vu1Cycles > 0) {
if (g_vif1Cycles < g_vu1Cycles) g_vu1Cycles -= g_vif1Cycles;
elif(g_vif1Cycles >= g_vu1Cycles) g_vu1Cycles = 0;
}
*/
vifX.irqoffset = transferred % 4; // cannot lose the offset
if (!TTE) {// *WARNING* - Tags CAN have interrupts! so lets just ignore the dma modifying stuffs (GT4)

View File

@ -230,6 +230,7 @@ _vifT void vifUnpackSetup(const u32 *data) {
vifX.cl = 0;
vifX.tag.cmd = vifX.cmd;
GetVifX.pass = 1;
}
template void vifUnpackSetup<0>(const u32 *data);

View File

@ -133,6 +133,7 @@ _vifT int nVifUnpack(const u8* data) {
}
else vu1Thread.VifUnpack(vif, vifRegs, (u8*)data, size);
vif.pass = 0;
vif.tag.size = 0;
vif.cmd = 0;
vifRegs.num = 0;