mirror of https://github.com/PCSX2/pcsx2.git
Gif/VIF:
-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:
parent
e4e2366bce
commit
9bb28d3fec
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. :)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue