mirror of https://github.com/PCSX2/pcsx2.git
Found wizardry / growlanser 2 & 3 hanging bug thanks to rama. OPH flag in GIF_STAT was misinterpreted (probably). It needs to be set on download, not upload.
Also clean-up/fix of GS download logic. Might fix something if we're very lucky. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2954 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
d474febcd6
commit
7c6f8877e8
|
@ -210,7 +210,6 @@ void GIFdma()
|
|||
}
|
||||
gifRegs->stat.clear_flags(GIF_STAT_P3Q);
|
||||
gifRegs->stat.APATH = GIF_APATH3;
|
||||
gifRegs->stat.OPH = true;
|
||||
|
||||
if (vif1Regs->mskpath3 || gifRegs->mode.M3R)
|
||||
{
|
||||
|
|
|
@ -256,11 +256,11 @@ _f void vif1STAT(u32 value) {
|
|||
// Update Refraction: Use of this function has been investigated and understood.
|
||||
// Before this ever happens, a DIRECT/HL command takes place sending the transfer info to the GS
|
||||
// One of the registers told about this is TRXREG which tells us how much data is going to transfer (th x tw) in words
|
||||
// As far as the GS is concerned, the transfer starts as soon as TRXREG is accessed, which is why fatal frame
|
||||
// As far as the GS is concerned, the transfer starts as soon as TRXDIR is accessed, which is why fatal frame
|
||||
// was expecting data, the GS should already be sending it over (buffering in the FIFO)
|
||||
|
||||
vif1Regs->stat.FQC = min((u32)16, vif1.GSLastTRXPOS);
|
||||
//Console.Warning("Reversing VIF Transfer for %x QWC", vif1.GSLastTRXPOS);
|
||||
vif1Regs->stat.FQC = min((u32)16, vif1.GSLastDownloadSize);
|
||||
//Console.Warning("Reversing VIF Transfer for %x QWC", vif1.GSLastDownloadSize);
|
||||
|
||||
}
|
||||
else // Memory transferring to Vif.
|
||||
|
|
|
@ -81,8 +81,8 @@ void vif1TransferToMemory()
|
|||
|
||||
g_vifCycles += vif1ch->qwc * 2;
|
||||
vif1ch->madr += vif1ch->qwc * 16; // mgs3 scene changes
|
||||
if(vif1.GSLastTRXPOS > vif1ch->qwc)
|
||||
vif1Regs->stat.FQC = vif1.GSLastTRXPOS - vif1ch->qwc;
|
||||
if(vif1.GSLastDownloadSize > vif1ch->qwc)
|
||||
vif1Regs->stat.FQC = vif1.GSLastDownloadSize - vif1ch->qwc;
|
||||
else
|
||||
vif1Regs->stat.FQC = 0;
|
||||
|
||||
|
@ -217,7 +217,7 @@ __forceinline void vif1Interrupt()
|
|||
//Simulated GS transfer time done, clear the flags
|
||||
if(gifRegs->stat.APATH == GIF_APATH2 && (vif1.cmd & 0x70) != 0x50)
|
||||
{
|
||||
gifRegs->stat.clear_flags(GIF_STAT_APATH2|GIF_STAT_OPH);
|
||||
gifRegs->stat.APATH = GIF_APATH_IDLE;
|
||||
}
|
||||
|
||||
if (schedulepath3msk & 0x10) Vif1MskPath3();
|
||||
|
|
|
@ -124,8 +124,6 @@ template<int idx> _f int _vifCode_Direct(int pass, u8* data, bool isDirectHL) {
|
|||
}
|
||||
//}
|
||||
gifRegs->stat.clear_flags(GIF_STAT_P2Q);
|
||||
gifRegs->stat.APATH = GIF_APATH2;
|
||||
gifRegs->stat.OPH = true;
|
||||
|
||||
Registers::Freeze();
|
||||
nVifStruct& v = nVif[1];
|
||||
|
@ -146,11 +144,11 @@ template<int idx> _f int _vifCode_Direct(int pass, u8* data, bool isDirectHL) {
|
|||
vif1.tag.size = 0;
|
||||
vif1.cmd = 0;
|
||||
v.bSize = 0;
|
||||
gifRegs->stat.clear_flags(GIF_STAT_APATH2 | GIF_STAT_OPH);
|
||||
gifRegs->stat.APATH = GIF_APATH_IDLE;
|
||||
}
|
||||
else { // Partial Transfer
|
||||
//DevCon.WriteLn("DirectHL: Partial Transfer [%d]", size);
|
||||
gifRegs->stat.set_flags(GIF_STAT_APATH2 | GIF_STAT_OPH);
|
||||
gifRegs->stat.APATH = GIF_APATH2;
|
||||
memcpy_fast(&v.buffer[v.bSize], data, size);
|
||||
v.bSize += size;
|
||||
vif1.tag.size -= ret;
|
||||
|
|
|
@ -24,16 +24,32 @@ struct vifCode {
|
|||
u16 cl;
|
||||
};
|
||||
|
||||
union tBITBLT {
|
||||
union tBITBLTBUF {
|
||||
u64 _u64;
|
||||
struct {
|
||||
u32 reserved : 8;
|
||||
u32 BLTDIVIDE : 8; // This is the value we want to work out the divider for the reverse transfer
|
||||
u32 reserved2 : 6;
|
||||
u32 TRXPOS : 16;
|
||||
u32 SBP : 14;
|
||||
u32 pad14 : 2;
|
||||
u32 SBW : 6;
|
||||
u32 pad22 : 2;
|
||||
u32 SPSM : 6;
|
||||
u32 pad30 : 2;
|
||||
u32 DBP : 14;
|
||||
u32 pad46 : 2;
|
||||
u32 DBW : 6;
|
||||
u32 pad54 : 2;
|
||||
u32 DPSM : 6;
|
||||
u32 pad62 : 2;
|
||||
};
|
||||
};
|
||||
u32 _u32;
|
||||
|
||||
|
||||
union tTRXREG {
|
||||
u64 _u64;
|
||||
struct {
|
||||
u32 RRW : 12;
|
||||
u32 pad12 : 20;
|
||||
u32 RRH : 12;
|
||||
u32 pad44 : 20;
|
||||
};
|
||||
};
|
||||
|
||||
// NOTE, if debugging vif stalls, use sega classics, spyro, gt4, and taito
|
||||
|
@ -48,9 +64,12 @@ struct vifStruct {
|
|||
bool done;
|
||||
bool vifstalled;
|
||||
bool stallontag;
|
||||
tBITBLT TRXPOS; //used for reversed fifo operations, sometimes only the GS knows how big (like on HW register fifo read)!
|
||||
u32 GSLastTRXPOS;
|
||||
|
||||
// GS registers used for calculating the size of the last local->host transfer initiated on the GS
|
||||
// Transfer size calculation should be restricted to GS emulation in the future
|
||||
tBITBLTBUF BITBLTBUF;
|
||||
tTRXREG TRXREG;
|
||||
u32 GSLastDownloadSize;
|
||||
|
||||
u8 irqoffset; // 32bit offset where next vif code is
|
||||
u32 savedtag; // need this for backwards compat with save states
|
||||
|
|
|
@ -277,51 +277,56 @@ void SaveStateBase::gifPathFreeze()
|
|||
|
||||
static __forceinline void gsHandler(const u8* pMem)
|
||||
{
|
||||
const int handler = pMem[8];
|
||||
const int reg = pMem[8];
|
||||
|
||||
if(handler == 0x50)
|
||||
if (reg == 0x50)
|
||||
vif1.BITBLTBUF._u64 = *(u64*)pMem;
|
||||
else if (reg == 0x52)
|
||||
vif1.TRXREG._u64 = *(u64*)pMem;
|
||||
else if (reg == 0x53)
|
||||
{
|
||||
const u16* pMem16 = (const u16*)pMem;
|
||||
// local -> host
|
||||
if ((pMem[0] & 3) == 1)
|
||||
{
|
||||
//Onimusha does TRXREG without BLTDIVIDE first, so we "assume" 32bit for this equation, probably isnt important.
|
||||
// ^ WTF, seriously? This is really important (pseudonym)
|
||||
u8 bpp = 32;
|
||||
|
||||
vif1.TRXPOS._u32 = pMem16[1];
|
||||
//Console.Warning("BLITBUF = %x %x_%x_%x_%x", vif1.TRXPOS.BLTDIVIDE, pMem16[0], pMem16[1], pMem16[2], pMem16[3]);
|
||||
switch(vif1.TRXPOS.BLTDIVIDE & 0x3)
|
||||
switch(vif1.BITBLTBUF.SPSM & 7)
|
||||
{
|
||||
case 0x3:
|
||||
VIF_LOG("8bit");
|
||||
vif1.TRXPOS.BLTDIVIDE = 16; //8bit
|
||||
case 0:
|
||||
bpp = 32;
|
||||
break;
|
||||
case 0x2:
|
||||
VIF_LOG("16bit");
|
||||
vif1.TRXPOS.BLTDIVIDE = 8; //16bit
|
||||
case 1:
|
||||
bpp = 24;
|
||||
break;
|
||||
case 0x1:
|
||||
VIF_LOG("24bit");
|
||||
vif1.TRXPOS.BLTDIVIDE = 5; //24bit
|
||||
case 2:
|
||||
bpp = 16;
|
||||
break;
|
||||
case 3:
|
||||
bpp = 8;
|
||||
break;
|
||||
// 4 is 4 bit but this is forbidden
|
||||
default:
|
||||
VIF_LOG("32bit");
|
||||
vif1.TRXPOS.BLTDIVIDE = 4; //32bit
|
||||
break;
|
||||
Console.Error("Illegal format for GS upload: SPSM=0%02o", vif1.BITBLTBUF.SPSM);
|
||||
}
|
||||
}
|
||||
if(handler == 0x52)
|
||||
{
|
||||
const u16* pMem16 = (const u16*)pMem;
|
||||
VIF_LOG("TRX REG = %x_%x_%x_%x", pMem16[0], pMem16[1], pMem16[2], pMem16[3]);
|
||||
|
||||
//Onimusha does TRXREG without BLTDIVIDE first, so we "assume" 32bit for this equasion, probably isnt important.
|
||||
if(vif1.TRXPOS.BLTDIVIDE) vif1.GSLastTRXPOS = (pMem16[0] * pMem16[2]) / (u8)vif1.TRXPOS.BLTDIVIDE;
|
||||
else vif1.GSLastTRXPOS = (pMem16[0] * pMem16[2]) / 4;
|
||||
VIF_LOG("GS Download %dx%d SPSM= bpp=%d", vif1.TRXREG.RRW, vif1.TRXREG.RRH, vif1.BITBLTBUF.SPSM, bpp);
|
||||
|
||||
// qwords, rounded down; any extra bits are lost
|
||||
// games must take care to ensure transfer rectangles are exact multiples of a qword
|
||||
vif1.GSLastDownloadSize = vif1.TRXREG.RRW * vif1.TRXREG.RRH * bpp >> 7;
|
||||
|
||||
gifRegs->stat.OPH = true;
|
||||
}
|
||||
if (handler >= 0x60)
|
||||
}
|
||||
if (reg >= 0x60)
|
||||
{
|
||||
// Question: What happens if an app writes to uncharted register space on real PS2
|
||||
// hardware (handler 0x63 and higher)? Probably a silent ignorance, but not tested
|
||||
// so just guessing... --air
|
||||
|
||||
s_gifPath.Handlers[handler-0x60]((const u32*)pMem);
|
||||
s_gifPath.Handlers[reg-0x60]((const u32*)pMem);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4341,13 +4341,10 @@ void recVUMI_XGKICK_(VURegs *VU)
|
|||
_freeX86regs();
|
||||
_freeXMMregs();
|
||||
|
||||
OR32ItoM((uptr)&psHu32(GIF_STAT), (GIF_STAT_APATH1 | GIF_STAT_OPH)); // Set PATH1 GIF Status Flags
|
||||
|
||||
xMOV(edx, xRegister32(s_XGKICKReg));
|
||||
xMOV(ecx, (uptr)VU->Mem);
|
||||
xCALL(VU1XGKICK_MTGSTransfer);
|
||||
|
||||
AND32ItoM((uptr)&psHu32(GIF_STAT), ~(GIF_STAT_APATH1 | GIF_STAT_OPH)); // Clear PATH1 GIF Status Flags
|
||||
s_ScheduleXGKICK = 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue