* SIGNAL! Pretty sure I got it handled accurately now, minus GIF stalling.

* Re-added a trace log for the GIFtag parse optimization; Fixed some mVU warnings.

DevNotes:
Places where GIF needs stalled and resumed are marked with [TODO]'s.  We also need to add a way for SIGNAL to abort the currently processing GIFtag, which might need a return code added to the callbacks.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3373 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-07-02 15:32:03 +00:00
parent 501cb676bc
commit 362294ab8b
4 changed files with 68 additions and 50 deletions

View File

@ -134,6 +134,17 @@
# define pxDebugCode(code) # define pxDebugCode(code)
#endif #endif
#ifdef PCSX2_DEVBUILD
# define pxDevelCode(code) code
#else
# define pxDevelCode(code)
#endif
#if !defined(PCSX2_DEBUG) && !defined(PCSX2_DEVEL)
# define pxReleaseCode(code)
#else
# define pxReleaseCode(code) code
#endif
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// __aligned / __aligned16 / __pagealigned // __aligned / __aligned16 / __pagealigned

View File

@ -51,7 +51,8 @@ void gsInit()
memzero(g_RealGSMem); memzero(g_RealGSMem);
} }
extern bool CSR_SIGNAL_Pending; extern bool SIGNAL_IMR_Pending;
extern u32 SIGNAL_Data_Pending[2];
void gsGIFReset() void gsGIFReset()
{ {
@ -68,7 +69,7 @@ void gsReset()
GSTransferStatus = (STOPPED_MODE<<8) | (STOPPED_MODE<<4) | STOPPED_MODE; GSTransferStatus = (STOPPED_MODE<<8) | (STOPPED_MODE<<4) | STOPPED_MODE;
memzero(g_RealGSMem); memzero(g_RealGSMem);
CSR_SIGNAL_Pending = false; SIGNAL_IMR_Pending = false;
CSRreg.Reset(); CSRreg.Reset();
GSIMR = 0x7f00; GSIMR = 0x7f00;
@ -96,7 +97,7 @@ static __forceinline void gsCSRwrite( const tGS_CSR& csr )
GetMTGS().SendSimplePacket( GS_RINGTYPE_RESET, 0, 0, 0 ); GetMTGS().SendSimplePacket( GS_RINGTYPE_RESET, 0, 0, 0 );
} }
CSR_SIGNAL_Pending = false; SIGNAL_IMR_Pending = false;
CSRreg.Reset(); CSRreg.Reset();
GSIMR = 0x7F00; //This is bits 14-8 thats all that should be 1 GSIMR = 0x7F00; //This is bits 14-8 thats all that should be 1
} }
@ -109,7 +110,15 @@ static __forceinline void gsCSRwrite( const tGS_CSR& csr )
if(csr.SIGNAL) if(csr.SIGNAL)
{ {
// SIGNAL : What's not known here is whether or not the SIGID register should be updated
// here or when the IMR is cleared (below).
GIF_LOG("GS SIGNAL (pending) data=%x_%x IMR=%x CSRr=%x\n",SIGNAL_Data_Pending[0], SIGNAL_Data_Pending[1], GSIMR, GSCSRr);
GSSIGLBLID.SIGID = (GSSIGLBLID.SIGID&~SIGNAL_Data_Pending[1])|(SIGNAL_Data_Pending[0]&SIGNAL_Data_Pending[1]);
CSRreg.SIGNAL = false; CSRreg.SIGNAL = false;
// [TODO] (SIGNAL) : Re-enable GIFpath DMAs here!
} }
if(csr.FINISH) CSRreg.FINISH = false; if(csr.FINISH) CSRreg.FINISH = false;
@ -125,17 +134,19 @@ static __forceinline void IMRwrite(u32 value)
if(CSRreg.GetInterruptMask() & (~(GSIMR >> 8) & 0x1f)) if(CSRreg.GetInterruptMask() & (~(GSIMR >> 8) & 0x1f))
gsIrq(); gsIrq();
if( CSR_SIGNAL_Pending && !(GSIMR & 0x100)) if( SIGNAL_IMR_Pending && !(GSIMR & 0x100))
{ {
// (note: PS2 apps are expected to write a successive 1 and 0 to the IMR in order to // Note: PS2 apps are expected to write a successive 1 and 0 to the IMR in order to
// trigger the gsInt and clear the second pending SIGNAL interrupt -- if they fail // trigger the gsInt and clear the second pending SIGNAL interrupt -- if they fail
// to do so, the GS will freeze again upon the very next SIGNAL). // to do so, the GS will freeze again upon the very next SIGNAL).
//
// What's not known here is whether or not the SIGID register should be updated
// here or when the GS is resumed during CSR write (above).
// It's yet unclear if the SIGNAL should be set back to TRUE or not when the IRQ is //GIF_LOG("GS SIGNAL (pending) data=%x_%x IMR=%x CSRr=%x\n",CSR_SIGNAL_Data[0], CSR_SIGNAL_Data[1], GSIMR, GSCSRr);
// raised here. Neither setting it nor leaving it be seemed to keep Soul Calibur 3 from //GSSIGLBLID.SIGID = (GSSIGLBLID.SIGID&~CSR_SIGNAL_Data[1])|(CSR_SIGNAL_Data[0]&CSR_SIGNAL_Data[1]);
// dying. This could be the fault of other emulation/timing errors in the DMA though --air
//CSRreg.SIGNAL = true; CSRreg.SIGNAL = true;
gsIrq(); gsIrq();
} }
} }
@ -441,7 +452,7 @@ void gsResetFrameSkip()
void SaveStateBase::gsFreeze() void SaveStateBase::gsFreeze()
{ {
FreezeMem(PS2MEM_GS, 0x2000); FreezeMem(PS2MEM_GS, 0x2000);
Freeze(CSR_SIGNAL_Pending); Freeze(SIGNAL_IMR_Pending);
if( GetVersion() > 0 ) if( GetVersion() > 0 )
Freeze(gsRegionMode); Freeze(gsRegionMode);

View File

@ -80,7 +80,7 @@ struct GIFTAG
struct GIFPath struct GIFPath
{ {
const GIFTAG tag; // The "original tag -- modification allowed only by SetTag(), so let's make it const. const GIFTAG tag; // A copy of the "original" tag -- modification allowed only by SetTag(), so let's make it const.
u8 regs[16]; // positioned after tag ensures 16-bit aligned (in case we SSE optimize later) u8 regs[16]; // positioned after tag ensures 16-bit aligned (in case we SSE optimize later)
u32 nloop; // local copy nloop counts toward zero, and leaves the tag copy unmodified. u32 nloop; // local copy nloop counts toward zero, and leaves the tag copy unmodified.
@ -113,59 +113,56 @@ struct GifPathStruct
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// SIGNAL / FINISH / LABEL (WIP!!) // SIGNAL / FINISH / LABEL
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// The current implementation for these is very incomplete, especially SIGNAL, which needs
// an extra VM-state status var to be handled correctly.
//
// [TODO] -- Apparently all gs writes should be ignored when this little flag is TRUE. bool SIGNAL_IMR_Pending = false;
// (not that any game's emulation accuracy probably depends on such a 'feature') --air u32 SIGNAL_Data_Pending[2];
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 do not raise a gsIrq, and ignore all
// and writes to general purpose registers to the GS. (note: I'm pretty sure this includes // subsequent drawing operations and writes to general purpose registers to the GS. (note:
// direct GS and GSreg accesses, as well as those coming through the GIFpath -- but that // I'm pretty sure this includes direct GS and GSreg accesses, as well as those coming
// behavior isn't confirmed yet). Privileged writes are still active. // through the GIFpath -- but that behavior isn't confirmed yet). Privileged writes are
// still active.
// //
// Ignorance continues until the SIGNAL bit in CSR is manually cleared by the EE. And here's // Ignorance continues until the SIGNAL bit in CSR is manually cleared by the EE. And here's
// the tricky part: the interrupt from the second SIGNAL is still pending, and should be // the tricky part: the interrupt from the second SIGNAL is still pending, and should be
// raised once the EE has reset the *IMR* mask for SIGNAL -- meaning setting the bit to 1 // raised once the EE has reset the *IMR* mask for SIGNAL -- meaning setting the bit to 1
// (disabled/masked) and then back to 0 (enabled/unmasked). // (disabled/masked) and then back to 0 (enabled/unmasked). Until the *IMR* is cleared, the
// SIGNAL is still in the second throw stage, and will freeze the GS upon being written.
// //
static void __fastcall RegHandlerSIGNAL(const u32* data) static void __fastcall RegHandlerSIGNAL(const u32* data)
{ {
GIF_LOG("GS SIGNAL data=%x_%x IMR=%x CSRr=%x\n",data[0], data[1], GSIMR, GSCSRr);
GSSIGLBLID.SIGID = (GSSIGLBLID.SIGID&~data[1])|(data[0]&data[1]);
// HACK: // HACK:
// Soul Calibur 3 has missing geometry on the Vs select screen if we only setup // Soul Calibur 3 seems to be doing SIGNALs on PATH2 and PATH3 simultaneously, and isn't
// SIGNAL when the CSR flag is cleared. It seems to be doing SIGNALs on PATH2 and // too happy with the results (dies on bootup). It properly clears the SIGNAL interrupt
// PATH3 simultaneously, and isn't too happy with the results. It properly clears the // but seems to get stuck on a VBLANK OVERLAP loop. Fixing SIGNAL so that it properly
// SIGNAL interrupt but seems to get suck on a VBLANK OVERLAP loop. // stalls the GIF might fix it. Investigating the game's internals more deeply may also
// Investigating the game's internals more deeply may prove to be revealing. --air // be revealing. --air
if (false) if (CSRreg.SIGNAL)
//if (CSRreg.SIGNAL) // breaks SC3
{ {
// Time to ignore all subsequent drawing operations. (which is not yet supported) // Time to ignore all subsequent drawing operations. (which is not yet supported)
if (!CSR_SIGNAL_Pending) if (!SIGNAL_IMR_Pending)
{ {
DevCon.WriteLn( Color_StrongOrange, "GS SIGNAL double throw encountered!" ); DevCon.WriteLn( Color_StrongOrange, "GS SIGNAL double throw encountered!" );
CSR_SIGNAL_Pending = true; SIGNAL_IMR_Pending = true;
SIGNAL_Data_Pending[0] = data[0];
SIGNAL_Data_Pending[1] = data[1];
// [TODO] (SIGNAL) : Disable GIFpath DMAs here!
// All PATHs and DMAs should be disabled until the CSR is written and the
// SIGNAL bit cleared.
} }
} }
else else
{ {
// notes: GIF_LOG("GS SIGNAL data=%x_%x IMR=%x CSRr=%x\n",data[0], data[1], GSIMR, GSCSRr);
// * DDS SMT however crashes at the first FMV if SIGNAL raises IRQs constantly, GSSIGLBLID.SIGID = (GSSIGLBLID.SIGID&~data[1])|(data[0]&data[1]);
// so that's why we only raise an IRQ if both signal and GSIMR are prepped.
// (this might be correct behavior-- hard to tell yet) --air
if (!CSRreg.SIGNAL && !(GSIMR&0x100) ) if (!(GSIMR&0x100))
gsIrq(); gsIrq();
CSRreg.SIGNAL = true; CSRreg.SIGNAL = true;
@ -472,7 +469,7 @@ __forceinline int GIFPath::ParseTagQuick(GIF_PATH pathidx, const u8* pMem, u32 s
} }
else else
{ {
// Note: The BIOS does an XGKICK on the VU1 and lets yt DMA to the GS without an EOP // Note: The BIOS does an XGKICK on the VU1 and lets it DMA to the GS without an EOP
// (seemingly to loop forever), only to write an EOP later on. No other game is known to // (seemingly to loop forever), only to write an EOP later on. No other game is known to
// do anything of the sort. // do anything of the sort.
// So lets just cap the DMA at 16k, and force it to "look" like it's terminated for now. // So lets just cap the DMA at 16k, and force it to "look" like it's terminated for now.
@ -482,7 +479,6 @@ __forceinline int GIFPath::ParseTagQuick(GIF_PATH pathidx, const u8* pMem, u32 s
Console.Warning("GIFTAG error, size exceeded VU memory size %x", startSize); Console.Warning("GIFTAG error, size exceeded VU memory size %x", startSize);
nloop = 0; nloop = 0;
const_cast<GIFTAG&>(tag).EOP = 0;
} }
} }
} }
@ -580,6 +576,8 @@ __forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
} }
else else
{ {
//DevCon.WriteLn(Color_Orange, "No E detected on Path%d: nloop=%x, numregs=%x, curreg=%x, size=%x", pathidx + 1, nloop, numregs, curreg, size);
// Note: curreg is *usually* zero here, but can be non-zero if a previous fragment was // Note: curreg is *usually* zero here, but can be non-zero if a previous fragment was
// handled via this optimized copy code below. // handled via this optimized copy code below.
@ -670,7 +668,6 @@ __forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
Console.Warning("GIFTAG error, size exceeded VU memory size %x", startSize); Console.Warning("GIFTAG error, size exceeded VU memory size %x", startSize);
nloop = 0; nloop = 0;
const_cast<GIFTAG&>(tag).EOP = 0;
} }
} }
} }
@ -683,10 +680,9 @@ __forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
// FINISH is *not* a per-path register, and it seems to pretty clearly indicate that all active // 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. // drawing *and* image transfer actions must be finished before the IRQ raises.
if (!s_gifPath.path[0].IsActive() && !s_gifPath.path[1].IsActive() && !s_gifPath.path[2].IsActive()) if (!(GSIMR&0x200) && !s_gifPath.path[0].IsActive() && !s_gifPath.path[1].IsActive() && !s_gifPath.path[2].IsActive())
{ {
if (!(GSIMR&0x200)) gsIrq();
gsIrq();
} }
} }
break; break;

View File

@ -295,9 +295,9 @@ _mVUt _f void* mVUsearchProg(u32 startPC, uptr pState) {
return entryPoint; return entryPoint;
} catch( BaseException& ex ) { } catch( BaseException& pxDevelCode(ex) ) {
pxFailDev( wxsFormat(L"microVU%d recompiler exception: " + ex.FormatDiagnosticMessage(), mVU->index) ); pxFailDev( wxsFormat(L"microVU%d recompiler exception: " + ex.FormatDiagnosticMessage(), mVU->index) );
} catch( std::exception& ex ) { } catch( std::exception& pxDevelCode(ex) ) {
pxFailDev( wxsFormat(L"microVU%d recompiler exception: " + Exception::RuntimeError(ex).FormatDiagnosticMessage(), mVU->index) ); pxFailDev( wxsFormat(L"microVU%d recompiler exception: " + Exception::RuntimeError(ex).FormatDiagnosticMessage(), mVU->index) );
} }