Big gif transfer code rewrite!

Pcsx2 now has a gifUnit class which acts like the ps2's gif and executes a single gif transfer at a time (and performs path arbitration according to priority and path3 slicing).

This new code is generally a speedup for most games. Particularly VU heavy games like GoW.
This revision breaks old saved state compatibility so don't update if you wish to keep playing with your old saved states.
Leave comments if this revision fixes or breaks anything...

Message to GS Plugin authors:
This new code now uses only 1 gif callback to transfer data to the gs plugin (GSgifTransfer).
pcsx2 also is garaunteed to send full GS primitives to the plugin. So you don't have to account for partial-transfers anymore.

Thanks goes out to shadowlady who tested around 500 games for me :D

Note 1: The old gif code is still in this revision, and can be enabled by the USE_OLD_GIF macro. The old code will be deleted soon.
Note 2: This revision also enables assertion dialogs in devel builds, and changed a lot of assume cases into assertions.


git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4821 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
cottonvibes 2011-07-24 13:02:50 +00:00
parent 7cb4dbb8d9
commit c05dc759e3
78 changed files with 1530 additions and 758 deletions

View File

@ -309,6 +309,7 @@ static const int __pagesize = PCSX2_PAGESIZE;
#define __ri __releaseinline
#define __fi __forceinline
#define __fc __fastcall
#define elif else if
#endif

View File

@ -84,15 +84,18 @@ extern pxDoAssertFnType* pxDoAssert;
// --------------------------------------------------------------------------------------
// pxAssume / pxAssumeDev / pxFail / pxFailDev
// --------------------------------------------------------------------------------------
// Assumptions are like "extra rigid" assertions, which should never fail under any circum-
// stance in release build optimized code.
// Assumptions are hints to the compiler that the condition will always be true,
// the condition should never fail under any circumstance in release builds
// or else you might get incorrect compiler generated code.
//
// Performance: All assumption/fail types optimize into __assume()/likely() directives in
// Release builds (non-dev varieties optimize as such in Devel builds as well). If using
// Release builds (non-dev varieties optimize as such in Devel builds as well).
// __assume(0) is a special form of __assume() which tells the compiler that the code path
// is not reachable and will cause undefined results if it is reachable...
//
// Having pxFail and pxFailDev translate into __assume statements is very dangerous, since
// it can lead to the compiler optimizing out code and leading to crashes in dev/release
// builds. To have code optimized, explicitly use pxAssume(false) or pxAssumeDev(false,msg);
// builds. To have code optimized, explicitly use pxAssume(false) or pxAssumeDev(false,msg);
#define pxDiagSpot DiagnosticOrigin( __TFILE__, __LINE__, __pxFUNCTION__ )
#define pxAssertSpot(cond) DiagnosticOrigin( __TFILE__, __LINE__, __pxFUNCTION__, _T(#cond) )
@ -119,16 +122,26 @@ extern pxDoAssertFnType* pxDoAssert;
#elif defined(PCSX2_DEVBUILD)
// Devel builds use __assume for standard assertions and call pxOnAssertDevel
// for AssertDev brand assertions (which typically throws a LogicError exception).
// Devel builds now will give you a release-mode assertion dialog window if any of the
// following macro's 'cond' field is false.
// Note: Only use pxAssume/Msg/Dev if you know what you're doing, __assume is supposed
// to be used as an optimization hint, yet many devs have been using psAssume
// thinking its the same as an assertion.
// __assume(0) is also very dangerous because it is a special case of __assume() which
// tells the compiler that the code path is not reachable, and it can cause unpredictable
// results if the code path can be reached.
// i.e. if (1) { __assume(0); something(); }
// In the above example, something() may never be called.
// __assume(0)'s real use is in optimizing stuff such as "default:" cases on a switch
// statement. See jNO_DEFAULT
# define pxAssertMsg(cond, msg) (likely(cond))
# define pxAssertMsg(cond, msg) pxAssertRel(cond, msg)
# define pxAssertDev(cond, msg) pxAssertRel(cond, msg)
# define pxAssumeMsg(cond, msg) (__assume(cond))
# define pxAssumeMsg(cond, msg) pxAssumeRel(cond, msg) //(__assume(cond))
# define pxAssumeDev(cond, msg) pxAssumeRel(cond, msg)
# define pxFail(msg)
# define pxFail(msg) pxAssertDev(false, msg)
# define pxFailDev(msg) pxAssertDev(false, msg)
#else
@ -142,8 +155,8 @@ extern pxDoAssertFnType* pxDoAssert;
# define pxAssumeMsg(cond, msg) (__assume(cond))
# define pxAssumeDev(cond, msg) (__assume(cond))
# define pxFail(msg)
# define pxFailDev(msg)
# define pxFail(msg) do{} while(0)
# define pxFailDev(msg) do{} while(0)
#endif
@ -186,7 +199,7 @@ extern void pxOnAssert( const DiagnosticOrigin& origin, const char* msg );
# define jNO_DEFAULT \
default: \
{ \
pxAssumeDev( false, "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)" ); \
pxAssumeDev( 0, "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)" ); \
break; \
}
#endif

View File

@ -195,18 +195,19 @@ public:
// --------------------------------------------------------------------------------------
// Handy Human-readable constants for common immediate values (_16kb -> _4gb)
static const sptr _64kb = 0x10000;
static const sptr _16kb = _64kb / 4;
static const sptr _128kb = _64kb * 2;
static const sptr _256kb = _128kb * 2;
static const sptr _1kb = 1024 * 1;
static const sptr _16kb = _1kb * 16;
static const sptr _64kb = _1kb * 64;
static const sptr _128kb = _1kb * 128;
static const sptr _256kb = _1kb * 256;
static const s64 _1mb = 0x100000;
static const s64 _1mb = 1024 * 1024;
static const s64 _8mb = _1mb * 8;
static const s64 _16mb = _1mb * 16;
static const s64 _32mb = _1mb * 32;
static const s64 _64mb = _1mb * 64;
static const s64 _256mb = _1mb * 256;
static const s64 _1gb = _256mb * 4;
static const s64 _1gb = _1mb * 1024;
static const s64 _4gb = _1gb * 4;

View File

@ -43,7 +43,7 @@ public:
void SetPath( const wxString& path );
void Flush();
wxConfigBase& GetConfig() { pxAssume( m_Config ); return *m_Config; }
wxConfigBase& GetConfig() { pxAssert( m_Config ); return *m_Config; }
bool IsOk() const { return m_Config != NULL; }
virtual bool IsLoading() const=0;

View File

@ -199,13 +199,13 @@ public:
u8& operator[](uint idx)
{
pxAssume(idx < (m_pages_reserved * __pagesize));
pxAssert(idx < (m_pages_reserved * __pagesize));
return *((u8*)m_baseptr + idx);
}
const u8& operator[](uint idx) const
{
pxAssume(idx < (m_pages_reserved * __pagesize));
pxAssert(idx < (m_pages_reserved * __pagesize));
return *((u8*)m_baseptr + idx);
}

View File

@ -107,7 +107,7 @@ public:
virtual ~BaseScopedAlloc() throw()
{
//pxAssume(m_buffer==NULL);
//pxAssert(m_buffer==NULL);
}
public:

View File

@ -50,12 +50,12 @@ public:
pxCheckBox& SetIndeterminate();
pxCheckBox& SetState( wxCheckBoxState state );
wxCheckBoxState GetState() const { pxAssume( m_checkbox != NULL ); return m_checkbox->Get3StateValue(); }
bool GetValue() const { pxAssume( m_checkbox != NULL ); return m_checkbox->GetValue(); }
bool IsChecked() const { pxAssume( m_checkbox != NULL ); return m_checkbox->IsChecked(); }
bool IsIndeterminate() const { pxAssume( m_checkbox != NULL ); return m_checkbox->Get3StateValue() == wxCHK_UNDETERMINED; }
operator wxCheckBox&() { pxAssume( m_checkbox != NULL ); return *m_checkbox; }
operator const wxCheckBox&() const { pxAssume( m_checkbox != NULL ); return *m_checkbox; }
wxCheckBoxState GetState() const { pxAssert( m_checkbox != NULL ); return m_checkbox->Get3StateValue(); }
bool GetValue() const { pxAssert( m_checkbox != NULL ); return m_checkbox->GetValue(); }
bool IsChecked() const { pxAssert( m_checkbox != NULL ); return m_checkbox->IsChecked(); }
bool IsIndeterminate() const { pxAssert( m_checkbox != NULL ); return m_checkbox->Get3StateValue() == wxCHK_UNDETERMINED; }
operator wxCheckBox&() { pxAssert( m_checkbox != NULL ); return *m_checkbox; }
operator const wxCheckBox&() const { pxAssert( m_checkbox != NULL ); return *m_checkbox; }
wxCheckBox* GetWxPtr() { return m_checkbox; }
const wxCheckBox* GetWxPtr() const { return m_checkbox; }

View File

@ -501,7 +501,7 @@ template< typename T > void xWrite( T val );
&xmm6, &xmm7
};
pxAssume(id < iREGCNT_XMM);
pxAssert(id < iREGCNT_XMM);
return *m_tbl_xmmRegs[id];
}

View File

@ -28,7 +28,7 @@ static const uint headsize = sizeof(AlignedMallocHeader);
void* __fastcall pcsx2_aligned_malloc(size_t size, size_t align)
{
pxAssume( align < 0x10000 );
pxAssert( align < 0x10000 );
u8* p = (u8*)malloc(size+align+headsize);
@ -37,7 +37,7 @@ void* __fastcall pcsx2_aligned_malloc(size_t size, size_t align)
uptr aligned = (pasthead + align-1) & ~(align-1);
AlignedMallocHeader* header = (AlignedMallocHeader*)(aligned-headsize);
pxAssume( (uptr)header >= (uptr)p );
pxAssert( (uptr)header >= (uptr)p );
header->baseptr = p;
header->size = size;
@ -47,7 +47,7 @@ void* __fastcall pcsx2_aligned_malloc(size_t size, size_t align)
void* __fastcall pcsx2_aligned_realloc(void* handle, size_t size, size_t align)
{
pxAssume( align < 0x10000 );
pxAssert( align < 0x10000 );
void* newbuf = pcsx2_aligned_malloc( size, align );

View File

@ -92,14 +92,14 @@ public:
BufferType& GrabBuffer()
{
++m_curslot;
pxAssume(m_curslot < BufferCount);
pxAssert(m_curslot < BufferCount);
return m_buffers[m_curslot];
}
void ReleaseBuffer()
{
--m_curslot;
pxAssume(m_curslot < BufferCount);
pxAssert(m_curslot < BufferCount);
}
BufferType& operator[](uint i)

View File

@ -270,7 +270,7 @@ void Threading::ScopedLock::AssignAndLock( const Mutex& locker )
void Threading::ScopedLock::AssignAndLock( const Mutex* locker )
{
pxAssume(!m_IsLocked); // if we're already locked, changing the lock is bad mojo.
pxAssert(!m_IsLocked); // if we're already locked, changing the lock is bad mojo.
m_lock = const_cast<Mutex*>(locker);
if( !m_lock ) return;

View File

@ -44,7 +44,7 @@ void pxInstallSignalHandler()
// --------------------------------------------------------------------------------------
EventListener_PageFault::EventListener_PageFault()
{
pxAssume(Source_PageFault);
pxAssert(Source_PageFault);
Source_PageFault->Add( *this );
}

View File

@ -83,14 +83,14 @@ pxCheckBox& pxCheckBox::SetToolTip( const wxString& tip )
pxCheckBox& pxCheckBox::SetValue( bool val )
{
pxAssume( m_checkbox );
pxAssert( m_checkbox );
m_checkbox->SetValue( val );
return *this;
}
pxCheckBox& pxCheckBox::SetIndeterminate()
{
pxAssume( m_checkbox );
pxAssert( m_checkbox );
m_checkbox->Set3StateValue( wxCHK_UNDETERMINED );
return *this;
}
@ -98,7 +98,7 @@ pxCheckBox& pxCheckBox::SetIndeterminate()
pxCheckBox& pxCheckBox::SetState( wxCheckBoxState state )
{
pxAssume( m_checkbox );
pxAssert( m_checkbox );
m_checkbox->Set3StateValue( state );
return *this;
}

View File

@ -116,7 +116,7 @@ pxStaticText& pxStaticText::PaddingPixV( int pixels )
pxStaticText& pxStaticText::PaddingPctH( float pct )
{
pxAssume( pct < 0.5 );
pxAssert( pct < 0.5 );
m_paddingPct_horiz = pct;
UpdateWrapping( false );
@ -126,7 +126,7 @@ pxStaticText& pxStaticText::PaddingPctH( float pct )
pxStaticText& pxStaticText::PaddingPctV( float pct )
{
pxAssume( pct < 0.5 );
pxAssert( pct < 0.5 );
m_paddingPct_vert = pct;
Refresh();
@ -152,7 +152,7 @@ int pxStaticText::calcPaddingHeight( int newHeight ) const
wxSize pxStaticText::GetBestWrappedSize( const wxClientDC& dc ) const
{
pxAssume( m_autowrap );
pxAssert( m_autowrap );
// Find an ideal(-ish) width, based on a search of all parent controls and their
// valid Minimum sizes.

View File

@ -86,7 +86,7 @@ pxWindowTextWriter& pxWindowTextWriter::MoveY( int ydelta )
void pxWindowTextWriter::_DoWriteLn( const wxChar* msg )
{
pxAssume( msg );
pxAssert( msg );
int tWidth, tHeight;
m_dc.GetMultiLineTextExtent( msg, &tWidth, &tHeight );
@ -110,7 +110,7 @@ void pxWindowTextWriter::_DoWriteLn( const wxChar* msg )
// to the text writer.
void pxWindowTextWriter::_DoWrite( const wxChar* msg )
{
pxAssume( msg );
pxAssert( msg );
wxArrayString parts;
SplitString( parts, msg, L'\n' );

View File

@ -44,7 +44,7 @@ ConsoleLogSource_App pxConLog_App;
void BaseDeletableObject::DoDeletion()
{
wxAppWithHelpers* app = wxDynamicCast( wxApp::GetInstance(), wxAppWithHelpers );
pxAssume( app != NULL );
pxAssert( app != NULL );
app->DeleteObject( *this );
}

View File

@ -616,6 +616,6 @@ wxFont pxGetFixedFont( int ptsize, int weight )
wxString pxGetAppName()
{
pxAssume( wxTheApp );
pxAssert( wxTheApp );
return wxTheApp->GetAppName();
}

View File

@ -368,7 +368,7 @@ void wxDialogWithHelpers::AddOkCancel( wxSizer &sizer, bool hasApply )
void wxDialogWithHelpers::AddOkCancel( wxSizer *sizer, bool hasApply )
{
if( sizer == NULL ) sizer = GetSizer();
pxAssume( sizer );
pxAssert( sizer );
AddOkCancel( *sizer, hasApply );
}

View File

@ -831,7 +831,7 @@ __fi void cdvdReadInterrupt()
// Any other value besides 0 should be considered invalid here (wtf is that wacky
// plugin trying to do?)
pxAssume( cdvd.RErr == 0 );
pxAssert( cdvd.RErr == 0 );
}
if (cdvd.nSectors > 0)
@ -844,7 +844,7 @@ __fi void cdvdReadInterrupt()
// An arbitrary delay of some number of cycles probably makes more sense here,
// but for now it's based on the cdvd.ReadTime value. -- air
pxAssume((int)cdvd.ReadTime > 0 );
pxAssert((int)cdvd.ReadTime > 0 );
CDVDREAD_INT(cdvd.ReadTime/4);
return;
}

View File

@ -185,14 +185,14 @@ void isoFile::_ReadBlockD(u8* dst, uint lsn)
void isoFile::_ReadBlock(u8* dst, uint lsn)
{
pxAssumeMsg(lsn <= m_blocks, "Invalid lsn passed into isoFile::_ReadBlock.");
pxAssumeMsg(m_numparts, "Invalid isoFile object state; an iso file needs at least one part!");
pxAssertMsg(lsn <= m_blocks, "Invalid lsn passed into isoFile::_ReadBlock.");
pxAssertMsg(m_numparts, "Invalid isoFile object state; an iso file needs at least one part!");
uint i;
for (i = 0; i < m_numparts-1; ++i)
{
// lsn indexes should always go in order; use an assertion just to be sure:
pxAssume(lsn >= m_parts[i].slsn);
pxAssert(lsn >= m_parts[i].slsn);
if (lsn <= m_parts[i].elsn) break;
}

View File

@ -18,6 +18,7 @@
#include "Common.h"
#include "Gif.h"
#include "Gif_Unit.h"
#include "GS.h"
#include "Vif.h"
#include "Vif_Dma.h"
@ -55,6 +56,9 @@ void __fastcall ReadFIFO_VIF1(mem128_t* out)
GetMTGS().WaitGS();
GSreadFIFO((u64*)out);
vif1.GSLastDownloadSize--;
#if USE_OLD_GIF == 0 // d
GUNIT_LOG("ReadFIFO_VIF1");
#endif
if (vif1.GSLastDownloadSize <= 16)
gifRegs.stat.OPH = false;
vif1Regs.stat.FQC = min((u32)16, vif1.GSLastDownloadSize);
@ -100,12 +104,15 @@ void __fastcall WriteFIFO_VIF1(const mem128_t *value)
if(vif1.irqoffset != 0 && vif1.vifstalled == true) DevCon.Warning("Offset on VIF1 FIFO start!");
bool ret = VIF1transfer((u32*)value, 4);
#if USE_OLD_GIF == 1 // d
if(GSTransferStatus.PTH2 == STOPPED_MODE && gifRegs.stat.APATH == GIF_APATH2)
{
if(gifRegs.stat.DIR == 0)gifRegs.stat.OPH = false;
gifRegs.stat.APATH = GIF_APATH_IDLE;
if(gifRegs.stat.P1Q) gsPath1Interrupt();
}
#endif
if (vif1.cmd)
{
if(vif1.done == true && vif1ch.qwc == 0) vif1Regs.stat.VPS = VPS_WAITING;
@ -120,6 +127,7 @@ void __fastcall WriteFIFO_VIF1(const mem128_t *value)
void __fastcall WriteFIFO_GIF(const mem128_t *value)
{
#if USE_OLD_GIF == 1 // d
GIF_LOG("WriteFIFO/GIF <- %ls", value->ToString().c_str());
//CopyQWC(&psHu128(GIF_FIFO), value);
@ -139,4 +147,9 @@ void __fastcall WriteFIFO_GIF(const mem128_t *value)
if(gifRegs.stat.P1Q) gsPath1Interrupt();
}
}
#else
GUNIT_LOG("WriteFIFO_GIF()");
gifUnit.TransferGSPacketData(GIF_TRANS_FIFO, (u8*)value, 16);
#endif
}

View File

@ -20,6 +20,7 @@
#include "GS.h"
#include "Gif.h"
#include "Gif_Unit.h"
#include "Counters.h"
using namespace Threading;
@ -51,38 +52,35 @@ void gsInit()
memzero(g_RealGSMem);
}
#if USE_OLD_GIF == 1 // d
extern bool SIGNAL_IMR_Pending;
extern u32 SIGNAL_Data_Pending[2];
void gsGIFReset()
{
gifRegs.stat.reset();
gifRegs.ctrl.reset();
gifRegs.mode.reset();
}
#endif
void gsReset()
{
GetMTGS().ResetGS();
UpdateVSyncRate();
GSTransferStatus = (STOPPED_MODE<<8) | (STOPPED_MODE<<4) | STOPPED_MODE;
memzero(g_RealGSMem);
#if USE_OLD_GIF == 1 // d
GSTransferStatus = (STOPPED_MODE<<8) | (STOPPED_MODE<<4) | STOPPED_MODE;
SIGNAL_IMR_Pending = false;
CSRreg.Reset();
GSIMR = 0x7f00;
// FIXME: This really doesn't belong here, and I seriously doubt it's needed.
// If it is needed it should be in the GIF portion of hwReset(). --air
gsGIFReset();
gifUnit.ResetRegs();
#endif
CSRreg.Reset();
GSIMR = 0x7f00;
}
static __fi void gsCSRwrite( const tGS_CSR& csr )
{
if (csr.RESET) {
#if USE_OLD_GIF == 1 // ...
// perform a soft reset -- which is a clearing of all GIFpaths -- and fall back to doing
// a full reset if the plugin doesn't support soft resets.
@ -98,6 +96,13 @@ static __fi void gsCSRwrite( const tGS_CSR& csr )
}
SIGNAL_IMR_Pending = false;
#else
GUNIT_WARN("csr.RESET");
//gifUnit.Reset(true); // Don't think gif should be reset...
gifUnit.gsSIGNAL.queued = false;
GetMTGS().SendSimplePacket(GS_RINGTYPE_RESET, 0, 0, 0);
#endif
CSRreg.Reset();
GSIMR = 0x7F00; //This is bits 14-8 thats all that should be 1
}
@ -110,6 +115,7 @@ static __fi void gsCSRwrite( const tGS_CSR& csr )
if(csr.SIGNAL)
{
#if USE_OLD_GIF == 1 // d
// SIGNAL : What's not known here is whether or not the SIGID register should be updated
// here or when the IMR is cleared (below).
@ -119,8 +125,7 @@ static __fi void gsCSRwrite( const tGS_CSR& csr )
GIF_LOG("GS SIGNAL (pending) data=%x_%x IMR=%x CSRr=%x",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]);
if (!(GSIMR&0x100))
gsIrq();
if (!(GSIMR&0x100)) gsIrq();
CSRreg.SIGNAL = true; //Just to be sure :P
}
@ -129,6 +134,20 @@ static __fi void gsCSRwrite( const tGS_CSR& csr )
SIGNAL_IMR_Pending = false;
if(gifRegs.stat.P1Q && gifRegs.stat.APATH <= GIF_APATH1) gsPath1Interrupt();
#else
GUNIT_LOG("csr.SIGNAL");
if (gifUnit.gsSIGNAL.queued) {
//DevCon.Warning("Firing pending signal");
GSSIGLBLID.SIGID = (GSSIGLBLID.SIGID & ~gifUnit.gsSIGNAL.data[1])
| (gifUnit.gsSIGNAL.data[0]&gifUnit.gsSIGNAL.data[1]);
if (!(GSIMR&0x100)) gsIrq();
CSRreg.SIGNAL = true; // Just to be sure :P
}
else CSRreg.SIGNAL = false;
gifUnit.gsSIGNAL.queued = false;
gifUnit.Execute();
#endif
}
if(csr.FINISH) CSRreg.FINISH = false;
@ -144,6 +163,7 @@ static __fi void IMRwrite(u32 value)
if(CSRreg.GetInterruptMask() & (~(GSIMR >> 8) & 0x1f))
gsIrq();
#if USE_OLD_GIF == 1 // d
if( SIGNAL_IMR_Pending && !(GSIMR & 0x100))
{
// Note: PS2 apps are expected to write a successive 1 and 0 to the IMR in order to
@ -159,6 +179,13 @@ static __fi void IMRwrite(u32 value)
CSRreg.SIGNAL = true;
gsIrq();
}
#else
GUNIT_LOG("IMRwrite()");
if (gifUnit.gsSIGNAL.queued && !(GSIMR & 0x100)) {
CSRreg.SIGNAL = true;
gsIrq();
}
#endif
}
__fi void gsWrite8(u32 mem, u8 value)
@ -166,7 +193,7 @@ __fi void gsWrite8(u32 mem, u8 value)
switch (mem)
{
// CSR 8-bit write handlers.
// I'm quite sure these whould just write the CSR portion with the other
// I'm quite sure these would just write the CSR portion with the other
// bits set to 0 (no action). The previous implementation masked the 8-bit
// write value against the previous CSR write value, but that really doesn't
// make any sense, given that the real hardware's CSR circuit probably has no
@ -280,8 +307,8 @@ void __fastcall gsWrite64_page_01( u32 mem, const mem64_t* value )
switch( mem )
{
case 0x12001040: //busdir
case GS_BUSDIR:
#if USE_OLD_GIF == 1 // d
//This is probably a complete hack, however writing to BUSDIR "should" start a transfer
//Only problem is it kills killzone :(.
// (yes it *is* a complete hack; both lines here in fact --air)
@ -294,12 +321,22 @@ void __fastcall gsWrite64_page_01( u32 mem, const mem64_t* value )
//
// Yup folks. BUSDIR is evil. The only safe way to handle it is to flush the whole MTGS
// and ensure complete MTGS and EEcore thread synchronization This is very slow, no doubt,
// but on the birght side BUSDIR is used quite rately, indeed.
// but on the bright side BUSDIR is used quite rarely, indeed.
// Important: writeback to gsRegs area *prior* to flushing the MTGS. The flush will sync
// the GS and MTGS register states, and upload our screwy busdir register in the process. :)
gsWrite64_generic( mem, value );
GetMTGS().WaitGS();
#else
GUNIT_LOG("GIF - busdir");
gifRegs.stat.DIR = value[0] & 1;
if (gifRegs.stat.DIR) { // Assume will do local->host transfer?
gifRegs.stat.OPH = true; // Is OPH set on local->host transfers?
DevCon.WriteLn("Busdir - Local->Host Transfer");
}
gsWrite64_generic( mem, value );
GetMTGS().WaitGS();
#endif
return;
case GS_CSR:
@ -461,7 +498,9 @@ void gsResetFrameSkip()
void SaveStateBase::gsFreeze()
{
FreezeMem(PS2MEM_GS, 0x2000);
#if USE_OLD_GIF == 1 // d
Freeze(SIGNAL_IMR_Pending);
#endif
Freeze(gsRegionMode);
gifPathFreeze();

View File

@ -17,6 +17,7 @@
#include "Common.h"
#include "System/SysThreads.h"
#include "Gif.h"
extern __aligned16 u8 g_RealGSMem[Ps2MemSize::GSregs];
@ -222,19 +223,6 @@ enum GS_RegionMode
Region_PAL
};
enum GIF_PATH
{
GIF_PATH_1 = 0,
GIF_PATH_2,
GIF_PATH_3,
};
extern void GIFPath_Initialize();
extern int GIFPath_CopyTag(GIF_PATH pathidx, const u128* pMem, u32 size);
extern int GIFPath_ParseTagQuick(GIF_PATH pathidx, const u8* pMem, u32 size);
extern void GIFPath_Reset();
extern void GIFPath_Clear( GIF_PATH pathidx );
extern GS_RegionMode gsRegionMode;
/////////////////////////////////////////////////////////////////////////////
@ -256,6 +244,7 @@ enum MTGS_RingCommand
, GS_RINGTYPE_SOFTRESET // issues a soft reset for the GIF
, GS_RINGTYPE_MODECHANGE // for issued mode changes.
, GS_RINGTYPE_CRC
, GS_RINGTYPE_GSPACKET
};
@ -326,6 +315,7 @@ public:
void WaitForOpen();
void Freeze( int mode, MTGS_FreezeData& data );
void SendSimpleGSPacket( MTGS_RingCommand type, u32 offset, u32 size, GIF_PATH path );
void SendSimplePacket( MTGS_RingCommand type, int data0, int data1, int data2 );
void SendPointerPacket( MTGS_RingCommand type, u32 data0, void* data1 );
@ -377,10 +367,6 @@ extern void gsFrameSkip();
// Some functions shared by both the GS and MTGS
extern void _gs_ResetFrameskip();
// used for resetting GIF fifo
extern void gsGIFReset();
extern void gsWrite8(u32 mem, u8 value);
extern void gsWrite16(u32 mem, u16 value);
extern void gsWrite32(u32 mem, u32 value);
@ -449,5 +435,30 @@ extern __aligned(32) MTGS_BufferedData RingBuffer;
// FIXME: These belong in common with other memcpy tools. Will move them there later if no one
// else beats me to it. --air
extern void MemCopy_WrappedDest( const u128* src, u128* destBase, uint& destStart, uint destSize, uint len );
extern void MemCopy_WrappedSrc( const u128* srcBase, uint& srcStart, uint srcSize, u128* dest, uint len );
inline void MemCopy_WrappedDest( const u128* src, u128* destBase, uint& destStart, uint destSize, uint len ) {
uint endpos = destStart + len;
if ( endpos < destSize ) {
memcpy_qwc(&destBase[destStart], src, len );
destStart += len;
}
else {
uint firstcopylen = destSize - destStart;
memcpy_qwc(&destBase[destStart], src, firstcopylen );
destStart = endpos % destSize;
memcpy_qwc(destBase, src+firstcopylen, destStart );
}
}
inline void MemCopy_WrappedSrc( const u128* srcBase, uint& srcStart, uint srcSize, u128* dest, uint len ) {
uint endpos = srcStart + len;
if ( endpos < srcSize ) {
memcpy_qwc(dest, &srcBase[srcStart], len );
srcStart += len;
}
else {
uint firstcopylen = srcSize - srcStart;
memcpy_qwc(dest, &srcBase[srcStart], firstcopylen );
srcStart = endpos % srcSize;
memcpy_qwc(dest+firstcopylen, srcBase, srcStart );
}
}

View File

@ -18,6 +18,7 @@
#include "GS.h"
#include "Gif.h"
#include "Gif_Unit.h"
#include "Vif_Dma.h"
#include "iR5900.h"
@ -26,71 +27,54 @@ using std::min;
// A three-way toggle used to determine if the GIF is stalling (transferring) or done (finished).
// Should be a gifstate_t rather then int, but I don't feel like possibly interfering with savestates right now.
static int gifstate = GIF_STATE_READY;
static int gifstate = GIF_STATE_READY;
static bool gspath3done = false;
static u32 gscycles = 0, prevcycles = 0, mfifocycles = 0;
static u32 gifqwc = 0;
static bool gifmfifoirq = false;
#if USE_OLD_GIF == 1 // d
//Just some temporary bits to store Path1 transfers if another is in progress.
__aligned16 u8 Path1Buffer[0x1000000];
u32 Path1WritePos = 0;
u32 Path1ReadPos = 0;
static __fi void clearFIFOstuff(bool full)
{
if (full)
CSRreg.FIFO = CSR_FIFO_FULL;
else
CSRreg.FIFO = CSR_FIFO_EMPTY;
}
extern bool SIGNAL_IMR_Pending;
void gsPath1Interrupt()
{
//DevCon.Warning("Path1 flush W %x, R %x", Path1WritePos, Path1ReadPos);
if((gifRegs.stat.APATH <= GIF_APATH1 || (gifRegs.stat.IP3 == true)) && Path1WritePos > 0 && !gifRegs.stat.PSE && SIGNAL_IMR_Pending == false)
{
if ((gifRegs.stat.APATH <= GIF_APATH1 || (gifRegs.stat.IP3 == true))
&& Path1WritePos > 0 && !gifRegs.stat.PSE && SIGNAL_IMR_Pending == false) {
gifRegs.stat.P1Q = false;
if (uint size = (Path1WritePos - Path1ReadPos))
{
if (uint size = (Path1WritePos - Path1ReadPos)) {
GetMTGS().PrepDataPacket(GIF_PATH_1, size);
//DevCon.Warning("Flush Size = %x", size);
while(size > 0 && SIGNAL_IMR_Pending == false)
{
while(size > 0 && SIGNAL_IMR_Pending == false) {
uint count = GIFPath_CopyTag(GIF_PATH_1, ((u128*)Path1Buffer) + Path1ReadPos, size);
Path1ReadPos += count;
size -= count;
if(GSTransferStatus.PTH1 == STOPPED_MODE)
{
if(GSTransferStatus.PTH1 == STOPPED_MODE) {
gifRegs.stat.OPH = false;
gifRegs.stat.APATH = GIF_APATH_IDLE;
}
}
GetMTGS().SendDataPacket();
if(Path1ReadPos == Path1WritePos)
{
if (Path1ReadPos == Path1WritePos) {
Path1WritePos = Path1ReadPos = 0;
}
else
{
else {
//DevCon.Warning("Queue quitting early due to signal or EOP %x", size);
gifRegs.stat.P1Q = true;
}
}
}
else
{
else {
if(gifRegs.stat.PSE) DevCon.Warning("Path1 paused by GIF_CTRL");
if(gifRegs.stat.P1Q == false && Path1ReadPos != Path1WritePos)
{
if(gifRegs.stat.P1Q == false && Path1ReadPos != Path1WritePos) {
DevCon.Warning("Wa's Goin on ere then?");
gifRegs.stat.P1Q = true;
}
@ -99,51 +83,59 @@ void gsPath1Interrupt()
}
}
#endif
extern bool SIGNAL_IMR_Pending;
static __fi void clearFIFOstuff(bool full) {
if (full) CSRreg.FIFO = CSR_FIFO_FULL;
else CSRreg.FIFO = CSR_FIFO_EMPTY;
}
__fi void gsInterrupt()
void incGifChAddr(u32 qwc) {
if (gifch.chcr.STR) {
gifch.madr += qwc * 16;
gifch.qwc -= qwc;
hwDmacSrcTadrInc(gifch);
}
else DevCon.Error("incGifAddr() Error!");
}
__fi void gifInterrupt()
{
GIF_LOG("gsInterrupt caught!");
GIF_LOG("gifInterrupt caught!");
if (dmacRegs.ctrl.MFD == MFD_GIF) // GIF MFIFO
{
if (dmacRegs.ctrl.MFD == MFD_GIF) { // GIF MFIFO
//Console.WriteLn("GIF MFIFO");
gifMFIFOInterrupt();
return;
}
if(SIGNAL_IMR_Pending == true)
{
#if USE_OLD_GIF == 1 // d
if(SIGNAL_IMR_Pending == true) {
//DevCon.Warning("Path 3 Paused");
CPU_INT(DMAC_GIF, 128);
return;
}
if(GSTransferStatus.PTH3 == PENDINGSTOP_MODE)
{
if(GSTransferStatus.PTH3 == PENDINGSTOP_MODE) {
GSTransferStatus.PTH3 = STOPPED_MODE;
if(gifRegs.stat.APATH == GIF_APATH3)
{
if(gifRegs.stat.APATH == GIF_APATH3) {
gifRegs.stat.APATH = GIF_APATH_IDLE;
gifRegs.stat.OPH = false;
if(gifRegs.stat.P1Q) gsPath1Interrupt();
}
}
if (!(gifch.chcr.STR))
{
//Console.WriteLn("Eh? why are you still interrupting! chcr %x, qwc %x, done = %x", gifch.chcr._u32, gifch.qwc, done);
#else
if (gifUnit.gsSIGNAL.queued) {
//DevCon.WriteLn("Path 3 Paused");
CPU_INT(DMAC_GIF, 128);
return;
}
#endif
if (!(gifch.chcr.STR)) return;
if ((gifch.qwc > 0) || (!gspath3done))
{
if (!dmacRegs.ctrl.DMAE)
{
if ((gifch.qwc > 0) || (!gspath3done)) {
if (!dmacRegs.ctrl.DMAE) {
Console.Warning("gs dma masked, re-scheduling...");
// re-raise the int shortly in the future
CPU_INT( DMAC_GIF, 64 );
@ -154,16 +146,11 @@ __fi void gsInterrupt()
return;
}
gspath3done = false;
gscycles = 0;
gifch.chcr.STR = false;
////
/*gifRegs.stat.OPH = false;
GSTransferStatus.PTH3 = STOPPED_MODE;
gifRegs.stat.APATH = GIF_APATH_IDLE;*/
////
gifRegs.stat.clear_flags(GIF_STAT_FQC);
gscycles = 0;
gspath3done = false;
gifch.chcr.STR = false;
clearFIFOstuff(false);
hwDmacIrq(DMAC_GIF);
DMA_LOG("GIF DMA End");
@ -171,15 +158,16 @@ __fi void gsInterrupt()
static u32 WRITERING_DMA(u32 *pMem, u32 qwc)
{
#if USE_OLD_GIF == 1 // d
GetMTGS().PrepDataPacket(GIF_PATH_3, qwc);
uint size = GIFPath_CopyTag(GIF_PATH_3, (u128*)pMem, qwc );
uint size = GIFPath_CopyTag(GIF_PATH_3, (u128*)pMem, qwc);
GetMTGS().SendDataPacket();
return size;
}
static u32 WRITERING_DMA(tDMA_TAG *pMem, u32 qwc)
{
return WRITERING_DMA((u32*)pMem, qwc);
#else
uint size = gifUnit.TransferGSPacketData(GIF_TRANS_DMA, (u8*)pMem, qwc*16) / 16;
incGifChAddr(size);
return size;
#endif
}
int _GIFchain()
@ -187,23 +175,23 @@ int _GIFchain()
tDMA_TAG *pMem;
pMem = dmaGetAddr(gifch.madr, false);
if (pMem == NULL)
{
if (pMem == NULL) {
#if USE_OLD_GIF == 1 // d
// reset path3, fixes dark cloud 2
GIFPath_Clear( GIF_PATH_3 );
#endif
//must increment madr and clear qwc, else it loops
gifch.madr += gifch.qwc * 16;
gifch.qwc = 0;
Console.Warning( "Hackfix - NULL GIFchain" );
Console.Warning("Hackfix - NULL GIFchain");
return -1;
}
return WRITERING_DMA(pMem, gifch.qwc);
return WRITERING_DMA((u32*)pMem, gifch.qwc);
}
static __fi void GIFchain()
{
static __fi void GIFchain() {
// qwc check now done outside this function
// Voodoocycles
// >> 2 so Drakan and Tekken 5 don't mess up in some PATH3 transfer. Cycles to interrupt were getting huge..
@ -212,13 +200,11 @@ static __fi void GIFchain()
static __fi bool checkTieBit(tDMA_TAG* &ptag)
{
if (gifch.chcr.TIE && ptag->IRQ)
{
if (gifch.chcr.TIE && ptag->IRQ) {
GIF_LOG("dmaIrq Set");
gspath3done = true;
return true;
}
return false;
}
@ -246,27 +232,24 @@ static __fi tDMA_TAG* ReadTag2()
return ptag;
}
bool CheckPaths(int Channel)
bool CheckPaths(EE_EventType Channel)
{
if((GSTransferStatus.PTH3 == IMAGE_MODE && gifRegs.mode.IMT) /*|| GSTransferStatus.PTH3 == WAITING_MODE*/)
{
if((gifRegs.stat.P1Q == true || gifRegs.stat.P2Q == true) || (gifRegs.stat.APATH > GIF_APATH_IDLE && gifRegs.stat.APATH < GIF_APATH3))
{
if((vif1.cmd & 0x7f) != 0x51 || gifRegs.stat.P1Q == true)
{
//DevCon.Warning("GIF Stall 1 P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd);
gifRegs.stat.IP3 = true;
if(gifRegs.stat.P1Q) gsPath1Interrupt();
CPU_INT(DMAC_GIF, 16);
return false;
#if USE_OLD_GIF == 1 // d
if((GSTransferStatus.PTH3 == IMAGE_MODE && gifRegs.mode.IMT) /*|| GSTransferStatus.PTH3 == WAITING_MODE*/) {
if((gifRegs.stat.P1Q == true || gifRegs.stat.P2Q == true) || (gifRegs.stat.APATH > GIF_APATH_IDLE && gifRegs.stat.APATH < GIF_APATH3)) {
if((vif1.cmd & 0x7f) != 0x51 || gifRegs.stat.P1Q == true) {
//DevCon.Warning("GIF Stall 1 P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd);
gifRegs.stat.IP3 = true;
if(gifRegs.stat.P1Q) gsPath1Interrupt();
CPU_INT(DMAC_GIF, 16);
return false;
}
}
}
else if(GSTransferStatus.PTH3 == STOPPED_MODE)
{
//This should cover both scenarios, as DIRECTHL doesn't gain priority when image mode is running (PENDINGIMAGE_MODE == fininshed).
if((gifRegs.stat.P1Q == true || gifRegs.stat.P2Q == true) || (gifRegs.stat.APATH > GIF_APATH_IDLE && gifRegs.stat.APATH < GIF_APATH3) || vif1Regs.stat.VGW == true)
{
else if(GSTransferStatus.PTH3 == STOPPED_MODE) {
//This should cover both scenarios, as DIRECTHL doesn't gain priority when image mode is running (PENDINGIMAGE_MODE == finished).
if((gifRegs.stat.P1Q == true || gifRegs.stat.P2Q == true)
|| (gifRegs.stat.APATH > GIF_APATH_IDLE && gifRegs.stat.APATH < GIF_APATH3) || vif1Regs.stat.VGW == true) {
//DevCon.Warning("GIF Stall 2 P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd);
gifRegs.stat.IP3 = true;
if(gifRegs.stat.P1Q) gsPath1Interrupt();
@ -274,41 +257,40 @@ bool CheckPaths(int Channel)
return false;
}
}
gifRegs.stat.IP3 = false;
#else
// Can't do Path 3, so try dma again later...
if(!gifUnit.CanDoPath3()) {
CPU_INT(Channel, 128);
return false;
}
#endif
return true;
}
void GIFdma()
{
tDMA_TAG *ptag;
gscycles = prevcycles;
if (gifRegs.ctrl.PSE) // temporarily stop
{
if (gifRegs.ctrl.PSE) { // temporarily stop
Console.WriteLn("Gif dma temp paused? (non MFIFO GIF)");
CPU_INT(DMAC_GIF, 16);
return;
}
if ((dmacRegs.ctrl.STD == STD_GIF) && (prevcycles != 0))
{
if ((dmacRegs.ctrl.STD == STD_GIF) && (prevcycles != 0)) {
//Console.WriteLn("GS Stall Control Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3, gifch.madr, psHu32(DMAC_STADR));
if ((gifch.madr + (gifch.qwc * 16)) > dmacRegs.stadr.ADDR)
{
if ((gifch.madr + (gifch.qwc * 16)) > dmacRegs.stadr.ADDR) {
CPU_INT(DMAC_GIF, 4);
gscycles = 0;
return;
}
prevcycles = 0;
gifch.qwc = 0;
}
if ((gifch.chcr.MOD == CHAIN_MODE) && (!gspath3done) && gifch.qwc == 0) // Chain Mode
{
ptag = ReadTag();
@ -340,10 +322,9 @@ void GIFdma()
clearFIFOstuff(true);
gifRegs.stat.FQC = min((u16)0x10, gifch.qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3]
if (vif1Regs.mskpath3 || gifRegs.mode.M3R)
{
if (GSTransferStatus.PTH3 == STOPPED_MODE)
{
#if USE_OLD_GIF == 1 // ...
if (vif1Regs.mskpath3 || gifRegs.mode.M3R) {
if (GSTransferStatus.PTH3 == STOPPED_MODE) {
MSKPATH3_LOG("Path3 Paused by VIF QWC %x", gifch.qwc);
if(gifch.qwc == 0) CPU_INT(DMAC_GIF, 4);
@ -351,18 +332,20 @@ void GIFdma()
return;
}
}
#endif
// Transfer Dn_QWC from Dn_MADR to GIF
if (gifch.qwc > 0) // Normal Mode
{
gifRegs.stat.FQC = min((u16)0x10, gifch.qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3]
#if USE_OLD_GIF == 1 // ...
gifRegs.stat.set_flags(GIF_STAT_P3Q);
if(CheckPaths(DMAC_GIF) == false)
return;
if(CheckPaths(DMAC_GIF) == false) return;
gifRegs.stat.clear_flags(GIF_STAT_P3Q);
#else
if(CheckPaths(DMAC_GIF) == false) return;
#endif
GIFchain(); //Transfers the data set by the switch
CPU_INT(DMAC_GIF, gscycles);
@ -389,34 +372,27 @@ void dmaGIF()
}
clearFIFOstuff(true);
if(gifch.chcr.MOD == CHAIN_MODE && gifch.qwc > 0)
{
if(gifch.chcr.MOD == CHAIN_MODE && gifch.qwc > 0) {
//DevCon.Warning(L"GIF QWC on Chain " + gifch.chcr.desc());
if ((gifch.chcr.tag().ID == TAG_REFE) || (gifch.chcr.tag().ID == TAG_END))
{
if ((gifch.chcr.tag().ID == TAG_REFE) || (gifch.chcr.tag().ID == TAG_END)) {
gspath3done = true;
}
}
gsInterrupt();
gifInterrupt();
}
static u16 QWCinGIFMFIFO(u32 DrainADDR)
{
u32 ret;
GIF_LOG("GIF MFIFO Requesting %x QWC from the MFIFO Base %x, SPR MADR %x Drain %x", gifch.qwc, dmacRegs.rbor.ADDR, spr0ch.madr, DrainADDR);
//Calculate what we have in the fifo.
if(DrainADDR <= spr0ch.madr)
{
if(DrainADDR <= spr0ch.madr) {
//Drain is below the tadr, calculate the difference between them
ret = (spr0ch.madr - DrainADDR) >> 4;
}
else
{
else {
u32 limit = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16;
//Drain is higher than SPR so it has looped round,
//calculate from base to the SPR tag addr and what is left in the top of the ring
@ -427,14 +403,13 @@ static u16 QWCinGIFMFIFO(u32 DrainADDR)
return ret;
}
// called from only one location, so forceinline it:
static __fi bool mfifoGIFrbTransfer()
{
u16 mfifoqwc = min(QWCinGIFMFIFO(gifch.madr), gifch.qwc);
if (mfifoqwc == 0) return true; //Lets skip all this, we don't have the data
#if USE_OLD_GIF == 1 // d
u32 *src;
if(mfifoqwc == 0) return true; //Lets skip all this, we don't have the data
GetMTGS().PrepDataPacket(GIF_PATH_3, mfifoqwc);
// TODO (minor optimization): The new GIFpath parser can do rather efficient wrapping of
@ -442,8 +417,8 @@ static __fi bool mfifoGIFrbTransfer()
// memory similarly to how it wraps VU1 memory on PATH1.
GIF_LOG("MFIFO QWC to Transfer %x", mfifoqwc);
/* Check if the transfer should wrap around the ring buffer */
if ( (gifch.madr + (mfifoqwc * 16)) > (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16))
{
if ( (gifch.madr + (mfifoqwc * 16)) > (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) {
DevCon.Warning("0mfifoGIFrbTransfer() - Wrap [%d]", mfifoqwc);
uint s1 = ((dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16) - gifch.madr) >> 4;
uint s2 = (mfifoqwc - s1);
GIF_LOG("Split transfer doing %x QWC of %x Total QWC", s1, mfifoqwc);
@ -455,8 +430,7 @@ static __fi bool mfifoGIFrbTransfer()
if (src == NULL) return false;
uint copied = GIFPath_CopyTag(GIF_PATH_3, (u128*)src, s1);
if (copied == s1) // but only copy second if first didn't abort prematurely for some reason.
{
if (copied == s1) { // but only copy second if first didn't abort prematurely for some reason.
GIF_LOG("Transferring last %x QWC", s2);
src = (u32*)PSM(dmacRegs.rbor.ADDR);
gifch.madr = dmacRegs.rbor.ADDR;
@ -466,9 +440,10 @@ static __fi bool mfifoGIFrbTransfer()
mfifoqwc = copied;
GIF_LOG("Copied %x QWC, %x QWC Left", mfifoqwc, gifch.qwc);
DevCon.Warning("1mfifoGIFrbTransfer() - Wrap [%d]", mfifoqwc);
}
else
{
else {
//DevCon.WriteLn("mfifoGIFrbTransfer() - Norm[%d]", mfifoqwc*16);
GIF_LOG("Direct MFIFO transfer doing %x Total QWC", mfifoqwc);
/* it doesn't, so just transfer 'qwc*16' words from 'gifch.madr' to GS */
@ -480,20 +455,45 @@ static __fi bool mfifoGIFrbTransfer()
}
GetMTGS().SendDataPacket();
//gifqwc -= mfifoqwc;
mfifocycles += (mfifoqwc) * 2; /* guessing */
mfifocycles += (mfifoqwc) * 2; // guessing
#else
if(!gifUnit.CanDoPath3()) {
DevCon.Warning("mfifoGIFrbTransfer() - Can't do path3");
return true; // Skip if can't do path3
}
bool needWrap = (gifch.madr + (mfifoqwc * 16)) > (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16);
uint s1 = ((dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16) - gifch.madr) >> 4;
uint s2 = mfifoqwc - s1;
uint s3 = needWrap ? s1 : mfifoqwc;
gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK);
u8* src = (u8*)PSM(gifch.madr);
if (src == NULL) return false;
u32 t1 = gifUnit.TransferGSPacketData(GIF_TRANS_DMA, src, s3*16) / 16; // First part
incGifChAddr(t1);
mfifocycles += t1 * 2; // guessing
if (needWrap && t1) { // Need to do second transfer to wrap around
GUNIT_WARN("mfifoGIFrbTransfer() - Wrap");
src = (u8*)PSM(dmacRegs.rbor.ADDR);
gifch.madr = dmacRegs.rbor.ADDR;
if (src == NULL) return false;
u32 t2 = gifUnit.TransferGSPacketData(GIF_TRANS_DMA, src, s2*16) / 16; // Second part
incGifChAddr(t2);
mfifocycles += t2 * 2; // guessing
}
#endif
return true;
}
// called from only one location, so forceinline it:
static __fi bool mfifoGIFchain()
{
/* Is QWC = 0? if so there is nothing to transfer */
if (gifch.qwc == 0) return true;
if (gifch.madr >= dmacRegs.rbor.ADDR &&
gifch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16))
gifch.madr <=(dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16))
{
bool ret = true;
// if(gifch.madr == (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) DevCon.Warning("Edge GIF");
@ -505,57 +505,47 @@ static __fi bool mfifoGIFchain()
gifch.tadr = dmacRegs.rbor.ADDR + (gifch.tadr & dmacRegs.rbsr.RMSK); //Check this too, tadr can suffer the same issue.
return ret;
}
else
{
else {
int mfifoqwc;
GIF_LOG("Non-MFIFO Location transfer doing %x Total QWC", gifch.qwc);
tDMA_TAG *pMem = dmaGetAddr(gifch.madr, false);
if (pMem == NULL) return false;
mfifoqwc = WRITERING_DMA(pMem, gifch.qwc);
mfifoqwc = WRITERING_DMA((u32*)pMem, gifch.qwc);
mfifocycles += (mfifoqwc) * 2; /* guessing */
}
return true;
}
static u32 qwctag(u32 mask)
{
static u32 qwctag(u32 mask) {
return (dmacRegs.rbor.ADDR + (mask & dmacRegs.rbsr.RMSK));
}
void mfifoGIFtransfer(int qwc)
{
tDMA_TAG *ptag;
mfifocycles = 0;
gifmfifoirq = false;
if(qwc > 0 )
{
if ((gifstate & GIF_STATE_EMPTY))
{
if (qwc > 0 ) {
if ((gifstate & GIF_STATE_EMPTY)) {
if(gifch.chcr.STR == true && !(cpuRegs.interrupt & (1<<DMAC_MFIFO_GIF)))
CPU_INT(DMAC_MFIFO_GIF, 4);
gifstate &= ~GIF_STATE_EMPTY;
}
gifRegs.stat.FQC = 16;
return;
}
if (gifRegs.ctrl.PSE) // temporarily stop
{
if (gifRegs.ctrl.PSE) { // temporarily stop
Console.WriteLn("Gif dma temp paused?");
CPU_INT(DMAC_MFIFO_GIF, 16);
return;
}
if (gifch.qwc == 0)
{
if (gifch.qwc == 0) {
gifch.tadr = qwctag(gifch.tadr);
ptag = dmaGetAddr(gifch.tadr, false);
@ -572,8 +562,7 @@ void mfifoGIFtransfer(int qwc)
if(gspath3done == true) gifstate = GIF_STATE_DONE;
else gifstate = GIF_STATE_READY;
if ((gifch.chcr.TIE) && (ptag->IRQ))
{
if ((gifch.chcr.TIE) && (ptag->IRQ)) {
SPR_LOG("dmaIrq Set");
gifstate = GIF_STATE_DONE;
gifmfifoirq = true;
@ -581,6 +570,7 @@ void mfifoGIFtransfer(int qwc)
if (QWCinGIFMFIFO(gifch.tadr) == 0) gifstate |= GIF_STATE_EMPTY;
}
#if USE_OLD_GIF == 1 // ...
if (vif1Regs.mskpath3 || gifRegs.mode.M3R)
{
if ((gifch.qwc == 0) && (gifstate & GIF_STATE_DONE)) gifstate |= GIF_STATE_STALL;
@ -594,8 +584,9 @@ void mfifoGIFtransfer(int qwc)
return;
}
}
if (!mfifoGIFchain())
{
#endif
if (!mfifoGIFchain()) {
Console.WriteLn("GIF dmaChain error size=%d, madr=%lx, tadr=%lx", gifch.qwc, gifch.madr, gifch.tadr);
gifstate = GIF_STATE_STALL;
}
@ -611,38 +602,42 @@ void gifMFIFOInterrupt()
GIF_LOG("gifMFIFOInterrupt");
mfifocycles = 0;
if (dmacRegs.ctrl.MFD != MFD_GIF)
{
if (dmacRegs.ctrl.MFD != MFD_GIF) {
DevCon.Warning("Not in GIF MFIFO mode! Stopping GIF MFIFO");
return;
}
if(SIGNAL_IMR_Pending == true)
{
#if USE_OLD_GIF == 1 // d
if(SIGNAL_IMR_Pending == true) {
//DevCon.Warning("Path 3 Paused");
CPU_INT(DMAC_MFIFO_GIF, 128);
return;
}
if(GSTransferStatus.PTH3 == PENDINGSTOP_MODE)
{
if(GSTransferStatus.PTH3 == PENDINGSTOP_MODE) {
GSTransferStatus.PTH3 = STOPPED_MODE;
if(gifRegs.stat.APATH == GIF_APATH3)
{
if(gifRegs.stat.APATH == GIF_APATH3) {
gifRegs.stat.APATH = GIF_APATH_IDLE;
gifRegs.stat.OPH = false;
if(gifRegs.stat.P1Q) gsPath1Interrupt();
}
}
#else
if (gifUnit.gsSIGNAL.queued) {
//DevCon.WriteLn("Path 3 Paused");
CPU_INT(DMAC_MFIFO_GIF, 128);
return;
}
#endif
if((gifstate & GIF_STATE_EMPTY))
{
if((gifstate & GIF_STATE_EMPTY)) {
FireMFIFOEmpty();
if(!(gifstate & GIF_STATE_STALL)) return;
}
if(CheckPaths(11) == false) return;
#if USE_OLD_GIF == 1 // d
#endif
if(CheckPaths(DMAC_MFIFO_GIF) == false) return;
if (!(gifch.chcr.STR))
{
@ -665,8 +660,7 @@ void gifMFIFOInterrupt()
}
#ifdef PCSX2_DEVBUILD
if ((gifstate & GIF_STATE_READY) || (gifch.qwc > 0))
{
if ((gifstate & GIF_STATE_READY) || (gifch.qwc > 0)) {
Console.Error("gifMFIFO Panic > Shouldn't go here!");
return;
}
@ -677,9 +671,13 @@ void gifMFIFOInterrupt()
gspath3done = false;
gscycles = 0;
#if USE_OLD_GIF == 1 // d
gifRegs.stat.clear_flags(GIF_STAT_APATH3 | GIF_STAT_P3Q | GIF_STAT_FQC); // APATH, P3Q, FQC = 0
vif1Regs.stat.VGW = false;
#else
gifRegs.stat.clear_flags(GIF_STAT_FQC); // FQC = 0
#endif
gifch.chcr.STR = false;
gifstate = GIF_STATE_READY;
hwDmacIrq(DMAC_GIF);
@ -687,7 +685,7 @@ void gifMFIFOInterrupt()
clearFIFOstuff(false);
}
void SaveStateBase::gifFreeze()
void SaveStateBase::gifDmaFreeze()
{
FreezeTag( "GIFdma" );
@ -697,21 +695,21 @@ void SaveStateBase::gifFreeze()
Freeze( gscycles );
// Note: mfifocycles is not a persistent var, so no need to save it here.
#if USE_OLD_GIF == 1 // d
int bufsize = Path1WritePos - Path1ReadPos;
Freeze(bufsize);
if (IsSaving())
{
if(!IsSaving()) {
// We can just load the queued Path1 data into the front of the buffer, and
// reset the ReadPos and WritePos accordingly.
FreezeMem(Path1Buffer, bufsize);
Path1ReadPos = 0;
Path1WritePos = bufsize;
}
else
{
else {
// Only want to save the actual Path1 data between readpos and writepos. The
// rest of the buffer is just unused-ness!
FreezeMem(&Path1Buffer[Path1ReadPos], bufsize);
}
#endif
}

View File

@ -13,19 +13,57 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIF_H__
#define __GIF_H__
#pragma once
enum gifstate_t
{
#define USE_OLD_GIF 0
#define COPY_GS_PACKET_TO_MTGS 0
//#define GUNIT_LOG DevCon.WriteLn
#define GUNIT_LOG(...) do {} while(0)
//#define GUNIT_WARN DevCon.WriteLn
#define GUNIT_WARN(...) do {} while(0)
enum GIF_PATH {
GIF_PATH_1 = 0,
GIF_PATH_2,
GIF_PATH_3,
};
// Lower byte contains path minus 1
enum GIF_TRANSFER_TYPE {
GIF_TRANS_INVALID = 0x000, // Invalid
GIF_TRANS_XGKICK = 0x100, // Path 1
GIF_TRANS_DIRECT = 0x201, // Path 2
GIF_TRANS_DIRECTHL = 0x301, // Path 2
GIF_TRANS_DMA = 0x402, // Path 3
GIF_TRANS_FIFO = 0x502 // Path 3
};
static const char Gif_TransferStr[6][32] = {
"Invalid Transfer Type",
"GIF_TRANS_XGKICK",
"GIF_TRANS_DIRECT",
"GIF_TRANS_DIRECTHL",
"GIF_TRANS_DMA",
"GIF_TRANS_FIFO"
};
enum GIF_PATH_STATE {
GIF_PATH_IDLE = 0, // Path is idle (hasn't started a GS packet)
GIF_PATH_PACKED = 1, // Path is on a PACKED gif tag
GIF_PATH_REGLIST = 2, // Path is on a REGLIST gif tag
GIF_PATH_IMAGE = 3 // Path is on a IMAGE gif tag
};
enum gifstate_t {
GIF_STATE_READY = 0,
GIF_STATE_STALL = 1,
GIF_STATE_DONE = 2,
GIF_STATE_DONE = 2,
GIF_STATE_EMPTY = 0x10
};
enum GSTransferModes //0 = Image Mode (DirectHL), 1 = transferring, 2 = Stopped at End of Packet
{
enum GSTransferModes { // 0 = Image Mode (DirectHL), 1 = transferring, 2 = Stopped at End of Packet
WAITING_MODE = 0,
IMAGE_MODE = 1,
TRANSFER_MODE = 2,
@ -50,9 +88,9 @@ union tGSTransferStatus {
void reset() { _u32 = 0; }
wxString desc() const { return wxsFormat(L"GSTransferStatus.PTH3: 0x%x", _u32); }
};
//GIF_STAT
enum gif_stat_flags
{
enum gif_stat_flags {
GIF_STAT_M3R = (1), // GIF_MODE Mask
GIF_STAT_M3P = (1<<1), // VIF PATH3 Mask
GIF_STAT_IMT = (1<<2), // Intermittent Transfer Mode
@ -69,16 +107,40 @@ enum gif_stat_flags
GIF_STAT_FQC = (31<<24) // QWC in GIF-FIFO
};
enum gif_mode_flags
{
enum gif_mode_flags {
GIF_MODE_M3R = (1),
GIF_MODE_IMT = (1<<2)
GIF_MODE_IMT = (1<<2)
};
enum GIF_FLG {
GIF_FLG_PACKED = 0,
GIF_FLG_REGLIST = 1,
GIF_FLG_IMAGE = 2,
GIF_FLG_IMAGE2 = 3
};
enum GIF_REG {
GIF_REG_PRIM = 0x00,
GIF_REG_RGBA = 0x01,
GIF_REG_STQ = 0x02,
GIF_REG_UV = 0x03,
GIF_REG_XYZF2 = 0x04,
GIF_REG_XYZ2 = 0x05,
GIF_REG_TEX0_1 = 0x06,
GIF_REG_TEX0_2 = 0x07,
GIF_REG_CLAMP_1 = 0x08,
GIF_REG_CLAMP_2 = 0x09,
GIF_REG_FOG = 0x0a,
GIF_REG_INVALID = 0x0b,
GIF_REG_XYZF3 = 0x0c,
GIF_REG_XYZ3 = 0x0d,
GIF_REG_A_D = 0x0e,
GIF_REG_NOP = 0x0f,
};
union tGIF_CTRL
{
struct
{
struct {
u32 RST : 1;
u32 reserved1 : 2;
u32 PSE : 1;
@ -88,6 +150,7 @@ union tGIF_CTRL
tGIF_CTRL(u32 val) { _u32 = val; }
void write(u32 val) { _u32 = val; }
bool test(u32 flags) { return !!(_u32 & flags); }
void set_flags(u32 flags) { _u32 |= flags; }
void clear_flags(u32 flags) { _u32 &= ~flags; }
@ -97,8 +160,7 @@ union tGIF_CTRL
union tGIF_MODE
{
struct
{
struct {
u32 M3R : 1;
u32 reserved1 : 1;
u32 IMT : 1;
@ -116,8 +178,7 @@ union tGIF_MODE
wxString desc() { return wxsFormat(L"Mode: 0x%x", _u32); }
};
enum gif_paths
{
enum gif_paths {
GIF_APATH_IDLE = 0,
GIF_APATH1,
GIF_APATH2,
@ -126,28 +187,28 @@ enum gif_paths
union tGIF_STAT
{
struct
{
u32 M3R : 1;
u32 M3P : 1;
u32 IMT : 1;
u32 PSE : 1;
u32 reserved1 : 1;
u32 IP3 : 1;
u32 P3Q : 1;
u32 P2Q : 1;
u32 P1Q : 1;
u32 OPH : 1;
u32 APATH : 2;
u32 DIR : 1;
u32 reserved2 : 11;
u32 FQC : 5;
u32 reserved3 : 3;
struct {
u32 M3R : 1; // GIF_MODE Mask
u32 M3P : 1; // VIF PATH3 Mask
u32 IMT : 1; // Intermittent Transfer Mode
u32 PSE : 1; // Temporary Transfer Stop
u32 reserved1 : 1; // ...
u32 IP3 : 1; // Interrupted PATH3
u32 P3Q : 1; // PATH3 request Queued
u32 P2Q : 1; // PATH2 request Queued
u32 P1Q : 1; // PATH1 request Queued
u32 OPH : 1; // Output Path (Outputting Data)
u32 APATH : 2; // Data Transfer Path (In progress)
u32 DIR : 1; // Transfer Direction
u32 reserved2 : 11; // ...
u32 FQC : 5; // QWC in GIF-FIFO
u32 reserved3 : 3; // ...
};
u32 _u32;
tGIF_STAT(u32 val) { _u32 = val; }
void write(u32 val) { _u32 = val; }
bool test(u32 flags) { return !!(_u32 & flags); }
void set_flags(u32 flags) { _u32 |= flags; }
void clear_flags(u32 flags) { _u32 &= ~flags; }
@ -157,8 +218,7 @@ union tGIF_STAT
union tGIF_TAG0
{
struct
{
struct {
u32 NLOOP : 15;
u32 EOP : 1;
u32 TAG : 16;
@ -176,8 +236,7 @@ union tGIF_TAG0
union tGIF_TAG1
{
struct
{
struct {
u32 TAG : 14;
u32 PRE : 1;
u32 PRIM : 11;
@ -197,8 +256,7 @@ union tGIF_TAG1
union tGIF_CNT
{
struct
{
struct {
u32 LOOPCNT : 15;
u32 reserved1 : 1;
u32 REGCNT : 4;
@ -219,8 +277,7 @@ union tGIF_CNT
union tGIF_P3CNT
{
struct
{
struct {
u32 P3CNT : 15;
u32 reserved1 : 17;
};
@ -234,8 +291,7 @@ union tGIF_P3CNT
union tGIF_P3TAG
{
struct
{
struct {
u32 LOOPCNT : 15;
u32 EOP : 1;
u32 reserved1 : 16;
@ -279,18 +335,28 @@ struct GIFregisters
static GIFregisters& gifRegs = (GIFregisters&)eeHw[0x3000];
extern tGSTransferStatus GSTransferStatus;
extern void gsInterrupt();
extern void gifInterrupt();
extern int _GIFchain();
extern void GIFdma();
extern void dmaGIF();
extern void mfifoGIFtransfer(int qwc);
extern void gifMFIFOInterrupt();
#if USE_OLD_GIF == 1 // d
extern u8 schedulepath3msk;
extern tGSTransferStatus GSTransferStatus;
extern bool CheckPath2GIF(EE_EventType channel);
//Just some temporary bits to store Path1 transfers if another is in progress.
extern void gsPath1Interrupt();
extern __aligned16 u8 Path1Buffer[0x1000000];
extern u32 Path1WritePos;
extern u32 Path1ReadPos;
extern void GIFPath_Initialize();
extern int GIFPath_CopyTag(GIF_PATH pathidx, const u128* pMem, u32 size);
extern int GIFPath_ParseTagQuick(GIF_PATH pathidx, const u8* pMem, u32 size);
extern void GIFPath_Reset();
extern void GIFPath_Clear( GIF_PATH pathidx );
#endif

136
pcsx2/Gif_Unit.cpp Normal file
View File

@ -0,0 +1,136 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Common.h"
#include "GS.h"
#include "Gif_Unit.h"
#include "Vif_Dma.h"
Gif_Unit gifUnit;
// Returns true on stalling SIGNAL
bool Gif_HandlerAD(u8* pMem) {
u32 reg = pMem[8];
u32* data = (u32*)pMem;
if (reg == 0x50) vif1.BITBLTBUF._u64 = *(u64*)pMem;
elif (reg == 0x52) vif1.TRXREG._u64 = *(u64*)pMem;
elif (reg == 0x53) {
if ((pMem[0] & 3) == 1) { // local -> host
u8 bpp = 32;
switch(vif1.BITBLTBUF.SPSM & 7) {
case 0: bpp = 32; break;
case 1: bpp = 24; break;
case 2: bpp = 16; break;
case 3: bpp = 8; break;
default: // 4 is 4 bit but this is forbidden
Console.Error("Illegal format for GS upload: SPSM=0%02o", vif1.BITBLTBUF.SPSM);
break;
}
// 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;
}
}
elif (reg == 0x60) { // SIGNAL
if (CSRreg.SIGNAL) { // Time to ignore all subsequent drawing operations.
GUNIT_WARN(Color_Orange, "GIF Handler - Stalling SIGNAL");
if(!gifUnit.gsSIGNAL.queued) {
gifUnit.gsSIGNAL.queued = true;
gifUnit.gsSIGNAL.data[0] = data[0];
gifUnit.gsSIGNAL.data[1] = data[1];
return true; // Stalling SIGNAL
}
}
else {
GUNIT_WARN("GIF Handler - SIGNAL");
GSSIGLBLID.SIGID = (GSSIGLBLID.SIGID&~data[1])|(data[0]&data[1]);
if (!(GSIMR&0x100)) gsIrq();
CSRreg.SIGNAL = true;
}
}
elif (reg == 0x61) { // FINISH
GUNIT_WARN("GIF Handler - FINISH");
CSRreg.FINISH = true;
}
elif (reg == 0x62) { // LABEL
GUNIT_WARN("GIF Handler - LABEL");
GSSIGLBLID.LBLID = (GSSIGLBLID.LBLID&~data[1])|(data[0]&data[1]);
}
elif (reg >= 0x63 && reg != 0x7f) {
DevCon.Warning("GIF Handler - Write to unknown register! [reg=%x]", reg);
}
return false;
}
void Gif_FinishIRQ() {
if (CSRreg.FINISH && !(GSIMR&0x200)) {
gsIrq();
}
}
void Gif_AddCompletedGSPacket(GS_Packet& gsPack, GIF_PATH path) {
//DevCon.WriteLn("Adding Completed Gif Packet [size=%x]", gsPack.size);
if (COPY_GS_PACKET_TO_MTGS) {
GetMTGS().PrepDataPacket(path, gsPack.size/16);
MemCopy_WrappedDest((u128*)&gifUnit.gifPath[path].buffer[gsPack.offset], RingBuffer.m_Ring,
GetMTGS().m_packet_writepos, RingBufferSize, gsPack.size/16);
GetMTGS().SendDataPacket();
}
else {
AtomicExchangeAdd(gifUnit.gifPath[path].readAmount, gsPack.size);
GetMTGS().SendSimpleGSPacket(GS_RINGTYPE_GSPACKET, gsPack.offset, gsPack.size, path);
}
}
void Gif_AddBlankGSPacket(u32 size, GIF_PATH path) {
//DevCon.WriteLn("Adding Blank Gif Packet [size=%x]", size);
AtomicExchangeAdd(gifUnit.gifPath[path].readAmount, size);
GetMTGS().SendSimpleGSPacket(GS_RINGTYPE_GSPACKET, ~0u, size, path);
}
void Gif_MTGS_Wait() {
GetMTGS().WaitGS();
}
void Gif_Execute() {
gifUnit.Execute();
}
void SaveStateBase::gifPathFreeze(u32 path) {
Gif_Path& gifPath = gifUnit.gifPath[path];
pxAssertDev(gifPath.readAmount==0, "Gif Path readAmount should be 0!");
if (IsSaving()) { // Move all the buffered data to the start of buffer
gifPath.RealignPacket(); // May add readAmount which we need to clear on load
}
u8* bufferPtr = gifPath.buffer; // Backup current buffer ptr
Freeze(gifPath);
FreezeMem(bufferPtr, gifPath.curSize);
gifPath.buffer = bufferPtr;
if (!IsSaving()) gifPath.readAmount = 0;
}
void SaveStateBase::gifFreeze() {
Gif_MTGS_Wait();
FreezeTag("Gif Unit");
Freeze(gifUnit.stat);
Freeze(gifUnit.gsSIGNAL);
Freeze(gifUnit.lastTranType);
gifPathFreeze(GIF_PATH_1);
gifPathFreeze(GIF_PATH_2);
gifPathFreeze(GIF_PATH_3);
}

451
pcsx2/Gif_Unit.h Normal file
View File

@ -0,0 +1,451 @@
#pragma once
#include "System/SysThreads.h"
extern void Gif_FinishIRQ();
extern bool Gif_HandlerAD(u8* pMem);
struct Gif_Tag {
struct HW_Gif_Tag {
u16 NLOOP : 15;
u16 EOP : 1;
u16 _dummy0 : 16;
u32 _dummy1 : 14;
u32 PRE : 1;
u32 PRIM : 11;
u32 FLG : 2;
u32 NREG : 4;
u32 REGS[2];
} tag;
u32 nLoop; // NLOOP left to process
u32 nRegs; // NREG (1~16)
u32 nRegIdx; // Current nReg Index (packed mode processing)
u32 len; // Packet Length in Bytes (not including tag)
u32 cycles; // Time needed to process packet data in ee-cycles
u8 regs[16]; // Regs
bool hasAD; // Has an A+D Write
bool isValid; // Tag is valid
Gif_Tag() { Reset(); }
Gif_Tag(u8* pMem, bool analyze = false) {
setTag (pMem, analyze);
}
void Reset() { memzero(*this); }
u8 curReg() { return regs[nRegIdx&0xf]; }
void packedStep() {
if (nLoop > 0) {
nRegIdx++;
if (nRegIdx >= nRegs) {
nRegIdx = 0;
nLoop--;
}
}
}
void setTag(u8* pMem, bool analyze = false) {
tag = *(HW_Gif_Tag*)pMem;
nLoop = tag.NLOOP;
hasAD = false;
nRegIdx = 0;
isValid = 1;
switch(tag.FLG) {
case GIF_FLG_PACKED:
nRegs = ((tag.NREG-1)&0xf) + 1;
len = (nRegs * tag.NLOOP)* 16;
cycles = len << 1; // Packed Mode takes 2 ee-cycles
if (analyze) analyzeTag();
break;
case GIF_FLG_REGLIST:
nRegs = ((tag.NREG-1)&0xf) + 1;
len =((nRegs * tag.NLOOP + 1) >> 1) * 16;
cycles = len << 2; // Reg-list Mode takes 4 ee-cycles
break;
case GIF_FLG_IMAGE:
case GIF_FLG_IMAGE2:
nRegs = 0;
len = tag.NLOOP * 16;
cycles = len << 2; // Image Mode takes 4 ee-cycles
tag.FLG = GIF_FLG_IMAGE;
break;
jNO_DEFAULT;
}
}
void analyzeTag() {
hasAD = false;
u32 t = tag.REGS[0];
for(u32 i = 0; i < nRegs; i++) {
if (i == 8) t = tag.REGS[1];
regs[i] = t & 0xf;
hasAD |= (regs[i] == GIF_REG_A_D);
t >>= 4;
}
}
};
struct GS_Packet {
u32 offset; // Path buffer offset for start of packet
u32 size; // Full size of GS-Packet
s32 cycles; // EE Cycles taken to process this GS packet
bool done; // 0 = Incomplete, 1 = Complete
GS_Packet() { Reset(); }
void Reset() { memzero(*this); }
};
struct GS_SIGNAL {
u32 data[2];
bool queued;
void Reset() { memzero(*this); }
};
__fi void incTag(u32& offset, u32& size, u32 incAmount) {
size += incAmount;
offset += incAmount;
}
struct Gif_Path {
volatile s32 __aligned(4) readAmount; // Amount of data MTGS still needs to read
u8* buffer; // Path packet buffer
u32 buffSize; // Full size of buffer
u32 buffLimit; // Cut off limit to wrap around
u32 curSize; // Used buffer in bytes
u32 curOffset; // Offset of current gifTag
Gif_Tag gifTag; // Current GS Primitive tag
GS_Packet gsPack; // Current GS Packet info
GIF_PATH idx; // Gif Path Index
GIF_PATH_STATE state; // Path State
Gif_Path() {}
~Gif_Path() { _aligned_free(buffer); }
void Init(GIF_PATH _idx, u32 _buffSize, u32 _buffSafeZone) {
idx = _idx;
buffSize = _buffSize;
buffLimit = _buffSize - _buffSafeZone;
buffer = (u8*)_aligned_malloc(buffSize, 16);
Reset();
}
void Reset(bool softReset = false) {
state = GIF_PATH_IDLE;
if (softReset) {
GUNIT_WARN("Gif Path %d - Soft Reset", idx+1);
//gifTag.Reset();
//gsPack.Reset();
//curOffset = curSize;
return;
}
curSize = 0;
curOffset = 0;
readAmount = 0;
gifTag.Reset();
gsPack.Reset();
}
bool hasDataRemaining() { return curOffset < curSize; }
bool isDone() { return !hasDataRemaining() && state == GIF_PATH_IDLE; }
// Waits on the MTGS to process gs packets
void mtgsReadWait() {
//pxAssertDev(AtomicExchangeAdd(readAmount, 0) != 0, "Gif Path Buffer Overflow!");
DevCon.WriteLn(Color_Red, "Gif Path[%d] - MTGS Wait! [r=0x%x]",
idx+1, AtomicExchangeAdd(readAmount, 0));
extern void Gif_MTGS_Wait();
Gif_MTGS_Wait();
}
// Moves packet data to start of buffer
void RealignPacket() {
extern void Gif_AddBlankGSPacket(u32 size, GIF_PATH path);
GUNIT_LOG("Path Buffer: Realigning packet!");
s32 offset = curOffset - gsPack.size;
s32 sizeToAdd = curSize - offset;
s32 intersect = sizeToAdd - offset;
if (intersect < 0) intersect = 0;
for(;;) {
s32 frontFree = offset - AtomicExchangeAdd(readAmount, 0);
if (frontFree >= sizeToAdd - intersect) break;
mtgsReadWait();
}
if (offset < (s32)buffLimit) { // Needed for correct readAmount values
Gif_AddBlankGSPacket(buffLimit - offset, idx);
}
//DevCon.WriteLn("Realign Packet [%d]", curSize - offset);
if (intersect) memmove(buffer, &buffer[offset], curSize - offset);
else memcpy_fast(buffer, &buffer[offset], curSize - offset);
curSize -= offset;
curOffset = gsPack.size;
gsPack.offset = 0;
}
void CopyGSPacketData(u8* pMem, u32 size, bool aligned = false) {
if (curSize + size > buffSize) { // Move gsPack to front of buffer
DevCon.Warning("CopyGSPacketData: Realigning packet!");
RealignPacket();
}
for(;;) {
s32 offset = curOffset - gsPack.size;
s32 readPos = offset - AtomicExchangeAdd(readAmount, 0);
if (readPos >= 0) break; // MTGS is reading in back of curOffset
if ((s32)buffLimit + readPos > (s32)curSize + (s32)size) break; // Enough free front space
mtgsReadWait(); // Let MTGS run to free up buffer space
}
pxAssertDev(curSize+size<=buffSize, "Gif Path Buffer Overflow!");
if (aligned) memcpy_qwc (&buffer[curSize], pMem, size/16);
else memcpy_fast(&buffer[curSize], pMem, size);
curSize += size;
}
// If completed a GS packet (with EOP) then returned GS_Packet.done = 1
GS_Packet ExecuteGSPacket() {
for(;;) {
if (!gifTag.isValid) { // Need new Gif Tag
// We don't have enough data for a Gif Tag
if (curOffset + 16 > curSize) {
GUNIT_LOG("Path Buffer: Not enough data for gif tag! [%d]", curSize-curOffset);
return gsPack;
}
// Move packet to start of buffer
if (curOffset > buffLimit) {
RealignPacket();
}
gifTag.setTag(&buffer[curOffset], 1);
state = (GIF_PATH_STATE)(gifTag.tag.FLG + 1);
// We don't have enough data for a complete GS packet
if (curOffset + 16 + gifTag.len > curSize) {
gifTag.isValid = false; // So next time we test again
return gsPack;
}
incTag(curOffset, gsPack.size, 16); // Tag Size
gsPack.cycles += 2 + gifTag.cycles; // Tag + Len ee-cycles
}
if (gifTag.hasAD) { // Only can be true if GIF_FLG_PACKED
bool dblSIGNAL = false;
while(gifTag.nLoop && !dblSIGNAL) {
if (gifTag.curReg() == GIF_REG_A_D) {
dblSIGNAL = Gif_HandlerAD(&buffer[curOffset]);
}
incTag(curOffset, gsPack.size, 16); // 1 QWC
gifTag.packedStep();
}
if (dblSIGNAL && !(gifTag.tag.EOP && !gifTag.nLoop)) return gsPack; // Exit Early
}
else incTag(curOffset, gsPack.size, gifTag.len); // Data length
// Reload gif tag next loop
gifTag.isValid = false;
if (gifTag.tag.EOP) {
GS_Packet t = gsPack;
t.done = 1;
state = GIF_PATH_IDLE;
gsPack.Reset();
gsPack.offset = curOffset;
return t; // Complete GS packet
}
}
}
};
struct Gif_Unit {
Gif_Path gifPath[3];
GS_SIGNAL gsSIGNAL; // Stalling Signal
tGIF_STAT& stat;
GIF_TRANSFER_TYPE lastTranType; // Last Transfer Type
Gif_Unit() : stat(gifRegs.stat) {
gifPath[0].Init(GIF_PATH_1, _1mb*8, _16kb + _1kb);
gifPath[1].Init(GIF_PATH_2, _1mb*8, _1mb + _1kb);
gifPath[2].Init(GIF_PATH_3, _1mb*9, _1mb + _1kb);
}
// Enable softReset when resetting during game emulation
void Reset(bool softReset = false) {
GUNIT_WARN(Color_Red, "Gif Unit Reset!!! [soft=%d]", softReset);
ResetRegs();
gsSIGNAL.Reset();
gifPath[0].Reset(softReset);
gifPath[1].Reset(softReset);
gifPath[2].Reset(softReset);
if(!softReset) {
lastTranType = GIF_TRANS_INVALID;
}
}
// Resets Gif HW Regs
void ResetRegs() {
gifRegs.stat.reset();
gifRegs.ctrl.reset();
gifRegs.mode.reset();
}
// Adds a finished GS Packet to the MTGS ring buffer
__fi void AddCompletedGSPacket(GS_Packet& gsPack, GIF_PATH path) {
extern void Gif_AddCompletedGSPacket(GS_Packet& gsPack, GIF_PATH path);
Gif_AddCompletedGSPacket(gsPack, path);
}
// Returns GS Packet Size in bytes
u32 GetGSPacketSize(GIF_PATH pathIdx, u8* pMem, u32 offset = 0) {
u32 memMask = pathIdx ? 0xffffffffu : 0x3fffu;
u32 size = 0;
for(;;) {
Gif_Tag gifTag(&pMem[offset & memMask]);
incTag(offset, size, 16 + gifTag.len); // Tag + Data length
if (pathIdx == GIF_PATH_1 && size >= 0x4000) {
Console.Warning("Gif Unit - GS packet size exceeded VU memory size!");
return 0; // Bios does this... (Fixed if you delay vu1's xgkick by 103 vu cycles)
}
if (gifTag.tag.EOP) {
return size;
}
}
}
// Specify the transfer type you are initiating
// The return value is the amount of data (in bytes) that was processed
// If transfer cannot take place at this moment the return value is 0
u32 TransferGSPacketData(GIF_TRANSFER_TYPE tranType, u8* pMem, u32 size, bool aligned=false) {
GIF_LOG("%s - [path=%d][size=%d]", Gif_TransferStr[(tranType>>8)&0xf], (tranType&3)+1, size);
if (size == 0) { GUNIT_WARN("Gif Unit - Size == 0"); return 0; }
if(!CanDoGif()) { GUNIT_WARN("Gif Unit - PSE Set or Dir = GS to EE"); }
pxAssertDev((stat.APATH==0) || checkPaths(1,1,1), "Gif Unit - APATH wasn't cleared?");
lastTranType = tranType; // Used for Vif FlushA hack
if (tranType == GIF_TRANS_FIFO) {
if(!CanDoPath3()) DevCon.Warning("Gif Unit - Path 3 FIFO transfer while !CanDoPath3()");
}
if (tranType == GIF_TRANS_DMA) {
if(!CanDoPath3()) { if (!Path3Masked()) stat.P3Q = 1; return 0; } // DMA Stall
}
if (tranType == GIF_TRANS_XGKICK) {
if(!CanDoPath1()) { stat.P1Q = 1; } // We always buffer path1 packets
}
if (tranType == GIF_TRANS_DIRECT) {
if(!CanDoPath2()) { stat.P2Q = 1; return 0; } // Direct Stall
}
if (tranType == GIF_TRANS_DIRECTHL) {
if(!CanDoPath2HL()) { stat.P2Q = 1; return 0; } // DirectHL Stall
}
gifPath[tranType&3].CopyGSPacketData(pMem, size, aligned);
Execute();
return size;
}
// Checks path activity for the given paths
// Returns an int with a bit enabled if the corresponding
// path is not finished (needs more data/processing for an EOP)
__fi int checkPaths(bool p1, bool p2, bool p3, bool checkQ=false) {
int ret = 0;
ret |= (p1 && !gifPath[GIF_PATH_1].isDone()) << 0;
ret |= (p2 && !gifPath[GIF_PATH_2].isDone()) << 1;
ret |= (p3 && !gifPath[GIF_PATH_3].isDone()) << 2;
return ret | (checkQ ? checkQueued(p1,p2,p3) : 0);
}
__fi int checkQueued(bool p1, bool p2, bool p3) {
int ret = 0;
ret |= (p1 && stat.P1Q) << 0;
ret |= (p2 && stat.P2Q) << 1;
ret |= (p3 && stat.P3Q) << 2;
return ret;
}
// Processes gif packets and performs path arbitration
// according to path priority...
void Execute() {
if (!CanDoGif()) { DevCon.Error("Gif Unit - Signal or PSE Set or Dir = GS to EE"); return; }
bool didPath3 = false;
stat.OPH = 1;
for(;;) {
if (stat.APATH) { // Some Transfer is happening
GS_Packet gsPack = gifPath[stat.APATH-1].ExecuteGSPacket();
if(!gsPack.done) {
if (stat.APATH == 3 && CanDoP3Slice() && !gsSIGNAL.queued) {
if(!didPath3 && checkPaths(1,1,0)) { // Path3 slicing
didPath3 = true;
stat.APATH = 0;
stat.IP3 = 1;
GUNIT_LOG(Color_Magenta, "Gif Unit - Path 3 slicing arbitration");
if (gsPack.size > 16) { // Packet had other tags which we already processed
Gif_Path& p3 = gifPath[GIF_PATH_3];
u32 subOffset = p3.gifTag.isValid ? 16 : 0; // if isValid, image-primitive not finished
gsPack.size -= subOffset; // Remove the image-tag (should be last thing read)
AddCompletedGSPacket(gsPack, GIF_PATH_3); // Consider current packet complete
p3.gsPack.Reset(); // Reset gs packet info
p3.curOffset -= subOffset; // Start the next GS packet at the image-tag
p3.gsPack.offset = p3.curOffset; // Set to image-tag
p3.gifTag.isValid = false; // Reload tag next ExecuteGSPacket()
pxAssert((s32)p3.curOffset >= 0);
pxAssert(p3.state == GIF_PATH_IMAGE);
GUNIT_LOG(Color_Magenta, "Gif Unit - Sending path 3 sliced gs packet!");
}
continue;
}
}
//DevCon.WriteLn("Incomplete GS Packet for path %d", stat.APATH);
break; // Not finished with GS packet
}
//DevCon.WriteLn("Adding GS Packet for path %d", stat.APATH);
AddCompletedGSPacket(gsPack, (GIF_PATH)(stat.APATH-1));
}
if (!gsSIGNAL.queued && checkPaths(1,0,0,0)) { stat.APATH = 1; stat.P1Q = 0; }
elif (!gsSIGNAL.queued && checkPaths(0,1,0,0)) { stat.APATH = 2; stat.P2Q = 0; }
elif (!gsSIGNAL.queued && checkPaths(0,0,1,0) && !Path3Masked())
{ stat.APATH = 3; stat.P3Q = 0; stat.IP3 = 0; }
else { stat.APATH = 0; stat.OPH = 0; break; }
}
Gif_FinishIRQ(); // hmm
//DevCon.WriteLn("APATH = %d [%d,%d,%d]", stat.APATH, !!checkPaths(1,0,0,0),!!checkPaths(0,1,0,0),!!checkPaths(0,0,1,0));
}
// XGkick
bool CanDoPath1() { return (stat.APATH == 0 || stat.APATH == 1
|| (stat.APATH == 3 && CanDoP3Slice()))
&& (CanDoGif() == 1); }
// Direct
bool CanDoPath2() { return (stat.APATH == 0 || stat.APATH == 2
|| (stat.APATH == 3 && CanDoP3Slice()))
&& (CanDoGif() == 1); }
// DirectHL
bool CanDoPath2HL() { return (stat.APATH == 0 || stat.APATH == 2)
&& (CanDoGif() == 1); }
// Gif DMA
bool CanDoPath3() { return((stat.APATH == 0 && !Path3Masked())
|| stat.APATH == 3)
&& (CanDoGif() == 1); }
bool CanDoP3Slice() { return stat.IMT == 1 && gifPath[GIF_PATH_3].state == GIF_PATH_IMAGE; }
bool CanDoGif() { return stat.PSE == 0 && stat.DIR == 0 && gsSIGNAL.queued == 0; }
bool Path3Masked() { return stat.M3R || stat.M3P; }
void PrintInfo(bool printP1=1, bool printP2=1, bool printP3=1) {
u32 a = checkPaths(1,1,1), b = checkQueued(1,1,1);
GUNIT_LOG("Gif Unit - LastTransfer = %s, Paths = [%d,%d,%d], Queued = [%d,%d,%d]",
Gif_TransferStr[(lastTranType>>8)&0xf],
!!(a&1),!!(a&2),!!(a&4),!!(b&1),!!(b&2),!!(b&4));
GUNIT_LOG("Gif Unit - [APATH = %d][Signal = %d][PSE = %d][DIR = %d]",
stat.APATH, gsSIGNAL.queued, stat.PSE, stat.DIR);
GUNIT_LOG("Gif Unit - [CanDoGif = %d][CanDoPath3 = %d][CanDoP3Slice = %d]",
CanDoGif(), CanDoPath3(), CanDoP3Slice());
if (printP1) PrintPathInfo(GIF_PATH_1);
if (printP2) PrintPathInfo(GIF_PATH_2);
if (printP3) PrintPathInfo(GIF_PATH_3);
}
void PrintPathInfo(GIF_PATH path) {
GUNIT_LOG("Gif Path %d - [hasData = %d][state = %d]", path,
gifPath[path].hasDataRemaining(), gifPath[path].state);
}
};
extern Gif_Unit gifUnit;

View File

@ -19,6 +19,8 @@
#include "Hardware.h"
#include "newVif.h"
#include "IPU/IPUdma.h"
#include "Gif.h"
#include "Gif_Unit.h"
using namespace R5900;
@ -73,6 +75,7 @@ void hwReset()
sprInit();
gsReset();
gifUnit.Reset();
ipuReset();
vif0Reset();
vif1Reset();
@ -145,14 +148,14 @@ void FireMFIFOEmpty()
hwDmacIrq(DMAC_MFIFO_EMPTY);
if (dmacRegs.ctrl.MFD == MFD_VIF1) vif1Regs.stat.FQC = 0;
else if (dmacRegs.ctrl.MFD == MFD_GIF) gifRegs.stat.FQC = 0;
if (dmacRegs.ctrl.MFD == MFD_GIF) gifRegs.stat.FQC = 0;
}
// Write 'size' bytes to memory address 'addr' from 'data'.
__ri bool hwMFIFOWrite(u32 addr, const u128* data, uint qwc)
{
// all FIFO addresses should always be QWC-aligned.
pxAssume((dmacRegs.rbor.ADDR & 15) == 0);
pxAssume((addr & 15) == 0);
pxAssert((dmacRegs.rbor.ADDR & 15) == 0);
pxAssert((addr & 15) == 0);
if(qwc > ((dmacRegs.rbsr.RMSK + 16) >> 4)) DevCon.Warning("MFIFO Write bigger than MFIFO! QWC=%x FifoSize=%x", qwc, ((dmacRegs.rbsr.RMSK + 16) >> 4));
// DMAC Address resolution: FIFO can be placed anywhere in the *physical* memory map

View File

@ -17,6 +17,8 @@
#include "PrecompiledHeader.h"
#include "Common.h"
#include "Hardware.h"
#include "Gif.h"
#include "Gif_Unit.h"
#include "ps2/HwInternal.h"
#include "ps2/eeHwTraceLog.inl"
@ -88,16 +90,17 @@ void __fastcall _hwWrite32( u32 mem, u32 value )
{
icase(GIF_CTRL)
{
psHu32(mem) = value & 0x8;
if (value & 0x1)
gsGIFReset();
if (value & 8)
gifRegs.stat.PSE = true;
else
gifRegs.stat.PSE = false;
// Not exactly sure what RST needs to do
gifRegs.ctrl.write(value & 9);
if (gifRegs.ctrl.RST) {
#if USE_OLD_GIF == 1 // d
gifUnit.ResetRegs(); // hmm?
#else
GUNIT_LOG("GIF CTRL - Reset");
gifUnit.Reset(true); // hmm?
#endif
}
gifRegs.stat.PSE = gifRegs.ctrl.PSE;
return;
}
@ -110,7 +113,6 @@ void __fastcall _hwWrite32( u32 mem, u32 value )
const u32 bitmask = GIF_MODE_M3R | GIF_MODE_IMT;
psHu32(GIF_STAT) &= ~bitmask;
psHu32(GIF_STAT) |= (u32)value & bitmask;
return;
}
}

View File

@ -106,7 +106,7 @@ int IPU_Fifo_Input::read(void *value)
int IPU_Fifo_Output::write(const u32 *value, uint size)
{
pxAssumeMsg(size>0, "Invalid size==0 when calling IPU_Fifo_Output::write");
pxAssertMsg(size>0, "Invalid size==0 when calling IPU_Fifo_Output::write");
uint origsize = size;
/*do {*/
@ -131,7 +131,7 @@ int IPU_Fifo_Output::write(const u32 *value, uint size)
void IPU_Fifo_Output::read(void *value, uint size)
{
pxAssume(ipuRegs.ctrl.OFC >= size);
pxAssert(ipuRegs.ctrl.OFC >= size);
ipuRegs.ctrl.OFC -= size;
// Zeroing the read data is not needed, since the ringbuffer design will never read back

View File

@ -73,31 +73,6 @@ static __fi void ipuDmacSrcChain()
}
}
static __fi bool WaitGSPaths()
{
if(CHECK_IPUWAITHACK)
{
if(GSTransferStatus.PTH3 < STOPPED_MODE && GSTransferStatus.PTH3 != IDLE_MODE)
{
//GIF_LOG("Flushing gif chcr %x tadr %x madr %x qwc %x", gif->chcr._u32, gif->tadr, gif->madr, gif->qwc);
//DevCon.WriteLn("Waiting for GIF");
return false;
}
if(GSTransferStatus.PTH2 != STOPPED_MODE)
{
//DevCon.WriteLn("Waiting for VIF");
return false;
}
if(GSTransferStatus.PTH1 != STOPPED_MODE)
{
//DevCon.WriteLn("Waiting for VU");
return false;
}
}
return true;
}
static __fi int IPU1chain() {
int totalqwc = 0;
@ -131,21 +106,6 @@ static __fi int IPU1chain() {
return totalqwc;
}
//static __fi bool WaitGSPaths()
//{
// //Wait for all GS paths to be clear
// if (GSTransferStatus._u32 != 0x2a)
// {
// if(GSTransferStatus.PTH3 != STOPPED_MODE && vif1Regs.mskpath3) return true;
// IPU_LOG("Waiting for GS transfers to finish %x", GSTransferStatus._u32);
// IPU_INT_TO(4);
// return false;
// }
// return true;
//}
int IPU1dma()
{
int ipu1cycles = 0;

View File

@ -808,7 +808,7 @@ __fi bool mpeg2sliceIDEC()
case 2:
{
pxAssume(decoder.ipu0_data > 0);
pxAssert(decoder.ipu0_data > 0);
uint read = ipu_fifo.out.write((u32*)decoder.GetIpuDataPtr(), decoder.ipu0_data);
decoder.AdvanceIpuDataBy(read);
@ -1113,7 +1113,7 @@ __fi bool mpeg2_slice()
case 3:
{
pxAssume(decoder.ipu0_data > 0);
pxAssert(decoder.ipu0_data > 0);
uint read = ipu_fifo.out.write((u32*)decoder.GetIpuDataPtr(), decoder.ipu0_data);
decoder.AdvanceIpuDataBy(read);

View File

@ -174,8 +174,8 @@ struct decoder_t {
void AdvanceIpuDataBy(uint amt)
{
pxAssumeMsg(ipu0_data>=amt, "IPU FIFO Overflow on advance!" );
ipu0_idx += amt;
pxAssertMsg(ipu0_data>=amt, "IPU FIFO Overflow on advance!" );
ipu0_idx += amt;
ipu0_data -= amt;
}
};

View File

@ -50,7 +50,7 @@ void iopMemoryReserve::Reset()
{
_parent::Reset();
pxAssume( iopMem );
pxAssert( iopMem );
if (!psxMemWLUT)
{

View File

@ -20,6 +20,7 @@
#include <wx/datetime.h>
#include "GS.h"
#include "Gif_Unit.h"
#include "Elfheader.h"
#include "SamplProf.h"
@ -114,7 +115,12 @@ void SysMtgsThread::ResetGS()
SendSimplePacket( GS_RINGTYPE_FRAMESKIP, 0, 0, 0 );
SetEvent();
#if USE_OLD_GIF == 1 // d
GIFPath_Reset();
#else
//DevCon.WriteLn("ResetGS()");
//gifUnit.Reset();
#endif
}
struct RingCmdPacket_Vsync
@ -328,6 +334,7 @@ void SysMtgsThread::ExecuteTaskInThread()
switch( tag.command )
{
#if USE_OLD_GIF == 1 || COPY_GS_PACKET_TO_MTGS == 1 // d
case GS_RINGTYPE_P1:
{
uint datapos = (m_ReadPos+1) & RingBufferMask;
@ -402,6 +409,15 @@ void SysMtgsThread::ExecuteTaskInThread()
ringposinc += qsize;
}
break;
#endif
case GS_RINGTYPE_GSPACKET: {
Gif_Path& path = gifUnit.gifPath[tag.data[2]];
u32 offset = tag.data[0];
u32 size = tag.data[1];
if (offset != ~0u) GSgifTransfer((u32*)&path.buffer[offset], size/16);
AtomicExchangeSub(path.readAmount, size);
break;
}
default:
{
@ -590,7 +606,7 @@ void SysMtgsThread::WaitGS()
// For use in loops that wait on the GS thread to do certain things.
void SysMtgsThread::SetEvent()
{
if( !m_RingBufferIsBusy )
if(!m_RingBufferIsBusy)
m_sem_event.Post();
m_CopyDataTally = 0;
@ -770,6 +786,18 @@ void SysMtgsThread::SendSimplePacket( MTGS_RingCommand type, int data0, int data
_FinishSimplePacket();
}
void SysMtgsThread::SendSimpleGSPacket(MTGS_RingCommand type, u32 offset, u32 size, GIF_PATH path)
{
SendSimplePacket(type, (int)offset, (int)size, (int)path);
if(!EmuConfig.GS.SynchronousMTGS) {
if(!m_RingBufferIsBusy) {
m_CopyDataTally += size / 16;
if (m_CopyDataTally > 0x2000) SetEvent();
}
}
}
void SysMtgsThread::SendPointerPacket( MTGS_RingCommand type, u32 data0, void* data1 )
{
//ScopedLock locker( m_PacketLocker );

View File

@ -837,7 +837,7 @@ static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::MainRam
//
int mmap_GetRamPageInfo( u32 paddr )
{
pxAssume( eeMem );
pxAssert( eeMem );
paddr &= ~0xfff;
@ -854,7 +854,7 @@ int mmap_GetRamPageInfo( u32 paddr )
// paddr - physically mapped PS2 address
void mmap_MarkCountedRamPage( u32 paddr )
{
pxAssume( eeMem );
pxAssert( eeMem );
paddr &= ~0xfff;
@ -883,7 +883,7 @@ void mmap_MarkCountedRamPage( u32 paddr )
// from code residing in this page will use manual protection.
static __fi void mmap_ClearCpuBlock( uint offset )
{
pxAssume( eeMem );
pxAssert( eeMem );
int rampage = offset >> 12;
@ -899,7 +899,7 @@ static __fi void mmap_ClearCpuBlock( uint offset )
void mmap_PageFaultHandler::OnPageFaultEvent( const PageFaultInfo& info, bool& handled )
{
pxAssume( eeMem );
pxAssert( eeMem );
// get bad virtual address
uptr offset = info.addr - (uptr)eeMem->Main;

View File

@ -227,7 +227,7 @@ static void CALLBACK GS_gifTransferLegacy( const u32* src, u32 data )
if (src128 == RingBuffer.m_Ring)
{
pxAssume( (data+path1size) <= 0x400 );
pxAssert( (data+path1size) <= 0x400 );
memcpy_qwc( &path1queue[path1size], src128, data );
path1size += data;
}
@ -951,7 +951,7 @@ SysCorePlugins::~SysCorePlugins() throw()
void SysCorePlugins::Load( PluginsEnum_t pid, const wxString& srcfile )
{
ScopedLock lock( m_mtx_PluginStatus );
pxAssume( (uint)pid < PluginId_Count );
pxAssert( (uint)pid < PluginId_Count );
Console.Indent().WriteLn( L"Binding %s\t: %s ", tbl_PluginInfo[pid].GetShortname().c_str(), srcfile.c_str() );
m_info[pid] = new PluginStatus_t( pid, srcfile );
}
@ -1017,7 +1017,7 @@ void SysCorePlugins::Load( const wxString (&folders)[PluginId_Count] )
void SysCorePlugins::Unload(PluginsEnum_t pid)
{
ScopedLock lock( m_mtx_PluginStatus );
pxAssume( (uint)pid < PluginId_Count );
pxAssert( (uint)pid < PluginId_Count );
m_info[pid].Delete();
}
@ -1119,7 +1119,7 @@ bool SysCorePlugins::OpenPlugin_Mcd()
void SysCorePlugins::Open( PluginsEnum_t pid )
{
pxAssume( (uint)pid < PluginId_Count );
pxAssert( (uint)pid < PluginId_Count );
if( IsOpen(pid) ) return;
Console.Indent().WriteLn( "Opening %s", tbl_PluginInfo[pid].shortname );
@ -1240,7 +1240,7 @@ void SysCorePlugins::ClosePlugin_Mcd()
void SysCorePlugins::Close( PluginsEnum_t pid )
{
pxAssume( (uint)pid < PluginId_Count );
pxAssert( (uint)pid < PluginId_Count );
if( !IsOpen(pid) ) return;
@ -1653,21 +1653,21 @@ bool SysCorePlugins::AreAnyInitialized() const
bool SysCorePlugins::IsOpen( PluginsEnum_t pid ) const
{
pxAssume( (uint)pid < PluginId_Count );
pxAssert( (uint)pid < PluginId_Count );
ScopedLock lock( m_mtx_PluginStatus );
return m_info[pid] && m_info[pid]->IsInitialized && m_info[pid]->IsOpened;
}
bool SysCorePlugins::IsInitialized( PluginsEnum_t pid ) const
{
pxAssume( (uint)pid < PluginId_Count );
pxAssert( (uint)pid < PluginId_Count );
ScopedLock lock( m_mtx_PluginStatus );
return m_info[pid] && m_info[pid]->IsInitialized;
}
bool SysCorePlugins::IsLoaded( PluginsEnum_t pid ) const
{
pxAssume( (uint)pid < PluginId_Count );
pxAssert( (uint)pid < PluginId_Count );
return !!m_info[pid];
}
@ -1732,13 +1732,13 @@ bool SysCorePlugins::NeedsClose() const
const wxString SysCorePlugins::GetName( PluginsEnum_t pid ) const
{
ScopedLock lock( m_mtx_PluginStatus );
pxAssume( (uint)pid < PluginId_Count );
pxAssert( (uint)pid < PluginId_Count );
return m_info[pid] ? m_info[pid]->Name : (wxString)_("Unloaded Plugin");
}
const wxString SysCorePlugins::GetVersion( PluginsEnum_t pid ) const
{
ScopedLock lock( m_mtx_PluginStatus );
pxAssume( (uint)pid < PluginId_Count );
pxAssert( (uint)pid < PluginId_Count );
return m_info[pid] ? m_info[pid]->Version : L"0.0";
}

View File

@ -278,10 +278,13 @@ static __fi void _cpuTestInterrupts()
that depends on the cycle timings */
TESTINT(DMAC_VIF1, vif1Interrupt);
TESTINT(DMAC_GIF, gsInterrupt);
TESTINT(DMAC_GIF, gifInterrupt);
TESTINT(DMAC_SIF0, EEsif0Interrupt);
TESTINT(DMAC_SIF1, EEsif1Interrupt);
//extern void Gif_Execute();
//TESTINT(DMAC_GIF_UNIT, Gif_Execute);
// Profile-guided Optimization (sorta)
// The following ints are rarely called. Encasing them in a conditional
// as follows helps speed up most games.
@ -488,7 +491,7 @@ __fi void cpuTestHwInts() {
__fi void CPU_INT( EE_EventType n, s32 ecycle)
{
if( n != 2 && cpuRegs.interrupt & (1<<n) ){ //2 is Gif, and every path 3 masking game triggers this :/
if( n != 2 && cpuRegs.interrupt & (1<<n) ){ // 2 is Gif, and every path 3 masking game triggers this :/
DevCon.Warning( "***** EE > Twice-thrown int on IRQ %d", n );
}

View File

@ -404,7 +404,9 @@ enum EE_EventType
// We're setting error conditions through hwDmacIrq, so these correspond to the conditions above.
DMAC_STALL_SIS = 13, // SIS
DMAC_MFIFO_EMPTY = 14, // MEIS
DMAC_BUS_ERROR = 15 // BEIS
DMAC_BUS_ERROR = 15, // BEIS
DMAC_GIF_UNIT
};
extern void CPU_INT( EE_EventType n, s32 ecycle );

View File

@ -81,7 +81,7 @@ void SaveStateBase::Init( SafeArray<u8>* memblock )
void SaveStateBase::PrepBlock( int size )
{
pxAssumeDev( m_memory, "Savestate memory/buffer pointer is null!" );
pxAssertDev( m_memory, "Savestate memory/buffer pointer is null!" );
const int end = m_idx+size;
if( IsSaving() )
@ -208,6 +208,7 @@ SaveStateBase& SaveStateBase::FreezeInternals()
ipuFreeze();
ipuDmaFreeze();
gifFreeze();
gifDmaFreeze();
sprFreeze();
// Fifth Block - iop-related systems
@ -283,7 +284,7 @@ void memSavingState::FreezeMem( void* data, int size )
void memSavingState::MakeRoomForData()
{
pxAssumeDev( m_memory, "Savestate memory/buffer pointer is null!" );
pxAssertDev( m_memory, "Savestate memory/buffer pointer is null!" );
m_memory->ChunkSize = ReallocThreshold;
m_memory->MakeRoomFor( m_idx + MemoryBaseAllocSize );

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 = (0x9A01 << 16) | 0x0000;
static const u32 g_SaveVersion = (0x9A02 << 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. :)
@ -202,8 +202,12 @@ protected:
#endif
void sifFreeze();
void ipuFreeze();
void ipuDmaFreeze();
void ipuDmaFreeze();
void gifFreeze();
void gifDmaFreeze();
void gifPathFreeze(u32 path); // called by gifFreeze()
void gifPathFreeze(); // called by gsFreeze()
void sprFreeze();
void sioFreeze();
@ -212,8 +216,6 @@ protected:
void psxRcntFreeze();
void sio2Freeze();
void gifPathFreeze(); // called by gsFreeze
void deci2Freeze();
};

View File

@ -276,7 +276,7 @@ void SIO_CommandWrite(u8 value,int way) {
info.McdSizeInSectors = cmd.mcdSizeInSectors;
SysPlugins.McdGetSizeInfo( port, slot, info );
pxAssumeDev( cmd.mcdSizeInSectors >= mc_sizeinfo_8mb.mcdSizeInSectors,
pxAssertDev( cmd.mcdSizeInSectors >= mc_sizeinfo_8mb.mcdSizeInSectors,
"Mcd plugin returned an invalid memorycard size: Cards smaller than 8MB are not supported." );
cmd.sectorSize = info.SectorSize;

View File

@ -111,7 +111,7 @@ void SysThreadBase::Suspend( bool isBlocking )
break;
}
pxAssumeDev( m_ExecMode == ExecMode_Closing, "ExecMode should be nothing other than Closing..." );
pxAssertDev( m_ExecMode == ExecMode_Closing, "ExecMode should be nothing other than Closing..." );
m_sem_event.Post();
}
@ -140,7 +140,7 @@ void SysThreadBase::Pause()
if( m_ExecMode == ExecMode_Opened )
m_ExecMode = ExecMode_Pausing;
pxAssumeDev( m_ExecMode == ExecMode_Pausing, "ExecMode should be nothing other than Pausing..." );
pxAssertDev( m_ExecMode == ExecMode_Pausing, "ExecMode should be nothing other than Pausing..." );
m_sem_event.Post();
}

View File

@ -51,8 +51,8 @@ void vuMemoryReserve::Reset()
{
_parent::Reset();
pxAssume( VU0.Mem );
pxAssume( VU1.Mem );
pxAssert( VU0.Mem );
pxAssert( VU1.Mem );
memMapVUmicro();

View File

@ -17,6 +17,7 @@
#include "Common.h"
#include "VUops.h"
#include "GS.h"
#include "Gif_Unit.h"
#include <cmath>
@ -2024,12 +2025,26 @@ static __ri void _vuXGKICK(VURegs * VU)
{
// flush all pipelines first (in the right order)
_vuFlushAll(VU);
#if USE_OLD_GIF == 1 // todo
u8* data = ((u8*)VU->Mem + ((VU->VI[_Is_].US[0]*16) & 0x3fff));
u32 size;
GetMTGS().PrepDataPacket( GIF_PATH_1, 0x400 );
size = GIFPath_CopyTag( GIF_PATH_1, (u128*)data, (0x400-(VU->VI[_Is_].US[0] & 0x3ff)) );
GetMTGS().SendDataPacket();
#else
u32 addr = (VU->VI[_Is_].US[0] & 0x3ff) * 16;
u32 diff = 0x4000 - addr;
u32 size = gifUnit.GetGSPacketSize(GIF_PATH_1, VU->Mem, addr);
if (size > diff) {
//DevCon.WriteLn(Color_Green, "VU1 Int: XGkick Wrap!");
gifUnit.gifPath[GIF_PATH_1].CopyGSPacketData( &VU->Mem[addr], diff,true);
gifUnit.TransferGSPacketData(GIF_TRANS_XGKICK, &VU->Mem[0],size-diff,true);
}
else {
gifUnit.TransferGSPacketData(GIF_TRANS_XGKICK, &VU->Mem[addr], size, true);
}
#endif
}
static __ri void _vuXTOP(VURegs * VU) {

View File

@ -23,7 +23,9 @@
__aligned16 vifStruct vif0, vif1;
#if USE_OLD_GIF == 1 // d
tGSTransferStatus GSTransferStatus((STOPPED_MODE<<8) | (STOPPED_MODE<<4) | STOPPED_MODE);
#endif
void vif0Reset()
{
@ -172,17 +174,21 @@ __fi void vif1FBRST(u32 value) {
vif1.done = true;
vif1ch.chcr.STR = false;
#if USE_OLD_GIF == 1 // ...
//DevCon.Warning("VIF FBRST Reset MSK = %x", vif1Regs.mskpath3);
if(vif1Regs.mskpath3 == 1 && GSTransferStatus.PTH3 == STOPPED_MODE && gifch.chcr.STR == true)
{
if(vif1Regs.mskpath3 == 1 && GSTransferStatus.PTH3 == STOPPED_MODE && gifch.chcr.STR == true) {
DevCon.Warning("VIF Path3 Resume on FBRST MSK = %x", vif1Regs.mskpath3);
gsInterrupt();
gifInterrupt();
vif1Regs.mskpath3 = false;
gifRegs.stat.M3P = 0;
}
vif1Regs.mskpath3 = false;
gifRegs.stat.M3P = 0;
gifRegs.stat.M3P = 0;
#else
GUNIT_WARN(Color_Red, "VIF FBRST Reset MSK = %x", vif1Regs.mskpath3);
vif1Regs.mskpath3 = false;
gifRegs.stat.M3P = 0;
#endif
vif1Regs.err.reset();
vif1.inprogress = 0;
vif1.cmd = 0;

View File

@ -227,4 +227,3 @@ extern void mfifoVIF1transfer(int qwc);
extern bool VIF0transfer(u32 *data, int size, bool TTE=0);
extern bool VIF1transfer(u32 *data, int size, bool TTE=0);
extern void vifMFIFOInterrupt();
extern bool CheckPath2GIF(EE_EventType channel);

View File

@ -18,6 +18,7 @@
#include "Vif_Dma.h"
#include "GS.h"
#include "Gif.h"
#include "Gif_Unit.h"
#include "VUmicro.h"
#include "newVif.h"
@ -46,13 +47,15 @@ __fi void vif1FLUSH()
//DevCon.Warning("VIF1 adding %x cycles", (VU1.cycle - _cycles) * BIAS);
g_vifCycles += (VU1.cycle - _cycles) * BIAS;
}
if(gifRegs.stat.P1Q && ((vif1.cmd & 0x7f) != 0x14) && ((vif1.cmd & 0x7f) != 0x17))
{
vif1.vifstalled = true;
#if USE_OLD_GIF == 1 // d
if ((gifRegs.stat.P1Q == true)
&& ((vif1.cmd & 0x7f) != 0x14) // cmd != MSCAL
&& ((vif1.cmd & 0x7f) != 0x17)) { // cmd != MSCNT
vif1.vifstalled = true;
vif1Regs.stat.VGW = true;
vif1.GifWaitState = 2;
}
#endif
}
void vif1TransferToMemory()
@ -250,6 +253,7 @@ __fi void vif1SetupTransfer()
}
}
#if USE_OLD_GIF == 1 // d
extern bool SIGNAL_IMR_Pending;
bool CheckPath2GIF(EE_EventType channel)
@ -330,33 +334,32 @@ bool CheckPath2GIF(EE_EventType channel)
return true;
}
#endif
__fi void vif1Interrupt()
{
VIF_LOG("vif1Interrupt: %8.8x", cpuRegs.cycle);
g_vifCycles = 0;
if (schedulepath3msk & 0x10)
{
#if USE_OLD_GIF == 1 // d
if (schedulepath3msk & 0x10) {
MSKPATH3_LOG("Scheduled Path3 Mask Firing");
Vif1MskPath3();
}
if(GSTransferStatus.PTH2 == PENDINGSTOP_MODE)
{
if (GSTransferStatus.PTH2 == PENDINGSTOP_MODE) {
GSTransferStatus.PTH2 = STOPPED_MODE;
if(gifRegs.stat.APATH == GIF_APATH2)
{
if(gifRegs.stat.DIR == 0)gifRegs.stat.OPH = false;
if(gifRegs.stat.APATH == GIF_APATH2) {
if(gifRegs.stat.DIR == 0) gifRegs.stat.OPH = false;
gifRegs.stat.APATH = GIF_APATH_IDLE;
if(gifRegs.stat.P1Q) gsPath1Interrupt();
}
}
#endif
//Some games (Fahrenheit being one) start vif first, let it loop through blankness while it sets MFIFO mode, so we need to check it here.
if (dmacRegs.ctrl.MFD == MFD_VIF1)
{
if (dmacRegs.ctrl.MFD == MFD_VIF1) {
//Console.WriteLn("VIFMFIFO\n");
// Test changed because the Final Fantasy 12 opening somehow has the tag in *Undefined* mode, which is not in the documentation that I saw.
if (vif1ch.chcr.MOD == NORMAL_MODE) Console.WriteLn("MFIFO mode is normal (which isn't normal here)! %x", vif1ch.chcr._u32);
@ -365,11 +368,19 @@ __fi void vif1Interrupt()
return;
}
//We need to check the direction, if it is downloading from the GS, we handle that separately (KH2 for testing)
if (vif1ch.chcr.DIR)
{
// We need to check the direction, if it is downloading
// from the GS then we handle that separately (KH2 for testing)
if (vif1ch.chcr.DIR) {
#if USE_OLD_GIF == 1 // ...
if (!CheckPath2GIF(DMAC_VIF1)) return;
#else
if(gifUnit.gsSIGNAL.queued && (vif1.cmd & 0x7e) == 0x50) { // Direct/DirectHL
GUNIT_WARN("Path 2 Paused (vif1ch.chcr.DIR)");
//CPU_INT(DMAC_VIF1, 128);
//return;
}
#endif
vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16);
//Simulated GS transfer time done, clear the flags
}

View File

@ -17,6 +17,7 @@
#include "Common.h"
#include "Vif.h"
#include "Gif.h"
#include "Gif_Unit.h"
#include "Vif_Dma.h"
u16 vifqwc = 0;
@ -261,47 +262,52 @@ void vifMFIFOInterrupt()
return;
}
if(GSTransferStatus.PTH2 == PENDINGSTOP_MODE)
{
#if USE_OLD_GIF == 1 // d
if (GSTransferStatus.PTH2 == PENDINGSTOP_MODE) {
GSTransferStatus.PTH2 = STOPPED_MODE;
if(gifRegs.stat.APATH == GIF_APATH2)
{
if(gifRegs.stat.APATH == GIF_APATH2) {
if(gifRegs.stat.DIR == 0)gifRegs.stat.OPH = false;
gifRegs.stat.APATH = GIF_APATH_IDLE;
if(gifRegs.stat.P1Q) gsPath1Interrupt();
}
}
if (schedulepath3msk & 0x10)
{
if (schedulepath3msk & 0x10) {
MSKPATH3_LOG("Scheduled Path3 Mask Firing on MFIFO VIF");
Vif1MskPath3();
}
#endif
if(vif1ch.chcr.DIR && CheckPath2GIF(DMAC_MFIFO_VIF) == false)
{
#if USE_OLD_GIF == 1 // ...
if(vif1ch.chcr.DIR && CheckPath2GIF(DMAC_MFIFO_VIF) == false) {
SPR_LOG("Waiting for PATH to be ready");
return;
}
//We need to check the direction, if it is downloading from the GS, we handle that seperately (KH2 for testing)
#else
if(vif1ch.chcr.DIR && gifUnit.gsSIGNAL.queued && (vif1.cmd & 0x7e) == 0x50) { // Direct/DirectHL
GUNIT_WARN("Waiting for PATH to be ready (vif1ch.chcr.DIR)");
//CPU_INT(DMAC_MFIFO_VIF, 128);
//return;
}
#endif
//Simulated GS transfer time done, clear the flags
// We need to check the direction, if it is downloading from the GS,
// we handle that separately (KH2 for testing)
// Simulated GS transfer time done, clear the flags
if (vif1.irq && vif1.tag.size == 0)
{
if (vif1.irq && vif1.tag.size == 0) {
SPR_LOG("VIF MFIFO Code Interrupt detected");
vif1Regs.stat.INT = true;
hwIntcIrq(INTC_VIF1);
--vif1.irq;
if (vif1Regs.stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS))
{
if (vif1Regs.stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) {
/*vif1Regs.stat.FQC = 0; // FQC=0
vif1ch.chcr.STR = false;*/
vif1Regs.stat.FQC = min((u16)0x10, vif1ch.qwc);
if((vif1ch.qwc > 0 || !vif1.done) && !(vif1.inprogress & 0x10))
{
if((vif1ch.qwc > 0 || !vif1.done) && !(vif1.inprogress & 0x10)) {
VIF_LOG("VIF1 MFIFO Stalled");
return;
}
@ -309,29 +315,22 @@ void vifMFIFOInterrupt()
}
//Mirroring change to VIF0
if (vif1.cmd)
{
if(vif1.done == true && vif1ch.qwc == 0) vif1Regs.stat.VPS = VPS_WAITING;
if (vif1.cmd) {
if (vif1.done == true && vif1ch.qwc == 0) vif1Regs.stat.VPS = VPS_WAITING;
}
else
{
else {
vif1Regs.stat.VPS = VPS_IDLE;
}
if(vif1.inprogress & 0x10)
{
if(vif1.inprogress & 0x10) {
FireMFIFOEmpty();
if(!(vif1.done && vif1ch.qwc == 0))return;
}
if (vif1.done == false || vif1ch.qwc)
{
switch(vif1.inprogress & 1)
{
if (vif1.done == false || vif1ch.qwc) {
switch(vif1.inprogress & 1) {
case 0: //Set up transfer
if (QWCinVIFMFIFO(vif1ch.tadr) == 0)
{
if (QWCinVIFMFIFO(vif1ch.tadr) == 0) {
vif1.inprogress |= 0x10;
CPU_INT(DMAC_MFIFO_VIF, 4 );
return;

View File

@ -17,14 +17,16 @@
#include "Common.h"
#include "GS.h"
#include "Gif.h"
#include "Gif_Unit.h"
#include "Vif_Dma.h"
#include "newVif.h"
#include "VUmicro.h"
#define vifOp(vifCodeName) _vifT int __fastcall vifCodeName(int pass, const u32 *data)
#define pass1 if (pass == 0)
#define pass2 if (pass == 1)
#define pass3 if (pass == 2)
#define pass1 if (pass == 0)
#define pass2 if (pass == 1)
#define pass3 if (pass == 2)
#define pass1or2 if (pass == 0 || pass == 1)
#define vif1Only() { if (!idx) return vifCode_Null<idx>(pass, (u32*)data); }
vifOp(vifCode_Null);
@ -80,34 +82,26 @@ static __fi void vuExecMicro(int idx, u32 addr) {
GetVifX.vifstalled = true;
}
#if USE_OLD_GIF == 1 // d
u8 schedulepath3msk = 0;
#endif
void Vif1MskPath3() {
#if USE_OLD_GIF == 1 // d
vif1Regs.mskpath3 = schedulepath3msk & 0x1;
GIF_LOG("VIF MSKPATH3 %x gif str %x path3 status %x", vif1Regs.mskpath3, gifch.chcr.STR, GSTransferStatus.PTH3);
gifRegs.stat.M3P = vif1Regs.mskpath3;
if (!vif1Regs.mskpath3)
{
if(!vif1Regs.mskpath3) {
MSKPATH3_LOG("Disabling Path3 Mask");
//if(GSTransferStatus.PTH3 > TRANSFER_MODE && gif->chcr.STR) GSTransferStatus.PTH3 = TRANSFER_MODE;
//DevCon.Warning("Mask off");
//if(GSTransferStatus.PTH3 >= PENDINGSTOP_MODE) GSTransferStatus.PTH3 = IDLE_MODE;
if(gifRegs.stat.P3Q)
{
if(gifRegs.stat.P3Q) {
MSKPATH3_LOG("Path3 Waiting to Transfer, triggering");
gsInterrupt();
gifInterrupt();
}
}
else
{
MSKPATH3_LOG("Path3 Mask Enabled");
}
// else if(!gif->chcr.STR && GSTransferStatus.PTH3 == IDLE_MODE) GSTransferStatus.PTH3 = STOPPED_MODE;//else DevCon.Warning("Mask on");
else { MSKPATH3_LOG("Path3 Mask Enabled"); }
schedulepath3msk = 0;
#endif
}
//------------------------------------------------------------------
@ -121,6 +115,7 @@ vifOp(vifCode_Base) {
return 0;
}
#if USE_OLD_GIF == 1 // d
extern bool SIGNAL_IMR_Pending;
static __aligned16 u32 partial_write[4];
static uint partial_count = 0;
@ -130,7 +125,7 @@ template<int idx> __fi int _vifCode_Direct(int pass, const u8* data, bool isDire
vif1Only();
int vifImm = (u16)vif1Regs.code;
vif1.tag.size = vifImm ? (vifImm*4) : (65536*4);
vif1.vifstalled = true;
vif1.vifstalled = true;
gifRegs.stat.P2Q = true;
if (gifRegs.stat.PSE) // temporarily stop
{
@ -160,7 +155,7 @@ template<int idx> __fi int _vifCode_Direct(int pass, const u8* data, bool isDire
//DevCon.Warning("Stall DIRECT/HL %x P3 %x APATH %x P1Q %x", vif1.cmd, GSTransferStatus.PTH3, gifRegs.stat.APATH, gifRegs.stat.P1Q);
vif1Regs.stat.VGW = true; // PATH3 is in image mode (DIRECTHL), or busy (BOTH no IMT)
vif1.GifWaitState = 0;
vif1.vifstalled = true;
vif1.vifstalled = true;
return 0;
}
}
@ -174,7 +169,7 @@ template<int idx> __fi int _vifCode_Direct(int pass, const u8* data, bool isDire
{
Console.WriteLn("Gif dma temp paused? VIF DIRECT");
vif1.GifWaitState = 3;
vif1.vifstalled = true;
vif1.vifstalled = true;
vif1Regs.stat.VGW = true;
return 0;
}
@ -248,6 +243,39 @@ template<int idx> __fi int _vifCode_Direct(int pass, const u8* data, bool isDire
}
return 0;
}
#else
template<int idx> __fi int _vifCode_Direct(int pass, const u8* data, bool isDirectHL) {
vif1Only();
pass1 {
int vifImm = (u16)vif1Regs.code;
vif1.tag.size = vifImm ? (vifImm*4) : (65536*4);
return 0;
}
pass2 {
const char* name = isDirectHL ? "DirectHL" : "Direct";
GIF_TRANSFER_TYPE tranType = isDirectHL ? GIF_TRANS_DIRECTHL : GIF_TRANS_DIRECT;
uint size = aMin(vif1.vifpacketsize, vif1.tag.size) * 4; // Get size in bytes
uint ret = gifUnit.TransferGSPacketData(tranType, (u8*)data, size);
vif1.tag.size -= ret/4; // Convert to u32's
vif1Regs.stat.VGW = false;
if (ret & 3) DevCon.Warning("Vif %s: Ret wasn't a multiple of 4!", name); // Shouldn't happen
if (size == 0) DevCon.Warning("Vif %s: No Data Transfer?", name); // Can this happen?
if (size != ret) { // Stall if gif didn't process all the data (path2 queued)
GUNIT_WARN("Vif %s: Stall! [size=%d][ret=%d]", name, size, ret);
//gifUnit.PrintInfo();
vif1.vifstalled = true;
vif1Regs.stat.VGW = true;
}
if (vif1.tag.size == 0) {
vif1.cmd = 0;
}
return ret / 4;
}
return 0;
}
#endif
vifOp(vifCode_Direct) {
pass3 { VifCodeLog("Direct"); }
@ -263,7 +291,21 @@ vifOp(vifCode_DirectHL) {
vifOp(vifCode_Flush) {
vif1Only();
vifStruct& vifX = GetVifX;
pass1 { vifFlush(idx); vifX.cmd = 0; }
#if USE_OLD_GIF == 1 // d
pass1 { vifFlush(idx); vifX.cmd = 0; }
#else
pass1or2 {
vif1Regs.stat.VGW = false;
vifFlush(idx);
if (gifUnit.checkPaths(1,1,0)) {
GUNIT_WARN("Vif Flush: Stall!");
//gifUnit.PrintInfo();
vif1Regs.stat.VGW = true;
vifX.vifstalled = true;
}
else vifX.cmd = 0;
}
#endif
pass3 { VifCodeLog("Flush"); }
return 0;
}
@ -272,21 +314,59 @@ vifOp(vifCode_Flush) {
vifOp(vifCode_FlushA) {
vif1Only();
vifStruct& vifX = GetVifX;
#if USE_OLD_GIF == 1 // d
pass1 {
vifFlush(idx);
// Gif is already transferring so wait for it.
if (gifRegs.stat.P1Q || GSTransferStatus.PTH3 < STOPPED_MODE) {
//DevCon.Warning("VIF FlushA Wait MSK = %x", vif1Regs.mskpath3);
//
MSKPATH3_LOG("Waiting for Path3 to Flush");
//DevCon.WriteLn("FlushA path3 Wait! PTH3 MD %x STR %x", GSTransferStatus.PTH3, gif->chcr.STR);
vif1Regs.stat.VGW = true;
vifX.GifWaitState = 1;
vifX.vifstalled = true;
} // else DevCon.WriteLn("FlushA path3 no Wait! PTH3 MD %x STR %x", GSTransferStatus.PTH3, gif->chcr.STR);
vifX.GifWaitState = 1;
vifX.vifstalled = true;
}
//else DevCon.WriteLn("FlushA path3 no Wait! PTH3 MD %x STR %x", GSTransferStatus.PTH3, gif->chcr.STR);
vifX.cmd = 0;
}
#else
pass1or2 {
Gif_Path& p3 = gifUnit.gifPath[GIF_PATH_3];
u32 p1or2 = gifUnit.checkPaths(1,1,0);
bool doStall = false;
vif1Regs.stat.VGW = false;
vifFlush(idx);
if (p3.state != GIF_PATH_IDLE || p1or2) {
GUNIT_WARN("Vif FlushA: Stall!");
//gifUnit.PrintInfo();
if (p3.state != GIF_PATH_IDLE && !p1or2) { // Only path 3 left...
GUNIT_WARN("Vif FlushA - Getting path3 to finish!");
if (gifUnit.lastTranType == GIF_TRANS_FIFO
&& p3.state != GIF_PATH_IDLE && !p3.hasDataRemaining()) {
p3.state = GIF_PATH_IDLE; // Hack: Tekken 4 and Gitaroo Man need this to boot...
DevCon.Warning("Vif FlushA - path3 has no more data, but didn't EOP");
}
else { // Path 3 hasn't finished its current gs packet
if (gifUnit.stat.APATH != 3 && gifUnit.Path3Masked()) {
gifUnit.stat.APATH = 3; // Hack: Force path 3 to finish (persona 3 needs this)
//DevCon.Warning("Vif FlushA - Forcing path3 to finish current packet");
}
gifInterrupt(); // Feed path3 some gif dma data
gifUnit.Execute(); // Execute path3 in-case gifInterrupt() didn't...
}
if (p3.state != GIF_PATH_IDLE) {
doStall = true; // If path3 still isn't finished...
}
}
else doStall = true;
}
if (doStall) {
vif1Regs.stat.VGW = true;
vifX.vifstalled = true;
}
else vifX.cmd = 0;
}
#endif
pass3 { VifCodeLog("FlushA"); }
return 0;
}
@ -310,7 +390,7 @@ vifOp(vifCode_Mark) {
pass1 {
vifXRegs.mark = (u16)vifXRegs.code;
vifXRegs.stat.MRK = true;
vifX.cmd = 0;
vifX.cmd = 0;
}
pass3 { VifCodeLog("Mark"); }
return 0;
@ -318,7 +398,7 @@ vifOp(vifCode_Mark) {
static __fi void _vifCode_MPG(int idx, u32 addr, const u32 *data, int size) {
VURegs& VUx = idx ? VU1 : VU0;
pxAssume(VUx.Micro > 0);
pxAssert(VUx.Micro > 0);
if (memcmp_mmx(VUx.Micro + addr, data, size*4)) {
// Clear VU memory before writing!
@ -372,7 +452,24 @@ vifOp(vifCode_MSCAL) {
vifOp(vifCode_MSCALF) {
vifStruct& vifX = GetVifX;
#if USE_OLD_GIF == 1 // d
pass1 { vifFlush(idx); vuExecMicro(idx, (u16)(vifXRegs.code) << 3); vifX.cmd = 0; }
#else
pass1or2 {
vifXRegs.stat.VGW = false;
vifFlush(idx);
if (u32 a = gifUnit.checkPaths(1,1,0)) {
GUNIT_WARN("Vif MSCALF: Stall! [%d,%d]", !!(a&1), !!(a&2));
vif1Regs.stat.VGW = true;
vifX.vifstalled = true;
}
else {
vuExecMicro(idx, (u16)(vifXRegs.code) << 3);
vifX.cmd = 0;
}
}
#endif
pass3 { VifCodeLog("MSCALF"); }
return 0;
}
@ -388,15 +485,25 @@ vifOp(vifCode_MSCNT) {
vifOp(vifCode_MskPath3) {
vif1Only();
pass1 {
#if USE_OLD_GIF == 1 // d
MSKPATH3_LOG("Direct MSKPATH3");
schedulepath3msk = 0x10 | (vif1Regs.code >> 15) & 0x1;
if(vif1ch.chcr.STR && vif1.lastcmd != 0x13)vif1.vifstalled = true;
if(vif1ch.chcr.STR && vif1.lastcmd != 0x13) vif1.vifstalled = true;
else Vif1MskPath3();
vif1.cmd = 0;
#else
vif1Regs.mskpath3 = (vif1Regs.code >> 15) & 0x1;
gifRegs.stat.M3P = (vif1Regs.code >> 15) & 0x1;
GUNIT_LOG("Vif1 - MskPath3 [p3 = %s]", vif1Regs.mskpath3 ? "disabled" : "enabled");
if(!vif1Regs.mskpath3) {
//if(!gifUnit.gifPath[GIF_PATH_3].isDone() || gifRegs.stat.P3Q || gifRegs.stat.IP3) {
GUNIT_WARN("Path3 triggering!");
gifInterrupt();
//}
}
vif1.cmd = 0;
#endif
}
pass3 { VifCodeLog("MskPath3"); }
return 0;
@ -446,15 +553,11 @@ template<int idx> static __fi int _vifCode_STColRow(const u32* data, u32* pmem2)
pxAssume(ret > 0);
switch (ret) {
case 4:
pmem2[3] = data[3];
case 3:
pmem2[2] = data[2];
case 2:
pmem2[1] = data[1];
case 1:
pmem2[0] = data[0];
break;
case 4: pmem2[3] = data[3];
case 3: pmem2[2] = data[2];
case 2: pmem2[1] = data[1];
case 1: pmem2[0] = data[0];
break;
jNO_DEFAULT
}
@ -481,7 +584,6 @@ vifOp(vifCode_STCol) {
vifOp(vifCode_STRow) {
vifStruct& vifX = GetVifX;
pass1 {
vifX.tag.addr = 0;
vifX.tag.size = 4;

View File

@ -85,7 +85,6 @@ struct vifStruct {
};
extern __aligned16 vifStruct vif0, vif1;
extern u8 schedulepath3msk;
_vifT extern u32 vifRead32(u32 mem);
_vifT extern bool vifWrite32(u32 mem, u32 value);

View File

@ -83,12 +83,11 @@ _vifT void vifTransferLoop(u32* &data) {
if(!vifX.cmd) { // Get new VifCode
vifXRegs.code = data[0];
vifX.cmd = data[0] >> 24;
iBit = data[0] >> 31;
vifX.cmd = data[0] >> 24;
iBit = data[0] >> 31;
//VIF_LOG("New VifCMD %x tagsize %x", vifX.cmd, vifX.tag.size);
if (IsDevBuild && SysTrace.EE.VIFcode.IsActive())
{
if (IsDevBuild && SysTrace.EE.VIFcode.IsActive()) {
// Pass 2 means "log it"
vifCmdHandler[idx][vifX.cmd & 0x7f](2, data);
}
@ -106,7 +105,7 @@ _vifT void vifTransferLoop(u32* &data) {
if (analyzeIbit<idx>(data, iBit)) break;
}
if (pSize) vifX.vifstalled = true;
if (pSize) vifX.vifstalled = true;
}
_vifT static __fi bool vifTransfer(u32 *data, int size, bool TTE) {
@ -122,51 +121,37 @@ _vifT static __fi bool vifTransfer(u32 *data, int size, bool TTE) {
g_packetsizeonvu = size;
vifTransferLoop<idx>(data);
transferred += size - vifX.vifpacketsize;
g_vifCycles +=((transferred * BIAS) >> 2) ; /* guessing */
transferred += size - vifX.vifpacketsize;
g_vifCycles +=((transferred * BIAS) >> 2) ; /* guessing */
if(!idx && g_vu0Cycles > 0)
{
if(g_vifCycles < g_vu0Cycles) g_vu0Cycles -= g_vifCycles;
else if(g_vifCycles >= g_vu0Cycles)g_vu0Cycles = 0;
if(!idx && g_vu0Cycles > 0) {
if (g_vifCycles < g_vu0Cycles) g_vu0Cycles -= g_vifCycles;
elif(g_vifCycles >= g_vu0Cycles) g_vu0Cycles = 0;
}
else if(idx && g_vu1Cycles > 0)
{
if(g_vifCycles < g_vu1Cycles) g_vu1Cycles -= g_vifCycles;
else if(g_vifCycles >= g_vu1Cycles)g_vu1Cycles = 0;
if (idx && g_vu1Cycles > 0) {
if (g_vifCycles < g_vu1Cycles) g_vu1Cycles -= g_vifCycles;
elif(g_vifCycles >= 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)
{
transferred = transferred >> 2;
if (!TTE) {// *WARNING* - Tags CAN have interrupts! so lets just ignore the dma modifying stuffs (GT4)
transferred = transferred >> 2;
vifXch.madr +=(transferred << 4);
vifXch.qwc -= transferred;
if(vifXch.chcr.STR)hwDmacSrcTadrInc(vifXch);
if (!vifXch.qwc)
{
if (vifXch.chcr.STR) hwDmacSrcTadrInc(vifXch);
if(!vifXch.qwc) {
vifX.inprogress &= ~0x1;
vifX.vifstalled = false;
}
}
else
{
if(!vifX.irqoffset)
{
vifX.vifstalled = false;
}
else {
if (!vifX.irqoffset) vifX.vifstalled = false;
}
if (vifX.irq && vifX.cmd == 0) {
//DevCon.WriteLn("Vif IRQ!");
if(((vifXRegs.code >> 24) & 0x7f) != 0x7)
{
if(((vifXRegs.code >> 24) & 0x7f) != 0x7) {
vifXRegs.stat.VIS = true; // Note: commenting this out fixes WALL-E?
vifX.vifstalled = true;
}

View File

@ -537,7 +537,7 @@ void SysExecEvent_CoreThreadPause::InvokeEvent()
if( CorePluginsAreOpen )
{
CorePluginsAreOpen = GetCorePlugins().AreOpen();
pxAssumeDev( CorePluginsAreOpen, "Invalid plugin close/shutdown detected during paused CoreThread; please Stop/Suspend the core instead." );
pxAssertDev( CorePluginsAreOpen, "Invalid plugin close/shutdown detected during paused CoreThread; please Stop/Suspend the core instead." );
}
paused_core.AllowResume();

View File

@ -188,7 +188,7 @@ public:
EventListenerHelper_CoreThread( TypeToDispatchTo* dispatchTo )
: Owner( *dispatchTo )
{
pxAssume(dispatchTo != NULL);
pxAssert(dispatchTo != NULL);
}
virtual ~EventListenerHelper_CoreThread() throw() {}
@ -215,7 +215,7 @@ public:
EventListenerHelper_Plugins( TypeToDispatchTo* dispatchTo )
: Owner( *dispatchTo )
{
pxAssume(dispatchTo != NULL);
pxAssert(dispatchTo != NULL);
}
virtual ~EventListenerHelper_Plugins() throw() {}
@ -244,7 +244,7 @@ public:
EventListenerHelper_AppStatus( TypeToDispatchTo* dispatchTo )
: Owner( *dispatchTo )
{
pxAssume(dispatchTo != NULL);
pxAssert(dispatchTo != NULL);
}
virtual ~EventListenerHelper_AppStatus() throw() {}

View File

@ -690,7 +690,7 @@ void Pcsx2App::ClearPendingSave()
if( AppRpc_TryInvokeAsync(&Pcsx2App::ClearPendingSave) ) return;
--m_PendingSaves;
pxAssumeDev( m_PendingSaves >= 0, "Pending saves count mismatch (pending count is less than 0)" );
pxAssertDev( m_PendingSaves >= 0, "Pending saves count mismatch (pending count is less than 0)" );
if( (m_PendingSaves == 0) && m_ScheduledTermination )
{
@ -708,17 +708,16 @@ MainEmuFrame& Pcsx2App::GetMainFrame() const
{
MainEmuFrame* mainFrame = GetMainFramePtr();
pxAssume( mainFrame != NULL );
pxAssert( ((uptr)GetTopWindow()) == ((uptr)mainFrame) );
return *mainFrame;
pxAssert(mainFrame != NULL);
pxAssert(((uptr)GetTopWindow()) == ((uptr)mainFrame));
return *mainFrame;
}
GSFrame& Pcsx2App::GetGsFrame() const
{
GSFrame* gsFrame = (GSFrame*)wxWindow::FindWindowById( m_id_GsFrame );
pxAssume( gsFrame != NULL );
return *gsFrame;
GSFrame* gsFrame = (GSFrame*)wxWindow::FindWindowById( m_id_GsFrame );
pxAssert(gsFrame != NULL);
return *gsFrame;
}
// NOTE: Plugins are *not* applied by this function. Changes to plugins need to handled

View File

@ -93,7 +93,7 @@ const ListViewColumnInfo& GameDatabaseListView::GetDefaultColumnInfo( uint idx )
{ L"Patches", 48, wxLIST_FORMAT_CENTER },
};
pxAssumeDev( idx < ArraySize(columns), "ListView column index is out of bounds." );
pxAssertDev( idx < ArraySize(columns), "ListView column index is out of bounds." );
return columns[idx];
}

View File

@ -244,7 +244,7 @@ public:
uint GetViewIndex() const
{
pxAssumeDev( m_viewIndex >= 0, "memory card view-Index is uninitialized (invalid drag&drop object state)" );
pxAssertDev( m_viewIndex >= 0, "memory card view-Index is uninitialized (invalid drag&drop object state)" );
return (uint)m_viewIndex;
}

View File

@ -36,7 +36,7 @@ void BaseMcdListView::SetMcdProvider( IMcdList* face )
IMcdList& BaseMcdListView::GetMcdProvider()
{
pxAssume( m_CardProvider );
pxAssert( m_CardProvider );
return *m_CardProvider;
}
@ -111,7 +111,7 @@ const ListViewColumnInfo& MemoryCardListView_Simple::GetDefaultColumnInfo( uint
{ _("Created on") , 85 , wxLIST_FORMAT_LEFT },
};
pxAssumeDev( idx < ArraySize(columns), "ListView column index is out of bounds." );
pxAssertDev( idx < ArraySize(columns), "ListView column index is out of bounds." );
return columns[idx];
}

View File

@ -175,7 +175,7 @@ namespace Panels
virtual wxDirName GetMcdPath() const
{
pxAssume(m_FolderPicker);
pxAssert(m_FolderPicker);
return m_FolderPicker->GetPath();
}

View File

@ -21,37 +21,11 @@
#include "Vif.h"
#include <xmmintrin.h>
#if USE_OLD_GIF == 1 // d
// --------------------------------------------------------------------------------------
// GIFpath -- the GIFtag Parser
// --------------------------------------------------------------------------------------
enum GIF_FLG
{
GIF_FLG_PACKED = 0,
GIF_FLG_REGLIST = 1,
GIF_FLG_IMAGE = 2,
GIF_FLG_IMAGE2 = 3
};
enum GIF_REG
{
GIF_REG_PRIM = 0x00,
GIF_REG_RGBA = 0x01,
GIF_REG_STQ = 0x02,
GIF_REG_UV = 0x03,
GIF_REG_XYZF2 = 0x04,
GIF_REG_XYZ2 = 0x05,
GIF_REG_TEX0_1 = 0x06,
GIF_REG_TEX0_2 = 0x07,
GIF_REG_CLAMP_1 = 0x08,
GIF_REG_CLAMP_2 = 0x09,
GIF_REG_FOG = 0x0a,
GIF_REG_XYZF3 = 0x0c,
GIF_REG_XYZ3 = 0x0d,
GIF_REG_A_D = 0x0e,
GIF_REG_NOP = 0x0f,
};
// GIFTAG
// Members of this structure are in CAPS to help visually denote that they are representative
// of actual hw register states of the GIF, unlike the internal tracking vars in GIFPath, which
@ -203,7 +177,7 @@ static void __fastcall RegHandlerSIGNAL(const u32* data)
if (!SIGNAL_IMR_Pending)
{
//DevCon.WriteLn( Color_StrongOrange, "GS SIGNAL double throw encountered!" );
SIGNAL_IMR_Pending = true;
SIGNAL_IMR_Pending = true;
SIGNAL_Data_Pending[0] = data[0];
SIGNAL_Data_Pending[1] = data[1];
@ -273,8 +247,8 @@ static void __fastcall RegHandlerUNMAPPED(const u32* data)
// Using microVU avoids the GIFtag errors, so probably just one of sVU's hacks conflicting
// with one of VIF's hacks, and causing corrupted packet data.
if( regidx != 0x7f && regidx != 0xee )
DbgCon.Warning( "Ignoring Unmapped GIFtag Register, Index = %02x", regidx );
if( regidx != 0x7f /*&& regidx != 0xee*/ )
DevCon.Warning( "Ignoring Unmapped GIFtag Register, Index = %02x", regidx );
}
#define INSERT_UNMAPPED_4 RegHandlerUNMAPPED, RegHandlerUNMAPPED, RegHandlerUNMAPPED, RegHandlerUNMAPPED,
@ -355,13 +329,6 @@ __fi bool GIFPath::IsActive() const
return (nloop != 0) || !tag.EOP;
}
void SaveStateBase::gifPathFreeze()
{
FreezeTag( "GIFpath" );
Freeze( s_gifPath.path );
}
static __fi void gsHandler(const u8* pMem)
{
const int reg = pMem[8];
@ -579,42 +546,6 @@ __fi int GIFPath::ParseTagQuick(GIF_PATH pathidx, const u8* pMem, u32 size)
return size;
}
__ri void MemCopy_WrappedDest( const u128* src, u128* destBase, uint& destStart, uint destSize, uint len )
{
uint endpos = destStart + len;
if( endpos < destSize )
{
memcpy_qwc(&destBase[destStart], src, len );
destStart += len;
}
else
{
uint firstcopylen = destSize - destStart;
memcpy_qwc(&destBase[destStart], src, firstcopylen );
destStart = endpos % destSize;
memcpy_qwc(destBase, src+firstcopylen, destStart );
}
}
__ri void MemCopy_WrappedSrc( const u128* srcBase, uint& srcStart, uint srcSize, u128* dest, uint len )
{
uint endpos = srcStart + len;
if( endpos < srcSize )
{
memcpy_qwc(dest, &srcBase[srcStart], len );
srcStart += len;
}
else
{
uint firstcopylen = srcSize - srcStart;
memcpy_qwc(dest, &srcBase[srcStart], firstcopylen );
srcStart = endpos % srcSize;
memcpy_qwc(dest+firstcopylen, srcBase, srcStart );
}
}
#define copyTag() do { \
_mm_store_ps( (float*)&RingBuffer.m_Ring[ringpos], Aligned ? _mm_load_ps((float*)pMem128) : _mm_loadu_ps((float*)pMem128)); \
++pMem128; --size; \
@ -991,7 +922,22 @@ __fi void GIFPath_Clear( GIF_PATH pathidx )
s_gifPath.path[pathidx].Reset();
GSTransferStatus._u32 &= ~(0xf << (pathidx * 4));
GSTransferStatus._u32 |= (0x5 << (pathidx * 4));
GSTransferStatus._u32 |= (0x5 << (pathidx * 4));
if( GSgifSoftReset == NULL ) return;
GetMTGS().SendSimplePacket( GS_RINGTYPE_SOFTRESET, (1<<pathidx), 0, 0 );
}
void SaveStateBase::gifPathFreeze()
{
FreezeTag( "GIFpath" );
Freeze( s_gifPath.path );
}
#else
void SaveStateBase::gifPathFreeze()
{
//FreezeTag( "GIFpath" );
//Freeze( s_gifPath.path );
}
#endif // USE_OLD_GIF == 1

View File

@ -889,6 +889,18 @@
RelativePath="..\..\Gif.h"
>
</File>
<File
RelativePath="..\..\Gif_Unit.cpp"
>
</File>
<File
RelativePath="..\..\Gif_Unit.h"
>
</File>
<File
RelativePath="..\..\ps2\GIFpath.cpp"
>
</File>
</Filter>
</Filter>
<Filter
@ -1355,10 +1367,6 @@
<Filter
Name="GS"
>
<File
RelativePath="..\..\ps2\GIFpath.cpp"
>
</File>
<File
RelativePath="..\..\GS.cpp"
>

View File

@ -158,7 +158,7 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
m_crtFile = -1;
m_fp = NULL;
pxAssume( (stdstream == stderr) || (stdstream == stdout) );
pxAssert( (stdstream == stderr) || (stdstream == stdout) );
try
{

View File

@ -259,7 +259,7 @@ static void recLUT_SetPage(uptr reclut[0x10000], uptr hwlut[0x10000],
// this value is in 64k pages!
uint page = pagebase + pageidx;
pxAssume( page < 0x10000 );
pxAssert( page < 0x10000 );
reclut[page] = (uptr)&mapbase[(mappage - page) << 14];
if (hwlut)
hwlut[page] = 0u - (pagebase << 16);

View File

@ -468,7 +468,7 @@ static DynGenFunc* _DynGen_DispatcherReg()
static DynGenFunc* _DynGen_EnterRecompiledCode()
{
pxAssumeDev( DispatcherReg != NULL, "Dynamically generated dispatchers are required prior to generating EnterRecompiledCode!" );
pxAssertDev( DispatcherReg != NULL, "Dynamically generated dispatchers are required prior to generating EnterRecompiledCode!" );
u8* retval = xGetAlignedCallTarget();
@ -1400,7 +1400,7 @@ static void __fastcall recRecompile( const u32 startpc )
if (dumplog & 4) iDumpRegisters(startpc, 0);
#endif
pxAssume( startpc );
pxAssert( startpc );
// if recPtr reached the mem limit reset whole mem
if (recPtr >= (recMem->GetPtrEnd() - _64kb)) {
@ -1429,7 +1429,7 @@ static void __fastcall recRecompile( const u32 startpc )
s_pCurBlockEx = recBlocks.New(HWADDR(startpc), (uptr)recPtr);
pxAssume(s_pCurBlockEx);
pxAssert(s_pCurBlockEx);
if (g_SkipBiosHack && HWADDR(startpc) == EELOAD_START) {
xCALL(eeloadReplaceOSDSYS);
@ -1448,7 +1448,7 @@ static void __fastcall recRecompile( const u32 startpc )
pc = startpc;
x86FpuState = FPU_STATE;
g_cpuHasConstReg = g_cpuFlushedConstReg = 1;
pxAssume( g_cpuConstRegs[0].UD[0] == 0 );
pxAssert( g_cpuConstRegs[0].UD[0] == 0 );
_initX86regs();
_initXMMregs();

View File

@ -26,6 +26,7 @@ using namespace x86Emitter;
#include "VU.h"
#include "GS.h"
#include "Gif.h"
#include "Gif_Unit.h"
#include "iR5900.h"
#include "R5900OpcodeTables.h"
#include "System/RecTypes.h"

View File

@ -25,9 +25,9 @@
__fi static const x32& getFlagReg(uint fInst)
{
static const x32* const gprF_crap[4] = { &gprF0, &gprF1, &gprF2, &gprF3 };
pxAssume(fInst < 4);
return *gprF_crap[fInst];
static const x32* const gprFlags[4] = { &gprF0, &gprF1, &gprF2, &gprF3 };
pxAssert(fInst < 4);
return *gprFlags[fInst];
}
__fi void setBitSFLAG(const x32& reg, const x32& regT, int bitTest, int bitSet)

View File

@ -508,8 +508,8 @@ __fi void* mVUentryGet(microVU& mVU, microBlockManager* block, u32 startPC, uptr
// Search for Existing Compiled Block (if found, return x86ptr; else, compile and return x86ptr)
__fi void* mVUblockFetch(microVU& mVU, u32 startPC, uptr pState) {
pxAssumeDev((startPC & 7) == 0, pxsFmt("microVU%d: unaligned startPC=0x%04x", mVU.index, startPC) );
pxAssumeDev( startPC <= mVU.microMemSize-8, pxsFmt("microVU%d: invalid startPC=0x%04x", mVU.index, startPC) );
pxAssertDev((startPC & 7) == 0, pxsFmt("microVU%d: unaligned startPC=0x%04x", mVU.index, startPC) );
pxAssertDev( startPC <= mVU.microMemSize-8, pxsFmt("microVU%d: invalid startPC=0x%04x", mVU.index, startPC) );
startPC &= mVU.microMemSize-8;
blockCreate(startPC/8);

View File

@ -230,7 +230,7 @@ protected:
}
}
int x = findFreeRegRec(0);
pxAssumeDev( x >= 0, "microVU register allocation failure!" );
pxAssertDev( x >= 0, "microVU register allocation failure!" );
return x;
}

View File

@ -1119,64 +1119,50 @@ mVUop(mVU_XITOP) {
// XGkick
//------------------------------------------------------------------
extern void gsPath1Interrupt();
extern bool SIGNAL_IMR_Pending;
void __fastcall mVU_XGKICK_(u32 addr) {
#if USE_OLD_GIF == 1 // d
extern void gsPath1Interrupt();
extern bool SIGNAL_IMR_Pending;
addr &= 0x3ff;
u8* data = vuRegs[1].Mem + (addr*16);
u32 diff = 0x400 - addr;
u32 size;
///////////////////////////////////////////////
///////////////SIGNAL WARNING!!////////////////
///////////////////////////////////////////////
/* Due to the face SIGNAL can cause the loop
to leave early, we can end up missing data.
The only way we can avoid this is to queue
it :(, im relying on someone else to come
up with a better solution! */
/*if(gifRegs.stat.APATH <= GIF_APATH1 || (gifRegs.stat.APATH == GIF_APATH3 && gifRegs.stat.IP3 == true) && SIGNAL_IMR_Pending == false)
{
if(Path1WritePos != 0)
{
//Flush any pending transfers so things dont go up in the wrong order
while(gifRegs.stat.P1Q == true) gsPath1Interrupt();
}
GetMTGS().PrepDataPacket(GIF_PATH_1, 0x400);
size = GIFPath_CopyTag(GIF_PATH_1, (u128*)data, diff);
GetMTGS().SendDataPacket();
size = GIFPath_ParseTagQuick(GIF_PATH_1, data, diff);
u8* pDest = &Path1Buffer[Path1WritePos*16];
if(GSTransferStatus.PTH1 == STOPPED_MODE)
{
gifRegs.stat.OPH = false;
gifRegs.stat.APATH = GIF_APATH_IDLE;
}
Path1WritePos += size;
pxAssertMsg((Path1WritePos < sizeof(Path1Buffer)), "XGKick Buffer Overflow detected on Path1Buffer!");
//DevCon.Warning("Storing size %x PATH 1", size);
if (size > diff) {
//DevCon.Status("XGkick Wrap!");
memcpy_qwc(pDest, vuRegs[1].Mem + (addr*16), diff);
memcpy_qwc(pDest+(diff*16), vuRegs[1].Mem, size-diff);
}
else
{*/
//DevCon.Warning("GIF APATH busy %x Holding for later W %x, R %x", gifRegs.stat.APATH, Path1WritePos, Path1ReadPos);
size = GIFPath_ParseTagQuick(GIF_PATH_1, data, diff);
u8* pDest = &Path1Buffer[Path1WritePos*16];
else {
memcpy_qwc(pDest, vuRegs[1].Mem + (addr*16), size);
}
//if(!gifRegs.stat.P1Q) CPU_INT(28, 128);
gifRegs.stat.P1Q = true;
Path1WritePos += size;
gsPath1Interrupt();
#else
addr = (addr & 0x3ff) * 16;
u32 diff = 0x4000 - addr;
u32 size = gifUnit.GetGSPacketSize(GIF_PATH_1, vuRegs[1].Mem, addr);
pxAssumeMsg((Path1WritePos < sizeof(Path1Buffer)), "XGKick Buffer Overflow detected on Path1Buffer!");
//DevCon.Warning("Storing size %x PATH 1", size);
if (size > diff) {
//DevCon.Status("XGkick Wrap!");
memcpy_qwc(pDest, vuRegs[1].Mem + (addr*16), diff);
memcpy_qwc(pDest+(diff*16), vuRegs[1].Mem, size-diff);
}
else {
memcpy_qwc(pDest, vuRegs[1].Mem + (addr*16), size);
}
//if(!gifRegs.stat.P1Q) CPU_INT(28, 128);
gifRegs.stat.P1Q = true;
//}
gsPath1Interrupt();
if (size > diff) {
//DevCon.WriteLn(Color_Green, "microVU1: XGkick Wrap!");
gifUnit.gifPath[GIF_PATH_1].CopyGSPacketData( &vuRegs[1].Mem[addr], diff,true);
gifUnit.TransferGSPacketData(GIF_TRANS_XGKICK, &vuRegs[1].Mem[0],size-diff,true);
}
else {
gifUnit.TransferGSPacketData(GIF_TRANS_XGKICK, &vuRegs[1].Mem[addr], size, true);
}
#endif
}
static __fi void mVU_XGKICK_DELAY(mV, bool memVI) {

View File

@ -241,11 +241,11 @@ typedef u32 (__fastcall *mVUCall)(void*, void*);
}
#define branchAddr ( \
pxAssumeDev((iPC & 1) == 0, "microVU: Expected Lower Op for valid branch addr."), \
pxAssertDev((iPC & 1) == 0, "microVU: Expected Lower Op for valid branch addr."), \
((((iPC + 2) + (_Imm11_ * 2)) & mVU.progMemMask) * 4) \
)
#define branchAddrN ( \
pxAssumeDev((iPC & 1) == 0, "microVU: Expected Lower Op for valid branch addr."), \
pxAssertDev((iPC & 1) == 0, "microVU: Expected Lower Op for valid branch addr."), \
((((iPC + 4) + (_Imm11_ * 2)) & mVU.progMemMask) * 4) \
)

View File

@ -32,7 +32,7 @@ void dVifReserve(int idx)
void dVifReset(int idx) {
pxAssumeDev(nVif[idx].recReserve, "Dynamic VIF recompiler reserve must be created prior to VIF use or reset!");
pxAssertDev(nVif[idx].recReserve, "Dynamic VIF recompiler reserve must be created prior to VIF use or reset!");
if (!nVif[idx].vifBlocks)
nVif[idx].vifBlocks = new HashBucket<_tParams>();
@ -92,7 +92,7 @@ __fi void VifUnpackSSE_Dynarec::SetMasks(int cS) const {
}
void VifUnpackSSE_Dynarec::doMaskWrite(const xRegisterSSE& regX) const {
pxAssumeDev(regX.Id <= 1, "Reg Overflow! XMM2 thru XMM6 are reserved for masking.");
pxAssertDev(regX.Id <= 1, "Reg Overflow! XMM2 thru XMM6 are reserved for masking.");
xRegisterSSE t = regX == xmm0 ? xmm1 : xmm0; // Get Temp Reg
int cc = aMin(vCL, 3);
u32 m0 = (vB.mask >> (cc * 8)) & 0xff;

View File

@ -110,7 +110,7 @@ void VifUnpackSSE_Base::xUPK_S_8() const {
void VifUnpackSSE_Base::xUPK_V2_32() const {
xMOV64 (destReg, ptr32[srcIndirect]);
xMOVH.PS (destReg, ptr32[srcIndirect]); //v1v0v1v0
xPSHUF.D (destReg, destReg, 0x44); //v1v0v1v0
}
void VifUnpackSSE_Base::xUPK_V2_16() const {

View File

@ -27,6 +27,7 @@
#include "sVU_Debug.h"
#include "sVU_zerorec.h"
#include "Gif.h"
#include "Gif_Unit.h"
using namespace x86Emitter;
//------------------------------------------------------------------
@ -1972,64 +1973,50 @@ void recVUMI_XTOP( VURegs *VU, int info )
//------------------------------------------------------------------
// VU1XGKICK_MTGSTransfer() - Called by ivuZerorec.cpp
//------------------------------------------------------------------
extern bool SIGNAL_IMR_Pending;
void __fastcall VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr)
void __fastcall VU1XGKICK_MTGSTransfer(u32 addr)
{
#if USE_OLD_GIF == 1 // todo
extern bool SIGNAL_IMR_Pending;
addr &= 0x3fff;
u8* data = VU1.Mem + (addr);
u32 diff = 0x400 - (addr / 16);
u32 size;
u8* pDest;
///////////////////////////////////////////////
///////////////SIGNAL WARNING!!////////////////
///////////////////////////////////////////////
/* Due to the face SIGNAL can cause the loop
to leave early, we can end up missing data.
The only way we can avoid this is to queue
it :(, im relying on someone else to come
up with a better solution! */
//DevCon.Warning("GIF APATH busy %x Holding for later W %x, R %x", gifRegs.stat.APATH, Path1WritePos, Path1ReadPos);
size = GIFPath_ParseTagQuick(GIF_PATH_1, data, diff);
pDest = &Path1Buffer[Path1WritePos*16];
Path1WritePos += size;
/*if(gifRegs.stat.APATH <= GIF_APATH1 || (gifRegs.stat.APATH == GIF_APATH3 && gifRegs.stat.IP3 == true) && SIGNAL_IMR_Pending == false)
{
if(Path1WritePos != 0)
{
//Flush any pending transfers so things dont go up in the wrong order
while(gifRegs.stat.P1Q == true) gsPath1Interrupt();
}
GetMTGS().PrepDataPacket(GIF_PATH_1, 0x400);
size = GIFPath_CopyTag(GIF_PATH_1, (u128*)data, diff);
GetMTGS().SendDataPacket();
pxAssertMsg((Path1WritePos+size < sizeof(Path1Buffer)), "XGKick Buffer Overflow detected on Path1Buffer!");
if(GSTransferStatus.PTH1 == STOPPED_MODE )
{
gifRegs.stat.OPH = false;
gifRegs.stat.APATH = GIF_APATH_IDLE;
}
if (size > diff) {
//DevCon.Status("XGkick Wrap!");
memcpy_qwc(pDest, VU1.Mem + addr, diff);
memcpy_qwc(pDest+(diff*16), VU1.Mem, size-diff);
}
else
{*/
//DevCon.Warning("GIF APATH busy %x Holding for later W %x, R %x", gifRegs.stat.APATH, Path1WritePos, Path1ReadPos);
size = GIFPath_ParseTagQuick(GIF_PATH_1, data, diff);
pDest = &Path1Buffer[Path1WritePos*16];
else {
memcpy_qwc(pDest, VU1.Mem + addr, size);
}
//if(!gifRegs.stat.P1Q) CPU_INT(28, 128);
gifRegs.stat.P1Q = true;
//}
gsPath1Interrupt();
#else
addr &= 0x3fff;
u32 diff = 0x4000 - addr;
u32 size = gifUnit.GetGSPacketSize(GIF_PATH_1, vuRegs[1].Mem, addr);
Path1WritePos += size;
pxAssumeMsg((Path1WritePos+size < sizeof(Path1Buffer)), "XGKick Buffer Overflow detected on Path1Buffer!");
if (size > diff) {
//DevCon.Status("XGkick Wrap!");
memcpy_qwc(pDest, VU1.Mem + addr, diff);
memcpy_qwc(pDest+(diff*16), VU1.Mem, size-diff);
}
else {
memcpy_qwc(pDest, VU1.Mem + addr, size);
}
//if(!gifRegs.stat.P1Q) CPU_INT(28, 128);
gifRegs.stat.P1Q = true;
//}
gsPath1Interrupt();
if (size > diff) {
//DevCon.WriteLn(Color_Green, "superVU1: XGkick Wrap!");
gifUnit.gifPath[0].CopyGSPacketData(&vuRegs[1].Mem[addr], diff, true);
gifUnit.TransferGSPacketData(GIF_TRANS_XGKICK, &vuRegs[1].Mem[0],size-diff,true);
}
else {
gifUnit.TransferGSPacketData(GIF_TRANS_XGKICK, &vuRegs[1].Mem[addr], size, true);
}
#endif
}
//------------------------------------------------------------------

View File

@ -47,7 +47,7 @@ struct _vuopinfo {
void SuperVUAnalyzeOp(VURegs *VU, _vuopinfo *info, _VURegsNum* pCodeRegs);
int eeVURecompileCode(VURegs *VU, _VURegsNum* regs); // allocates all the necessary regs and returns the indices
void __fastcall VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr); // used for MTGS in XGKICK
void __fastcall VU1XGKICK_MTGSTransfer(u32 addr); // used for MTGS in XGKICK
extern int vucycle;
typedef void (*vFloat)(int regd, int regTemp);

View File

@ -396,7 +396,7 @@ void DestroyVUHeaders(int vuindex)
// destroy VU resources
void SuperVUDestroy(int vuindex)
{
pxAssumeDev(vuindex >= 0 && vuindex <= 2, "Invalid VU index parameter!");
pxAssertDev(vuindex >= 0 && vuindex <= 2, "Invalid VU index parameter!");
safe_delete_array(recVUHeaders[vuindex]);
safe_delete_array(recVUBlocks[vuindex]);
@ -418,7 +418,7 @@ void SuperVUDestroy(int vuindex)
// reset VU
void SuperVUReset(int vuindex)
{
pxAssumeDev(vuindex >= 0 && vuindex <= 2, "Invalid VU index parameter!");
pxAssertDev(vuindex >= 0 && vuindex <= 2, "Invalid VU index parameter!");
#ifdef PCSX2_DEBUG
s_vucount = 0;
@ -4314,8 +4314,7 @@ void recVUMI_XGKICK_(VURegs *VU)
_freeX86regs();
_freeXMMregs();
xMOV(edx, xRegister32(s_XGKICKReg));
xMOV(ecx, (uptr)VU->Mem);
xMOV(ecx, xRegister32(s_XGKICKReg));
xCALL(VU1XGKICK_MTGSTransfer);
s_ScheduleXGKICK = 0;

View File

@ -535,7 +535,7 @@ static __forceinline StereoOut32 MixVoice( uint coreidx, uint voiceidx )
// If this assertion fails, it mans SCurrent is being corrupted somewhere, or is not initialized
// properly. Invalid values in SCurrent will cause errant IRQs and corrupted audio.
pxAssumeMsg( (vc.SCurrent <= 28) && (vc.SCurrent != 0), "Current sample should always range from 1->28" );
pxAssertMsg( (vc.SCurrent <= 28) && (vc.SCurrent != 0), "Current sample should always range from 1->28" );
// Most games don't use much volume slide effects. So only call the UpdateVolume
// methods when needed by checking the flag outside the method here...

View File

@ -54,7 +54,7 @@ s32 __fastcall Savestate::FreezeIt( DataBlock& spud )
spud.spu2id = SAVE_ID;
spud.version = SAVE_VERSION;
pxAssumeMsg( spu2regs && _spu2mem, "Looks like PCSX2 is trying to savestate while pluigns are shut down. That's a no-no! It shouldn't crash, but the savestate will probably be corrupted." );
pxAssertMsg( spu2regs && _spu2mem, "Looks like PCSX2 is trying to savestate while pluigns are shut down. That's a no-no! It shouldn't crash, but the savestate will probably be corrupted." );
if( spu2regs != NULL ) memcpy(spud.unkregs, spu2regs, sizeof(spud.unkregs));
if( _spu2mem != NULL ) memcpy(spud.mem, _spu2mem, sizeof(spud.mem));
@ -104,7 +104,7 @@ s32 __fastcall Savestate::ThawIt( DataBlock& spud )
{
SndBuffer::ClearContents();
pxAssumeMsg( spu2regs && _spu2mem, "Looks like PCSX2 is trying to loadstate while pluigns are shut down. That's a no-no! It shouldn't crash, but the savestate will probably be corrupted." );
pxAssertMsg( spu2regs && _spu2mem, "Looks like PCSX2 is trying to loadstate while pluigns are shut down. That's a no-no! It shouldn't crash, but the savestate will probably be corrupted." );
// base stuff
if( spu2regs ) memcpy(spu2regs, spud.unkregs, sizeof(spud.unkregs));

View File

@ -452,9 +452,9 @@ __forceinline void _TransferLocalLocal_4()
assert((gs.imageWnew % 8) == 0);
for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < maxY; ++i, ++i2)
for(u32 i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < maxY; ++i, ++i2)
{
for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < maxX; j += 8, j2 += 8)
for(u32 j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < maxX; j += 8, j2 += 8)
{
/* NOTE: the 2 conseq 4bit values are in NOT in the same byte */
u32 read = gsp(j%2048, i%2048, gs.srcbuf.bw);