mirror of https://github.com/PCSX2/pcsx2.git
Correct handling of FINISH events on the GIFpath; the FINISH is not posted until *after* all GIFpaths have been drained (nloop is 0 and EOP is 1). This fixes Ys6 bootup hangs.
Note: I'm reasonably sure this is the correct implementation for FINISH. There's a *good* chance this could cause regressions in some other games that use PATH3 or other DMA tricks. This will likely be due to hacks or bugs in the GIF/VIF dma code, and not FINISH. That is, we've been catering to a broken FINISH tag this entire time -- basically telling games the GS paths are clear when they're not. ;) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3320 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
2787e6e2a1
commit
f1fb7810be
|
@ -90,10 +90,12 @@ struct GIFPath
|
||||||
|
|
||||||
GIFPath();
|
GIFPath();
|
||||||
|
|
||||||
|
void Reset();
|
||||||
void PrepPackedRegs();
|
void PrepPackedRegs();
|
||||||
void SetTag(const void* mem);
|
void SetTag(const void* mem);
|
||||||
bool StepReg();
|
bool StepReg();
|
||||||
u8 GetReg();
|
u8 GetReg();
|
||||||
|
bool IsActive() const;
|
||||||
|
|
||||||
int ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size);
|
int ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size);
|
||||||
int ParseTagQuick(GIF_PATH pathidx, const u8* pMem, u32 size);
|
int ParseTagQuick(GIF_PATH pathidx, const u8* pMem, u32 size);
|
||||||
|
@ -121,6 +123,7 @@ struct GifPathStruct
|
||||||
// (not that any game's emulation accuracy probably depends on such a 'feature') --air
|
// (not that any game's emulation accuracy probably depends on such a 'feature') --air
|
||||||
bool CSR_SIGNAL_Pending = false;
|
bool CSR_SIGNAL_Pending = false;
|
||||||
|
|
||||||
|
|
||||||
// SIGNAL : This register is a double-throw. If the SIGNAL bit in CSR is clear, set the CSR
|
// SIGNAL : This register is a double-throw. If the SIGNAL bit in CSR is clear, set the CSR
|
||||||
// and raise a gsIrq. If CSR is already *set*, then ignore all subsequent drawing operations
|
// and raise a gsIrq. If CSR is already *set*, then ignore all subsequent drawing operations
|
||||||
// and writes to general purpose registers to the GS. (note: I'm pretty sure this includes
|
// and writes to general purpose registers to the GS. (note: I'm pretty sure this includes
|
||||||
|
@ -139,7 +142,9 @@ static void __fastcall RegHandlerSIGNAL(const u32* data)
|
||||||
GSSIGLBLID.SIGID = (GSSIGLBLID.SIGID&~data[1])|(data[0]&data[1]);
|
GSSIGLBLID.SIGID = (GSSIGLBLID.SIGID&~data[1])|(data[0]&data[1]);
|
||||||
|
|
||||||
// This is not working yet for some reason. Will have to troubleshoot it later.
|
// This is not working yet for some reason. Will have to troubleshoot it later.
|
||||||
// For now having the SIGNAL behave like other interrpts seems to be fine. --air
|
// For now having the SIGNAL behave like other interrupts seems to be fine. --air
|
||||||
|
// (note: use Soul Calibur 3 for testing double-throw Signals!)
|
||||||
|
|
||||||
/*if (!(GSIMR&0x100) )
|
/*if (!(GSIMR&0x100) )
|
||||||
{
|
{
|
||||||
if (CSRreg.SIGNAL)
|
if (CSRreg.SIGNAL)
|
||||||
|
@ -171,25 +176,22 @@ static void __fastcall RegHandlerSIGNAL(const u32* data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FINISH : Enables end-of-draw signaling. When FINISH is written it tells the GIF to
|
// FINISH : Enables end-of-draw signaling. When FINISH is written it tells the GIF to
|
||||||
// raise a gsIrq and set the FINISH bit of CSR when the current operation is finished.
|
// raise a gsIrq and set the FINISH bit of CSR when the *current drawing operation* is
|
||||||
// As far as I can figure, this feature is meant for EE/GS synchronization when the EE
|
// finished. Translation: Only after all three logical GIFpaths are in EOP status.
|
||||||
// wants to utilize GS post-processing effects. We don't need to emulate that part of
|
|
||||||
// it since we flush/interlock the GS for those specific read operations.
|
|
||||||
//
|
//
|
||||||
// However! We should properly emulate handling partial-DMA transfers on PATH2 and
|
// This feature can be used for both reversing the GS transfer mode (downloading post-
|
||||||
// PATH3 of the GIF, which means only signaling FINISH if nloop==0.
|
// processing effects to the EE), and more importantly for *DMA synch* between the
|
||||||
|
// three logical GIFpaths.
|
||||||
//
|
//
|
||||||
static void __fastcall RegHandlerFINISH(const u32* data)
|
static void __fastcall RegHandlerFINISH(const u32* data)
|
||||||
{
|
{
|
||||||
GIF_LOG("GIFpath FINISH data=%x_%x CSRr=%x\n", data[0], data[1], GSCSRr);
|
GIF_LOG("GIFpath FINISH data=%x_%x CSRr=%x\n", data[0], data[1], GSCSRr);
|
||||||
|
|
||||||
if (!CSRreg.FINISH)
|
// The FINISH bit is set here, and then it will be cleared when all three
|
||||||
{
|
// logical GIFpaths finish their packets (EOPs) At that time (found below
|
||||||
CSRreg.FINISH = true;
|
// in the GIFpath_Parser), IMR is tested and a gsIrq() raised if needed.
|
||||||
|
|
||||||
if (!(GSIMR&0x200))
|
CSRreg.FINISH = true;
|
||||||
gsIrq();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __fastcall RegHandlerLABEL(const u32* data)
|
static void __fastcall RegHandlerLABEL(const u32* data)
|
||||||
|
@ -245,7 +247,13 @@ static __aligned16 GifPathStruct s_gifPath =
|
||||||
|
|
||||||
GIFPath::GIFPath() : tag()
|
GIFPath::GIFPath() : tag()
|
||||||
{
|
{
|
||||||
memzero( *this );
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void GIFPath::Reset()
|
||||||
|
{
|
||||||
|
memzero(*this);
|
||||||
|
const_cast<GIFTAG&>(tag).EOP = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline bool GIFPath::StepReg()
|
__forceinline bool GIFPath::StepReg()
|
||||||
|
@ -292,6 +300,11 @@ __forceinline void GIFPath::SetTag(const void* mem)
|
||||||
curreg = 0;
|
curreg = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__forceinline bool GIFPath::IsActive() const
|
||||||
|
{
|
||||||
|
return (nloop != 0) || !tag.EOP;
|
||||||
|
}
|
||||||
|
|
||||||
void SaveStateBase::gifPathFreeze()
|
void SaveStateBase::gifPathFreeze()
|
||||||
{
|
{
|
||||||
FreezeTag( "GIFpath" );
|
FreezeTag( "GIFpath" );
|
||||||
|
@ -441,25 +454,25 @@ __forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
|
||||||
|
|
||||||
if(nloop > 0)
|
if(nloop > 0)
|
||||||
{
|
{
|
||||||
switch(pathidx)
|
switch(pathidx)
|
||||||
{
|
{
|
||||||
case GIF_PATH_1:
|
case GIF_PATH_1:
|
||||||
if(tag.FLG & 2)GSTransferStatus.PTH1 = IMAGE_MODE;
|
if(tag.FLG & 2)GSTransferStatus.PTH1 = IMAGE_MODE;
|
||||||
else GSTransferStatus.PTH1 = TRANSFER_MODE;
|
else GSTransferStatus.PTH1 = TRANSFER_MODE;
|
||||||
break;
|
break;
|
||||||
case GIF_PATH_2:
|
case GIF_PATH_2:
|
||||||
if(tag.FLG & 2)GSTransferStatus.PTH2 = IMAGE_MODE;
|
if(tag.FLG & 2)GSTransferStatus.PTH2 = IMAGE_MODE;
|
||||||
else GSTransferStatus.PTH2 = TRANSFER_MODE;
|
else GSTransferStatus.PTH2 = TRANSFER_MODE;
|
||||||
break;
|
break;
|
||||||
case GIF_PATH_3:
|
case GIF_PATH_3:
|
||||||
if(tag.FLG & 2) GSTransferStatus.PTH3 = IMAGE_MODE;
|
if(tag.FLG & 2) GSTransferStatus.PTH3 = IMAGE_MODE;
|
||||||
else GSTransferStatus.PTH3 = TRANSFER_MODE;
|
else GSTransferStatus.PTH3 = TRANSFER_MODE;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gifRegs->stat.OPH = true;
|
gifRegs->stat.OPH = true;
|
||||||
gifRegs->stat.APATH = pathidx + 1;
|
gifRegs->stat.APATH = pathidx + 1;
|
||||||
if(pathidx == GIF_PATH_3) break;
|
if(pathidx == GIF_PATH_3) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -518,13 +531,39 @@ __forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tag.EOP && !nloop) break;
|
|
||||||
|
if (tag.EOP && !nloop)
|
||||||
|
{
|
||||||
|
if (CSRreg.FINISH)
|
||||||
|
{
|
||||||
|
// To resolve potential confusion or false assumptions on when to FINISH:
|
||||||
|
//
|
||||||
|
// Our choices are:
|
||||||
|
// 1. only signal FINISH if ALL THREE paths are stopped (nloop is zero and EOP is set)
|
||||||
|
// 2. signal FINISH when the current path is stopped.
|
||||||
|
//
|
||||||
|
// #1 makes a lot more sense. FINISH is *not* a per-path register, and it seems to pretty
|
||||||
|
// clearly indicate that all active drawing *and* image transfer actions must be finished
|
||||||
|
// before the IRQ raises. Furthermore, the Real PS2 has only a single physical GIFpath that
|
||||||
|
// has the ability to stall Path3 in favor of Path1 and Path2 transfers, so it wouldn't
|
||||||
|
// really make sense that it would maintain anything other than #1 behavior.
|
||||||
|
//
|
||||||
|
// But! If things are working suspiciously, you can always test a hackfix by commenting out
|
||||||
|
// the conditional below; and see what happens.
|
||||||
|
|
||||||
|
if (!s_gifPath.path[0].IsActive() && !s_gifPath.path[1].IsActive() && !s_gifPath.path[2].IsActive())
|
||||||
|
{
|
||||||
|
CSRreg.FINISH = false;
|
||||||
|
if (!(GSIMR&0x200))
|
||||||
|
gsIrq();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size = (startSize - size);
|
size = (startSize - size);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (tag.EOP && nloop <= 16) {
|
if (tag.EOP && nloop <= 16) {
|
||||||
if(pathidx == 2 && nloop > 0)
|
if(pathidx == 2 && nloop > 0)
|
||||||
{
|
{
|
||||||
|
@ -617,7 +656,8 @@ __forceinline int GIFPath_ParseTagQuick(GIF_PATH pathidx, const u8* pMem, u32 si
|
||||||
// Clears all GIFpath data to zero.
|
// Clears all GIFpath data to zero.
|
||||||
void GIFPath_Reset()
|
void GIFPath_Reset()
|
||||||
{
|
{
|
||||||
memzero( s_gifPath.path );
|
for(uint i=0; i<3; ++i )
|
||||||
|
s_gifPath.path[i].Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a hackfix tool provided for "canceling" the contents of the GIFpath when
|
// This is a hackfix tool provided for "canceling" the contents of the GIFpath when
|
||||||
|
@ -625,6 +665,8 @@ void GIFPath_Reset()
|
||||||
__forceinline void GIFPath_Clear( GIF_PATH pathidx )
|
__forceinline void GIFPath_Clear( GIF_PATH pathidx )
|
||||||
{
|
{
|
||||||
memzero(s_gifPath.path[pathidx]);
|
memzero(s_gifPath.path[pathidx]);
|
||||||
|
s_gifPath.path[pathidx].Reset();
|
||||||
|
|
||||||
GSTransferStatus._u32 &= ~(0xf << (pathidx * 4));
|
GSTransferStatus._u32 &= ~(0xf << (pathidx * 4));
|
||||||
GSTransferStatus._u32 |= (0x5 << (pathidx * 4));
|
GSTransferStatus._u32 |= (0x5 << (pathidx * 4));
|
||||||
if( GSgifSoftReset == NULL ) return;
|
if( GSgifSoftReset == NULL ) return;
|
||||||
|
|
Loading…
Reference in New Issue