mirror of https://github.com/PCSX2/pcsx2.git
wxgui: Prepped the R5900 recompiler for the new wxWidgets-enhanced dedicated emulation thread design, and removed the old boolean-based re-entrant event checking mess.
Note: Nearly have a successfully booting branch! (bios crashes when it reaches CDVD api callbacks, should be a simple fix but it'll have to wait until later >_<) git-svn-id: http://pcsx2.googlecode.com/svn/branches/wxgui@1680 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
307346e19e
commit
9303bc5bf2
|
@ -540,6 +540,7 @@ typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int);
|
|||
//typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info);
|
||||
|
||||
// PAD
|
||||
typedef s32 (CALLBACK* _PADinit)(u32 flags);
|
||||
typedef s32 (CALLBACK* _PADopen)(void *pDsp);
|
||||
typedef u8 (CALLBACK* _PADstartPoll)(int pad);
|
||||
typedef u8 (CALLBACK* _PADpoll)(u8 value);
|
||||
|
|
|
@ -43,6 +43,8 @@ namespace Exception
|
|||
};
|
||||
}
|
||||
|
||||
class wxTimeSpan;
|
||||
|
||||
namespace Threading
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -74,7 +76,9 @@ namespace Threading
|
|||
void Reset();
|
||||
void Post();
|
||||
void Post( int multiple );
|
||||
|
||||
void Wait();
|
||||
void Wait( const wxTimeSpan& timeout );
|
||||
void WaitNoCancel();
|
||||
int Count();
|
||||
};
|
||||
|
@ -107,7 +111,7 @@ namespace Threading
|
|||
// PersistentThread - Helper class for the basics of starting/managing persistent threads.
|
||||
//
|
||||
// Use this as a base class for your threaded procedure, and implement the 'int ExecuteTask()'
|
||||
// method. Use Start() and Cancel() to start and shutdown the thread, and use m_post_event
|
||||
// method. Use Start() and Cancel() to start and shutdown the thread, and use m_sem_event
|
||||
// internally to post/receive events for the thread (make a public accessor for it in your
|
||||
// derived class if your thread utilizes the post).
|
||||
//
|
||||
|
@ -127,7 +131,7 @@ namespace Threading
|
|||
sptr m_returncode; // value returned from the thread on close.
|
||||
|
||||
bool m_running;
|
||||
Semaphore m_post_event; // general wait event that's needed by most threads.
|
||||
Semaphore m_sem_event; // general wait event that's needed by most threads.
|
||||
|
||||
public:
|
||||
virtual ~PersistentThread();
|
||||
|
@ -259,7 +263,7 @@ namespace Threading
|
|||
{
|
||||
if( !m_running ) return m_returncode;
|
||||
m_Done = true;
|
||||
m_post_event.Post();
|
||||
m_sem_event.Post();
|
||||
return PersistentThread::Block();
|
||||
}
|
||||
|
||||
|
@ -270,7 +274,7 @@ namespace Threading
|
|||
jASSUME( m_running );
|
||||
m_TaskComplete = false;
|
||||
m_post_TaskComplete.Reset();
|
||||
m_post_event.Post();
|
||||
m_sem_event.Post();
|
||||
}
|
||||
|
||||
// Blocks current thread execution pending the completion of the parallel task.
|
||||
|
@ -293,7 +297,7 @@ namespace Threading
|
|||
do
|
||||
{
|
||||
// Wait for a job!
|
||||
m_post_event.Wait();
|
||||
m_sem_event.Wait();
|
||||
|
||||
if( m_Done ) break;
|
||||
Task();
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
#include "Threading.h"
|
||||
|
||||
#include <wx/datetime.h>
|
||||
|
||||
#ifdef __LINUX__
|
||||
# include <signal.h> // for pthread_kill, which is in pthread.h on w32-pthreads
|
||||
#endif
|
||||
|
@ -31,7 +33,7 @@ namespace Threading
|
|||
m_thread()
|
||||
, m_returncode( 0 )
|
||||
, m_running( false )
|
||||
, m_post_event()
|
||||
, m_sem_event()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -175,22 +177,30 @@ namespace Threading
|
|||
sem_post( &sema );
|
||||
}
|
||||
|
||||
// Valid on Win32 builds only!! Attempts to use it on Linux will result in unresolved
|
||||
// external linker errors.
|
||||
#if defined(_MSC_VER)
|
||||
void Semaphore::Post( int multiple )
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
sem_post_multiple( &sema, multiple );
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void Semaphore::Wait()
|
||||
{
|
||||
sem_wait( &sema );
|
||||
}
|
||||
|
||||
void Semaphore::Wait( const wxTimeSpan& timeout )
|
||||
{
|
||||
const timespec fail = { timeout.GetSeconds().GetLo(), 0 };
|
||||
sem_timedwait( &sema, &fail );
|
||||
}
|
||||
|
||||
// Performs an uncancellable wait on a semaphore; restoring the thread's previous cancel state
|
||||
// after the wait has completed. Useful for situations where the semaphore itself is stored on
|
||||
// the stack and passed to another thread via GUI message or such, avoiding complications where
|
||||
// the thread might be cancelled and the stack value becomes invalid.
|
||||
// the thread might be canceled and the stack value becomes invalid.
|
||||
//
|
||||
// Performance note: this function has quite a bit more overhead compared to Semaphore::Wait(), so
|
||||
// consider manually specifying the thread as uncancellable and using Wait() instead if you need
|
||||
|
|
|
@ -107,12 +107,11 @@ void Win32::RealVersionInfo::InitVersionString()
|
|||
int majorVersion = (DWORD)(LOBYTE(LOWORD(version)));
|
||||
int minorVersion = (DWORD)(HIBYTE(LOWORD(version)));
|
||||
|
||||
RealVersionInfo really;
|
||||
wxString verName( wxString::FromAscii( GetVersionName( minorVersion, majorVersion ) ) );
|
||||
|
||||
bool IsCompatMode = false;
|
||||
|
||||
if( really.IsVista() )
|
||||
if( IsVista() )
|
||||
{
|
||||
m_VersionString = L"Windows Vista";
|
||||
|
||||
|
@ -131,7 +130,7 @@ void Win32::RealVersionInfo::InitVersionString()
|
|||
else
|
||||
m_VersionString += L" (32-bit)";
|
||||
}
|
||||
else if( really.IsXP() )
|
||||
else if( IsXP() )
|
||||
{
|
||||
m_VersionString = wxsFormat( L"Windows XP v%d.%d", majorVersion, minorVersion );
|
||||
|
||||
|
|
|
@ -22,10 +22,10 @@ class IniInterface;
|
|||
|
||||
enum PluginsEnum_t
|
||||
{
|
||||
PluginId_CDVD = 0,
|
||||
PluginId_GS,
|
||||
PluginId_GS = 0,
|
||||
PluginId_PAD,
|
||||
PluginId_SPU2,
|
||||
PluginId_CDVD,
|
||||
PluginId_USB,
|
||||
PluginId_FW,
|
||||
PluginId_DEV9,
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "GS.h"
|
||||
#include "VUmicro.h"
|
||||
#include "ps2/CoreEmuThread.h"
|
||||
|
||||
using namespace Threading;
|
||||
|
||||
|
@ -436,10 +437,10 @@ __forceinline void rcntUpdate_hScanline()
|
|||
}
|
||||
}
|
||||
|
||||
__forceinline bool rcntUpdate_vSync()
|
||||
__forceinline void rcntUpdate_vSync()
|
||||
{
|
||||
s32 diff = (cpuRegs.cycle - vsyncCounter.sCycle);
|
||||
if( diff < vsyncCounter.CycleT ) return false;
|
||||
if( diff < vsyncCounter.CycleT ) return;
|
||||
|
||||
//iopBranchAction = 1;
|
||||
if (vsyncCounter.Mode == MODE_VSYNC)
|
||||
|
@ -450,7 +451,7 @@ __forceinline bool rcntUpdate_vSync()
|
|||
vsyncCounter.CycleT = vSyncInfo.Render;
|
||||
vsyncCounter.Mode = MODE_VRENDER;
|
||||
|
||||
return true;
|
||||
CoreEmuThread::Get().StateCheck();
|
||||
}
|
||||
else // VSYNC end / VRENDER begin
|
||||
{
|
||||
|
@ -477,7 +478,6 @@ __forceinline bool rcntUpdate_vSync()
|
|||
}
|
||||
# endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static __forceinline void _cpuTestTarget( int i )
|
||||
|
@ -518,14 +518,14 @@ static __forceinline void _cpuTestOverflow( int i )
|
|||
// forceinline note: this method is called from two locations, but one
|
||||
// of them is the interpreter, which doesn't count. ;) So might as
|
||||
// well forceinline it!
|
||||
__forceinline bool rcntUpdate()
|
||||
__forceinline void rcntUpdate()
|
||||
{
|
||||
bool retval = rcntUpdate_vSync();
|
||||
rcntUpdate_vSync();
|
||||
|
||||
// Update counters so that we can perform overflow and target tests.
|
||||
|
||||
for (int i=0; i<=3; i++) {
|
||||
|
||||
for (int i=0; i<=3; i++)
|
||||
{
|
||||
// We want to count gated counters (except the hblank which exclude below, and are
|
||||
// counted by the hblank timer instead)
|
||||
|
||||
|
@ -550,7 +550,6 @@ __forceinline bool rcntUpdate()
|
|||
}
|
||||
|
||||
cpuRcntSet();
|
||||
return retval;
|
||||
}
|
||||
|
||||
static __forceinline void _rcntSetGate( int index )
|
||||
|
@ -582,8 +581,8 @@ __forceinline void rcntStartGate(bool isVblank, u32 sCycle)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i <=3; i++) {
|
||||
|
||||
for (i=0; i <=3; i++)
|
||||
{
|
||||
//if ((mode == 0) && ((counters[i].mode & 0x83) == 0x83))
|
||||
if (!isVblank && counters[i].mode.IsCounting && (counters[i].mode.ClockSource == 3) )
|
||||
{
|
||||
|
|
|
@ -135,8 +135,8 @@ extern s32 nextCounter; // delta until the next counter event (must be signed)
|
|||
extern u32 nextsCounter;
|
||||
|
||||
extern void rcntUpdate_hScanline();
|
||||
extern bool rcntUpdate_vSync();
|
||||
extern bool rcntUpdate();
|
||||
extern void rcntUpdate_vSync();
|
||||
extern void rcntUpdate();
|
||||
|
||||
extern void rcntInit();
|
||||
extern void rcntStartGate(bool mode, u32 sCycle);
|
||||
|
|
55
pcsx2/GS.cpp
55
pcsx2/GS.cpp
|
@ -30,8 +30,6 @@ using namespace Threading;
|
|||
using namespace std;
|
||||
using namespace R5900;
|
||||
|
||||
static bool m_gsOpened = false;
|
||||
|
||||
u32 CSRw;
|
||||
|
||||
PCSX2_ALIGNED16( u8 g_RealGSMem[0x2000] );
|
||||
|
@ -150,61 +148,10 @@ void gsInit()
|
|||
}
|
||||
}
|
||||
|
||||
// Opens the gsRingbuffer thread.
|
||||
s32 gsOpen()
|
||||
{
|
||||
if( m_gsOpened ) return 0;
|
||||
|
||||
//video
|
||||
// Only bind the gsIrq if we're not running the MTGS.
|
||||
// The MTGS simulates its own gsIrq in order to maintain proper sync.
|
||||
|
||||
m_gsOpened = mtgsOpen();
|
||||
if( !m_gsOpened )
|
||||
{
|
||||
// MTGS failed to init or is disabled. Try the GS instead!
|
||||
// ... and set the memptr again just in case (for switching between GS/MTGS on the fly)
|
||||
|
||||
GSsetBaseMem( PS2MEM_GS );
|
||||
GSirqCallback( gsIrq );
|
||||
|
||||
m_gsOpened = !GSopen( &pDsp, "PCSX2", 0 );
|
||||
}
|
||||
|
||||
/*if( m_gsOpened )
|
||||
{
|
||||
gsOnModeChanged(
|
||||
(Config.PsxType & 1) ? FRAMERATE_PAL : FRAMERATE_NTSC,
|
||||
UpdateVSyncRate()
|
||||
);
|
||||
}*/
|
||||
|
||||
// FIXME : This is the gs/vsync tie-in for framelimiting, but it really
|
||||
// needs to be called from the hotkey framelimiter enable/disable too.
|
||||
|
||||
if(GSsetFrameLimit == NULL)
|
||||
{
|
||||
DevCon::Notice("Notice: GS Plugin does not implement GSsetFrameLimit.");
|
||||
}
|
||||
else
|
||||
{
|
||||
GSsetFrameLimit( EmuConfig.Video.EnableFrameLimiting );
|
||||
}
|
||||
|
||||
return !m_gsOpened;
|
||||
}
|
||||
|
||||
void gsClose()
|
||||
{
|
||||
if( !m_gsOpened ) return;
|
||||
m_gsOpened = false;
|
||||
safe_delete( mtgsThread );
|
||||
}
|
||||
|
||||
void gsReset()
|
||||
{
|
||||
// Sanity check in case the plugin hasn't been initialized...
|
||||
if( !m_gsOpened ) return;
|
||||
if( mtgsThread == NULL ) return;
|
||||
mtgsThread->Reset();
|
||||
|
||||
gsOnModeChanged(
|
||||
|
|
|
@ -178,7 +178,11 @@ protected:
|
|||
uint m_WritePos; // cur pos ee thread is writing to
|
||||
|
||||
// used to regulate thread startup and gsInit
|
||||
Threading::Semaphore m_post_InitDone;
|
||||
Threading::Semaphore m_sem_InitDone;
|
||||
|
||||
// used for quitting the ringbuffer thread only -- is posted by the ringbuffer when
|
||||
// a QUIT message is processed (signals that the GS has been closed).
|
||||
Threading::Semaphore m_sem_Quitter;
|
||||
|
||||
Threading::MutexLock m_lock_RingRestart;
|
||||
|
||||
|
@ -282,8 +286,7 @@ protected:
|
|||
extern mtgsThreadObject* mtgsThread;
|
||||
|
||||
void mtgsWaitGS();
|
||||
bool mtgsOpen();
|
||||
//void mtgsRingBufSimplePacket( s32 command, u32 data0, u32 data1, u32 data2 );
|
||||
void mtgsOpen();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Generalized GS Functions and Stuff
|
||||
|
|
|
@ -74,8 +74,6 @@ static void execI()
|
|||
opcode.interpret();
|
||||
}
|
||||
|
||||
static bool EventRaised = false;
|
||||
|
||||
static __forceinline void _doBranch_shared(u32 tar)
|
||||
{
|
||||
branch2 = cpuRegs.branch = 1;
|
||||
|
@ -96,7 +94,7 @@ static void __fastcall doBranch( u32 target )
|
|||
_doBranch_shared( target );
|
||||
cpuRegs.cycle += cpuBlockCycles >> 3;
|
||||
cpuBlockCycles &= (1<<3)-1;
|
||||
EventRaised |= intEventTest();
|
||||
intEventTest();
|
||||
}
|
||||
|
||||
void __fastcall intDoBranch(u32 target)
|
||||
|
@ -108,7 +106,7 @@ void __fastcall intDoBranch(u32 target)
|
|||
{
|
||||
cpuRegs.cycle += cpuBlockCycles >> 3;
|
||||
cpuBlockCycles &= (1<<3)-1;
|
||||
EventRaised |= intEventTest();
|
||||
intEventTest();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,10 +369,10 @@ void intReset()
|
|||
branch2 = 0;
|
||||
}
|
||||
|
||||
bool intEventTest()
|
||||
void intEventTest()
|
||||
{
|
||||
// Perform counters, ints, and IOP updates:
|
||||
return _cpuBranchTest_Shared();
|
||||
_cpuBranchTest_Shared();
|
||||
}
|
||||
|
||||
void intExecute()
|
||||
|
@ -384,22 +382,12 @@ void intExecute()
|
|||
// Mem protection should be handled by the caller here so that it can be
|
||||
// done in a more optimized fashion.
|
||||
|
||||
EventRaised = false;
|
||||
|
||||
while( !EventRaised )
|
||||
while( true )
|
||||
{
|
||||
execI();
|
||||
}
|
||||
}
|
||||
|
||||
static void intExecuteBlock()
|
||||
{
|
||||
g_EEFreezeRegs = false;
|
||||
|
||||
branch2 = 0;
|
||||
while (!branch2) execI();
|
||||
}
|
||||
|
||||
static void intStep()
|
||||
{
|
||||
g_EEFreezeRegs = false;
|
||||
|
@ -418,7 +406,6 @@ R5900cpu intCpu = {
|
|||
intReset,
|
||||
intStep,
|
||||
intExecute,
|
||||
intExecuteBlock,
|
||||
intClear,
|
||||
intShutdown
|
||||
};
|
||||
|
|
|
@ -18,9 +18,10 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#include <wx/datetime.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "VU.h"
|
||||
#include "GS.h"
|
||||
|
@ -181,7 +182,7 @@ mtgsThreadObject::mtgsThreadObject() :
|
|||
, m_RingPos( 0 )
|
||||
, m_WritePos( 0 )
|
||||
|
||||
, m_post_InitDone()
|
||||
, m_sem_InitDone()
|
||||
, m_lock_RingRestart()
|
||||
, m_PacketLocker( true ) // true - makes it a recursive lock
|
||||
|
||||
|
@ -204,16 +205,16 @@ mtgsThreadObject::mtgsThreadObject() :
|
|||
|
||||
void mtgsThreadObject::Start()
|
||||
{
|
||||
m_post_InitDone.Reset();
|
||||
m_sem_InitDone.Reset();
|
||||
PersistentThread::Start();
|
||||
|
||||
// Wait for the thread to finish initialization (it runs GSopen, which can take
|
||||
// some time since it's creating a new window and all), and then check for errors.
|
||||
|
||||
m_post_InitDone.Wait();
|
||||
m_sem_InitDone.Wait();
|
||||
|
||||
if( m_returncode != 0 ) // means the thread failed to init the GS plugin
|
||||
throw Exception::PluginFailure( "GS", wxLt("%s plugin initialization failed.") ); // plugin returned an error after having been asked very nicely to initialize itself." );
|
||||
throw Exception::PluginFailure( "GS", wxLt("%s plugin failed to open.") );
|
||||
}
|
||||
|
||||
mtgsThreadObject::~mtgsThreadObject()
|
||||
|
@ -226,7 +227,9 @@ void mtgsThreadObject::Cancel()
|
|||
Console::WriteLn( "MTGS > Closing GS thread..." );
|
||||
SendSimplePacket( GS_RINGTYPE_QUIT, 0, 0, 0 );
|
||||
SetEvent();
|
||||
pthread_join( m_thread, NULL );
|
||||
m_sem_Quitter.Wait( wxTimeSpan( 0, 0, 5, 0 ) );
|
||||
Sleep( 2 );
|
||||
PersistentThread::Cancel( true );
|
||||
}
|
||||
|
||||
void mtgsThreadObject::Reset()
|
||||
|
@ -495,11 +498,7 @@ struct PacketTagType
|
|||
u32 command;
|
||||
u32 data[3];
|
||||
};
|
||||
// Until such time as there is a Gsdx port for Linux, or a Linux plugin needs the functionality,
|
||||
// lets only declare this for Windows.
|
||||
#ifndef __LINUX__
|
||||
extern bool renderswitch;
|
||||
#endif
|
||||
|
||||
sptr mtgsThreadObject::ExecuteTask()
|
||||
{
|
||||
Console::WriteLn("MTGS > Thread Started, Opening GS Plugin...");
|
||||
|
@ -508,18 +507,12 @@ sptr mtgsThreadObject::ExecuteTask()
|
|||
GSsetBaseMem( m_gsMem );
|
||||
GSirqCallback( NULL );
|
||||
|
||||
#ifdef __LINUX__
|
||||
m_returncode = GSopen((void *)&pDsp, "PCSX2", 1);
|
||||
#else
|
||||
//tells GSdx to go into dx9 sw if "renderswitch" is set. Abusing the isMultiThread int
|
||||
//for that so we don't need a new callback
|
||||
m_returncode = GSopen((void *)&pDsp, "PCSX2", renderswitch ? 2 : 1);
|
||||
#endif
|
||||
g_plugins->Open( PluginId_GS );
|
||||
|
||||
Console::WriteLn( "MTGS > GSopen Finished, return code: 0x%x", params m_returncode );
|
||||
|
||||
GSCSRr = 0x551B4000; // 0x55190000
|
||||
m_post_InitDone.Post();
|
||||
m_sem_InitDone.Post();
|
||||
if (m_returncode != 0) { return m_returncode; } // error msg will be issued to the user by Plugins.c
|
||||
|
||||
#ifdef RINGBUF_DEBUG_STACK
|
||||
|
@ -528,7 +521,7 @@ sptr mtgsThreadObject::ExecuteTask()
|
|||
|
||||
while( true )
|
||||
{
|
||||
m_post_event.Wait();
|
||||
m_sem_event.Wait();
|
||||
|
||||
AtomicExchange( m_RingBufferIsBusy, 1 );
|
||||
|
||||
|
@ -675,6 +668,7 @@ sptr mtgsThreadObject::ExecuteTask()
|
|||
|
||||
case GS_RINGTYPE_QUIT:
|
||||
g_plugins->Close( PluginId_GS );
|
||||
m_sem_Quitter.Post();
|
||||
return 0;
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
|
@ -715,7 +709,7 @@ void mtgsThreadObject::WaitGS()
|
|||
// For use in loops that wait on the GS thread to do certain things.
|
||||
void mtgsThreadObject::SetEvent()
|
||||
{
|
||||
m_post_event.Post();
|
||||
m_sem_event.Post();
|
||||
m_CopyCommandTally = 0;
|
||||
m_CopyDataTally = 0;
|
||||
}
|
||||
|
@ -1087,23 +1081,30 @@ void mtgsWaitGS()
|
|||
mtgsThread->WaitGS();
|
||||
}
|
||||
|
||||
bool mtgsOpen()
|
||||
// Exceptions:
|
||||
// ThreadCreationError - Thready could not be created (indicates OS resource limitations)
|
||||
// PluginFailure - GS plugin's "GSopen" call failed.
|
||||
//
|
||||
void mtgsOpen()
|
||||
{
|
||||
// better not be a thread already running, yo!
|
||||
assert( mtgsThread == NULL );
|
||||
if( mtgsThread != NULL ) return;
|
||||
|
||||
mtgsThread = new mtgsThreadObject();
|
||||
|
||||
try
|
||||
{
|
||||
mtgsThread = new mtgsThreadObject();
|
||||
mtgsThread->Start();
|
||||
}
|
||||
catch( Exception::ThreadCreationError& )
|
||||
catch( ... )
|
||||
{
|
||||
Console::Error( "MTGS > Thread creation failed!" );
|
||||
mtgsThread = NULL;
|
||||
return false;
|
||||
// if the thread start fails for any reason then set the handle to null.
|
||||
// The handle is used as a NULL test of thread running status, which is why
|
||||
// we really need to do this. :)
|
||||
safe_delete( mtgsThread );
|
||||
throw;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -83,7 +83,14 @@ void MemoryCard::Load( uint mcd )
|
|||
{
|
||||
// Translation note: detailed description should mention that the memory card will be disabled
|
||||
// for the duration of this session.
|
||||
Msgbox::Alert( wxsFormat( _("Could not load MemoryCard from file: %s"), str.c_str() ) );
|
||||
Msgbox::Alert( pxE( ".Popup:MemoryCard:FailedtoOpen",
|
||||
wxsFormat(
|
||||
L"Could not load or create a MemoryCard from the file:\n\n%s\n\n"
|
||||
L"The MemoryCard in slot %d has been automatically disabled. You can correct the problem\n"
|
||||
L"and re-enable the MemoryCard at any time using Config:MemoryCards from the main menu.",
|
||||
str.c_str(), mcd
|
||||
) )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,7 +113,7 @@ void MemoryCard::Read( uint mcd, u8 *data, u32 adr, int size )
|
|||
|
||||
if( !mcfp.IsOpened() )
|
||||
{
|
||||
DevCon::Error( "MemoryCard > Ignoring attempted read from disabled card." );
|
||||
DevCon::Error( "MemoryCard: Ignoring attempted read from disabled card." );
|
||||
memset(data, 0, size);
|
||||
return;
|
||||
}
|
||||
|
@ -121,7 +128,7 @@ void MemoryCard::Save( uint mcd, const u8 *data, u32 adr, int size )
|
|||
|
||||
if( !mcfp.IsOpened() )
|
||||
{
|
||||
DevCon::Error( "MemoryCard > Ignoring attempted save/write to disabled card." );
|
||||
DevCon::Error( "MemoryCard: Ignoring attempted save/write to disabled card." );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -152,12 +159,12 @@ void MemoryCard::Erase( uint mcd, u32 adr )
|
|||
|
||||
if( !mcfp.IsOpened() )
|
||||
{
|
||||
DevCon::Error( "MemoryCard > Ignoring seek for disabled card." );
|
||||
DevCon::Error( "MemoryCard: Ignoring seek for disabled card." );
|
||||
return;
|
||||
}
|
||||
|
||||
Seek(mcfp, adr);
|
||||
mcfp.Write( data, 528*16 );
|
||||
mcfp.Write( data, sizeof(data) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -172,12 +179,7 @@ void MemoryCard::Create( const wxString& mcdFile )
|
|||
memset8_obj<0xff>( effeffs );
|
||||
|
||||
for( uint i=0; i<16384; i++ )
|
||||
{
|
||||
for( uint j=0; j<528; j++ )
|
||||
fp.Write( effeffs, sizeof(effeffs) );
|
||||
|
||||
//for(j=0; j<16; j++) fputc(enc[j],fp);
|
||||
}
|
||||
}
|
||||
|
||||
u64 MemoryCard::GetCRC( uint mcd )
|
||||
|
|
|
@ -48,7 +48,9 @@ using namespace std;
|
|||
using namespace R5900;
|
||||
|
||||
static int g_Pcsx2Recording = 0; // true 1 if recording video and sound
|
||||
bool renderswitch = 0;
|
||||
|
||||
// renderswitch - tells GSdx to go into dx9 sw if "renderswitch" is set.
|
||||
bool renderswitch = false;
|
||||
|
||||
struct KeyModifiers keymodifiers = {false, false, false, false};
|
||||
|
||||
|
@ -330,7 +332,11 @@ void ProcessFKeys(int fkey, struct KeyModifiers *keymod)
|
|||
case 9: //gsdx "on the fly" renderer switching
|
||||
StateRecovery::MakeGsOnly();
|
||||
g_EmulationInProgress = false;
|
||||
CloseGS();
|
||||
|
||||
// close GS and PAD together, because the PAD depends on the GS window.
|
||||
g_plugins->Close( PluginId_PAD );
|
||||
safe_delete( mtgsThread );
|
||||
|
||||
renderswitch = !renderswitch;
|
||||
StateRecovery::Recover();
|
||||
HostGui::BeginExecution(); // also sets g_EmulationInProgress to true later
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,8 +16,7 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef __PLUGINS_H__
|
||||
#define __PLUGINS_H__
|
||||
#pragma once
|
||||
|
||||
#define PLUGINtypedefs
|
||||
#define PLUGINfuncs
|
||||
|
@ -31,6 +30,11 @@ struct PluginInfo
|
|||
PluginsEnum_t id;
|
||||
int typemask;
|
||||
int version; // minimum version required / supported
|
||||
|
||||
wxString GetShortname() const
|
||||
{
|
||||
return wxString::FromUTF8( shortname );
|
||||
}
|
||||
};
|
||||
|
||||
namespace Exception
|
||||
|
@ -60,6 +64,17 @@ struct LegacyPluginAPI_Common
|
|||
s32 (CALLBACK* Test)();
|
||||
void (CALLBACK* Configure)();
|
||||
void (CALLBACK* About)();
|
||||
|
||||
LegacyPluginAPI_Common() :
|
||||
Init ( NULL )
|
||||
, Close ( NULL )
|
||||
, Shutdown( NULL )
|
||||
, Freeze ( NULL )
|
||||
, Test ( NULL )
|
||||
, Configure( NULL )
|
||||
, About ( NULL )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class SaveState;
|
||||
|
@ -68,39 +83,52 @@ class SaveState;
|
|||
//
|
||||
class PluginManager
|
||||
{
|
||||
DeclareNoncopyableObject( PluginManager )
|
||||
|
||||
protected:
|
||||
struct PluginStatus_t
|
||||
{
|
||||
bool IsInitialized;
|
||||
bool IsOpened;
|
||||
wxString Filename;
|
||||
|
||||
LegacyPluginAPI_Common CommonBindings;
|
||||
wxDynamicLibrary Lib;
|
||||
|
||||
PluginStatus_t() :
|
||||
IsInitialized( false )
|
||||
, IsOpened( false )
|
||||
, Filename()
|
||||
, CommonBindings()
|
||||
, Lib()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
bool m_initialized;
|
||||
bool m_loaded;
|
||||
|
||||
bool m_IsInitialized[PluginId_Count];
|
||||
bool m_IsOpened[PluginId_Count];
|
||||
|
||||
LegacyPluginAPI_Common m_CommonBindings[PluginId_Count];
|
||||
wxDynamicLibrary m_libs[PluginId_Count];
|
||||
PluginStatus_t m_info[PluginId_Count];
|
||||
|
||||
public:
|
||||
~PluginManager();
|
||||
PluginManager() :
|
||||
m_initialized( false )
|
||||
, m_loaded( false )
|
||||
{
|
||||
memzero_obj( m_IsInitialized );
|
||||
memzero_obj( m_IsOpened );
|
||||
}
|
||||
|
||||
void LoadPlugins();
|
||||
void UnloadPlugins();
|
||||
|
||||
void Init( PluginsEnum_t pid );
|
||||
void Shutdown( PluginsEnum_t pid );
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void Open( PluginsEnum_t pid );
|
||||
void Close( PluginsEnum_t pid );
|
||||
void Close();
|
||||
|
||||
void Freeze( PluginsEnum_t pid, int mode, freezeData* data );
|
||||
void Freeze( PluginsEnum_t pid, SaveState& state );
|
||||
void Freeze( SaveState& state );
|
||||
|
||||
friend PluginManager* PluginManager_Create( const wxString (&folders)[PluginId_Count] );
|
||||
friend PluginManager* PluginManager_Create( const wxChar* (&folders)[PluginId_Count] );
|
||||
|
||||
protected:
|
||||
// Internal constructor, should be called by Create only.
|
||||
PluginManager( const wxString (&folders)[PluginId_Count] );
|
||||
|
||||
void BindCommon( PluginsEnum_t pid );
|
||||
void BindRequired( PluginsEnum_t pid );
|
||||
void BindOptional( PluginsEnum_t pid );
|
||||
|
@ -112,16 +140,12 @@ extern PluginManager* g_plugins;
|
|||
extern int EnumeratePluginsInFolder( const wxDirName& searchPath, wxArrayString* dest );
|
||||
|
||||
|
||||
void LoadPlugins();
|
||||
void ReleasePlugins();
|
||||
extern void LoadPlugins();
|
||||
extern void ReleasePlugins();
|
||||
|
||||
void OpenPlugins();
|
||||
void ClosePlugins( bool closegs );
|
||||
void CloseGS();
|
||||
extern void InitPlugins();
|
||||
extern void ShutdownPlugins();
|
||||
|
||||
void InitPlugins();
|
||||
void ShutdownPlugins();
|
||||
extern void OpenPlugins();
|
||||
extern void ClosePlugins( bool closegs );
|
||||
|
||||
void PluginsResetGS();
|
||||
|
||||
#endif /* __PLUGINS_H__ */
|
||||
|
|
|
@ -361,7 +361,7 @@ u32 g_nextBranchCycle = 0;
|
|||
|
||||
// Shared portion of the branch test, called from both the Interpreter
|
||||
// and the recompiler. (moved here to help alleviate redundant code)
|
||||
__forceinline bool _cpuBranchTest_Shared()
|
||||
__forceinline void _cpuBranchTest_Shared()
|
||||
{
|
||||
eeEventTestIsActive = true;
|
||||
g_nextBranchCycle = cpuRegs.cycle + eeWaitCycles;
|
||||
|
@ -373,12 +373,11 @@ __forceinline bool _cpuBranchTest_Shared()
|
|||
iopBranchAction = true;
|
||||
|
||||
// ---- Counters -------------
|
||||
bool vsyncEvent = false;
|
||||
rcntUpdate_hScanline();
|
||||
|
||||
if( cpuTestCycle( nextsCounter, nextCounter ) )
|
||||
{
|
||||
vsyncEvent = rcntUpdate();
|
||||
rcntUpdate();
|
||||
_cpuTestPERF();
|
||||
}
|
||||
|
||||
|
@ -490,8 +489,6 @@ __forceinline bool _cpuBranchTest_Shared()
|
|||
TESTINT(30, intcInterrupt);
|
||||
TESTINT(31, dmacInterrupt);
|
||||
}
|
||||
|
||||
return vsyncEvent;
|
||||
}
|
||||
|
||||
__releaseinline void cpuTestINTCInts()
|
||||
|
@ -572,8 +569,7 @@ void cpuExecuteBios()
|
|||
while( cpuRegs.pc != 0x00200008 &&
|
||||
cpuRegs.pc != 0x00100008 )
|
||||
{
|
||||
g_nextBranchCycle = cpuRegs.cycle;
|
||||
Cpu->ExecuteBlock();
|
||||
Cpu->Execute();
|
||||
}
|
||||
g_ExecBiosHack = false;
|
||||
|
||||
|
|
|
@ -228,7 +228,7 @@ extern bool eeEventTestIsActive;
|
|||
extern u32 s_iLastCOP0Cycle;
|
||||
extern u32 s_iLastPERFCycle[2];
|
||||
|
||||
bool intEventTest();
|
||||
void intEventTest();
|
||||
void intSetBranch();
|
||||
|
||||
// This is a special form of the interpreter's doBranch that is run from various
|
||||
|
@ -243,8 +243,7 @@ struct R5900cpu
|
|||
void (*Allocate)(); // throws exceptions on failure.
|
||||
void (*Reset)();
|
||||
void (*Step)();
|
||||
void (*Execute)(); /* executes up to a break */
|
||||
void (*ExecuteBlock)();
|
||||
void (*Execute)();
|
||||
void (*Clear)(u32 Addr, u32 Size);
|
||||
void (*Shutdown)(); // deallocates memory reserved by Allocate
|
||||
};
|
||||
|
@ -267,7 +266,7 @@ extern void cpuSetNextBranchDelta( s32 delta );
|
|||
extern int cpuTestCycle( u32 startCycle, s32 delta );
|
||||
extern void cpuSetBranch();
|
||||
|
||||
extern bool _cpuBranchTest_Shared(); // for internal use by the Dynarecs and Ints inside R5900:
|
||||
extern void _cpuBranchTest_Shared(); // for internal use by the Dynarecs and Ints inside R5900:
|
||||
|
||||
extern void cpuTestINTCInts();
|
||||
extern void cpuTestDMACInts();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
#include "App.h"
|
||||
#include "IniInterface.h"
|
||||
#include "Plugins.h"
|
||||
|
||||
#include <wx/stdpaths.h>
|
||||
|
||||
|
@ -266,7 +267,7 @@ namespace FilenameDefs
|
|||
wxFileName( L"Mcd002.ps2" )
|
||||
};
|
||||
|
||||
if( IsDevBuild && ((uint)slot) < 2 )
|
||||
if( IsDevBuild && ((uint)slot) >= 2 )
|
||||
throw Exception::IndexBoundsFault( L"FilenameDefs::Memcard", slot, 2 );
|
||||
|
||||
return retval[slot];
|
||||
|
@ -373,6 +374,10 @@ AppConfig::AppConfig() :
|
|||
, EmuOptions()
|
||||
, m_IsLoaded( false )
|
||||
{
|
||||
Mcd[0].Enabled = true;
|
||||
Mcd[1].Enabled = true;
|
||||
Mcd[0].Filename = FilenameDefs::Memcard(0);
|
||||
Mcd[1].Filename = FilenameDefs::Memcard(1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -395,6 +400,17 @@ void AppConfig::LoadSaveUserMode( IniInterface& ini, const wxString& cwdhash )
|
|||
ini.Flush();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void AppConfig::LoadSaveMemcards( IniInterface& ini )
|
||||
{
|
||||
IniScopedGroup path( ini, L"MemoryCards" );
|
||||
|
||||
ini.Entry( L"Slot1Enable", Mcd[0].Enabled, true );
|
||||
ini.Entry( L"Slot2Enable", Mcd[1].Enabled, true );
|
||||
ini.Entry( L"Slot1Filename", Mcd[0].Filename, FilenameDefs::Memcard(0) );
|
||||
ini.Entry( L"Slot2Filename", Mcd[1].Filename, FilenameDefs::Memcard(1) );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void AppConfig::LoadSave( IniInterface& ini )
|
||||
{
|
||||
|
@ -584,22 +600,9 @@ void AppConfig::FilenameOptions::LoadSave( IniInterface& ini )
|
|||
IniScopedGroup path( ini, L"Filenames" );
|
||||
|
||||
static const wxFileName pc( L"Please Configure" );
|
||||
static const wxString g_PluginNames[] =
|
||||
{
|
||||
L"CDVD",
|
||||
L"GS",
|
||||
L"PAD1",
|
||||
L"PAD2",
|
||||
L"SPU2",
|
||||
L"USB",
|
||||
L"FW",
|
||||
L"DEV9"
|
||||
};
|
||||
|
||||
for( int i=0; i<PluginId_Count; ++i )
|
||||
{
|
||||
ini.Entry( g_PluginNames[i], Plugins[i], pc );
|
||||
}
|
||||
ini.Entry( tbl_PluginInfo[i].GetShortname(), Plugins[i], pc );
|
||||
|
||||
ini.Entry( L"BIOS", Bios, pc );
|
||||
}
|
||||
|
|
|
@ -161,6 +161,7 @@ public:
|
|||
|
||||
protected:
|
||||
void LoadSave( IniInterface& ini );
|
||||
void LoadSaveMemcards( IniInterface& ini );
|
||||
};
|
||||
|
||||
class wxFileConfig; // forward declare.
|
||||
|
|
|
@ -451,6 +451,7 @@ namespace Panels
|
|||
void Apply( AppConfig& conf );
|
||||
|
||||
protected:
|
||||
void OnConfigure_Clicked( wxCommandEvent& evt );
|
||||
virtual void OnProgress( wxCommandEvent& evt );
|
||||
virtual void OnEnumComplete( wxCommandEvent& evt );
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ DEFINE_EVENT_TYPE(wxEVT_EnumeratedNext)
|
|||
DEFINE_EVENT_TYPE(wxEVT_EnumerationFinished);
|
||||
|
||||
typedef s32 (CALLBACK* PluginTestFnptr)();
|
||||
typedef void (CALLBACK* PluginConfigureFnptr)();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
@ -154,6 +155,9 @@ void Panels::PluginSelectorPanel::StatusPanel::Reset()
|
|||
m_label.SetLabel( wxEmptyString );
|
||||
}
|
||||
|
||||
// Id for all Configure buttons (any non-negative arbitrary integer will do)
|
||||
static const int ButtonId_Configure = 51;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
Panels::PluginSelectorPanel::ComboBoxPanel::ComboBoxPanel( PluginSelectorPanel* parent ) :
|
||||
wxPanelWithHelpers( parent )
|
||||
|
@ -170,14 +174,16 @@ Panels::PluginSelectorPanel::ComboBoxPanel::ComboBoxPanel( PluginSelectorPanel*
|
|||
for( int i=0; i<NumPluginTypes; ++i )
|
||||
{
|
||||
s_plugin.Add(
|
||||
new wxStaticText( this, wxID_ANY, wxString::FromAscii( tbl_PluginInfo[i].shortname ) ),
|
||||
new wxStaticText( this, wxID_ANY, tbl_PluginInfo[i].GetShortname() ),
|
||||
wxSizerFlags().Border( wxTOP | wxLEFT, 2 )
|
||||
);
|
||||
s_plugin.Add(
|
||||
m_combobox[i] = new wxComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY ),
|
||||
wxSizerFlags().Expand()
|
||||
);
|
||||
s_plugin.Add( new wxButton( this, wxID_ANY, L"Configure..." ) );
|
||||
wxButton* bleh = new wxButton( this, ButtonId_Configure, L"Configure..." );
|
||||
bleh->SetClientData( (void*)(int)tbl_PluginInfo[i].id );
|
||||
s_plugin.Add( bleh );
|
||||
}
|
||||
|
||||
m_FolderPicker.SetStaticDesc( _("Click the Browse button to select a different folder for PCSX2 plugins.") );
|
||||
|
@ -225,6 +231,7 @@ Panels::PluginSelectorPanel::PluginSelectorPanel( wxWindow& parent, int idealWid
|
|||
|
||||
Connect( wxEVT_EnumeratedNext, wxCommandEventHandler( PluginSelectorPanel::OnProgress ) );
|
||||
Connect( wxEVT_EnumerationFinished, wxCommandEventHandler( PluginSelectorPanel::OnEnumComplete ) );
|
||||
Connect( ButtonId_Configure, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PluginSelectorPanel::OnConfigure_Clicked ) );
|
||||
}
|
||||
|
||||
Panels::PluginSelectorPanel::~PluginSelectorPanel()
|
||||
|
@ -239,7 +246,7 @@ void Panels::PluginSelectorPanel::Apply( AppConfig& conf )
|
|||
int sel = m_ComponentBoxes.Get(i).GetSelection();
|
||||
if( sel == wxNOT_FOUND )
|
||||
{
|
||||
wxString plugname( wxString::FromAscii( tbl_PluginInfo[i].shortname ) );
|
||||
wxString plugname( tbl_PluginInfo[i].GetShortname() );
|
||||
|
||||
throw Exception::CannotApplySettings( this,
|
||||
// English Log
|
||||
|
@ -307,6 +314,17 @@ bool Panels::PluginSelectorPanel::ValidateEnumerationStatus()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void Panels::PluginSelectorPanel::OnConfigure_Clicked( wxCommandEvent& evt )
|
||||
{
|
||||
PluginsEnum_t pid = (PluginsEnum_t)(int)evt.GetClientData();
|
||||
|
||||
int sel = m_ComponentBoxes.Get(pid).GetSelection();
|
||||
if( sel == wxNOT_FOUND ) return;
|
||||
wxDynamicLibrary dynlib( (*m_FileList)[(int)m_ComponentBoxes.Get(pid).GetClientData(sel)] );
|
||||
if( PluginConfigureFnptr configfunc = (PluginConfigureFnptr)dynlib.GetSymbol( tbl_PluginInfo[pid].GetShortname() + L"configure" ) )
|
||||
configfunc();
|
||||
}
|
||||
|
||||
void Panels::PluginSelectorPanel::OnEnumComplete( wxCommandEvent& evt )
|
||||
{
|
||||
safe_delete( m_EnumeratorThread );
|
||||
|
|
|
@ -150,6 +150,8 @@ bool Pcsx2App::OnInit()
|
|||
g_Conf = new AppConfig();
|
||||
g_EmuThread = new CoreEmuThread();
|
||||
|
||||
delete wxMessageOutput::Set( new wxMessageOutputDebug() );
|
||||
|
||||
wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
|
||||
|
||||
// User/Admin Mode Dual Setup:
|
||||
|
|
|
@ -27,18 +27,23 @@
|
|||
#include "R3000A.h"
|
||||
#include "VUmicro.h"
|
||||
|
||||
sptr CoreEmuThread::ExecuteTask()
|
||||
{
|
||||
while( !m_Done && (m_ExecMode != ExecMode_Running) )
|
||||
{
|
||||
m_ResumeEvent.Wait();
|
||||
}
|
||||
static __threadlocal CoreEmuThread* tls_coreThread = NULL;
|
||||
|
||||
CoreEmuThread& CoreEmuThread::Get()
|
||||
{
|
||||
wxASSERT_MSG( tls_coreThread != NULL, L"This function must be called from the context of a running CoreEmuThread." );
|
||||
return *tls_coreThread;
|
||||
}
|
||||
|
||||
void CoreEmuThread::CpuInitializeMess()
|
||||
{
|
||||
try
|
||||
{
|
||||
OpenPlugins();
|
||||
cpuReset();
|
||||
SysClearExecutionCache();
|
||||
OpenPlugins();
|
||||
|
||||
GSsetGameCRC( ElfCRC, 0 );
|
||||
|
||||
if( StateRecovery::HasState() )
|
||||
{
|
||||
|
@ -69,9 +74,25 @@ sptr CoreEmuThread::ExecuteTask()
|
|||
{
|
||||
Msgbox::Alert( ex.DisplayMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
sptr CoreEmuThread::ExecuteTask()
|
||||
{
|
||||
tls_coreThread = this;
|
||||
|
||||
while( !m_Done && (m_ExecMode != ExecMode_Running) )
|
||||
{
|
||||
m_ResumeEvent.Wait();
|
||||
}
|
||||
|
||||
CpuInitializeMess();
|
||||
|
||||
StateCheck();
|
||||
|
||||
PCSX2_MEM_PROTECT_BEGIN();
|
||||
Cpu->Execute();
|
||||
PCSX2_MEM_PROTECT_END();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,9 @@ protected:
|
|||
MutexLock m_lock_elf_file;
|
||||
MutexLock m_lock_ExecMode;
|
||||
|
||||
public:
|
||||
static CoreEmuThread& Get();
|
||||
|
||||
public:
|
||||
CoreEmuThread() :
|
||||
m_ExecMode( ExecMode_Idle )
|
||||
|
@ -80,7 +83,9 @@ public:
|
|||
void Resume();
|
||||
void ApplySettings( const Pcsx2Config& src );
|
||||
|
||||
protected:
|
||||
sptr ExecuteTask();
|
||||
void StateCheck();
|
||||
|
||||
protected:
|
||||
void CpuInitializeMess();
|
||||
sptr ExecuteTask();
|
||||
};
|
||||
|
|
|
@ -108,7 +108,7 @@ static u32 dumplog = 0;
|
|||
#define dumplog 0
|
||||
#endif
|
||||
|
||||
static void iBranchTest(u32 newpc = 0xffffffff, bool noDispatch=false);
|
||||
static void iBranchTest(u32 newpc = 0xffffffff);
|
||||
static void ClearRecLUT(BASEBLOCK* base, int count);
|
||||
static u32 eeScaleBlockCycles();
|
||||
|
||||
|
@ -538,7 +538,9 @@ static void recShutdown( void )
|
|||
void recStep( void ) {
|
||||
}
|
||||
|
||||
static __forceinline bool recEventTest()
|
||||
|
||||
|
||||
static void recEventTest()
|
||||
{
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
// dont' remove this check unless doing an official release
|
||||
|
@ -550,13 +552,12 @@ static __forceinline bool recEventTest()
|
|||
assert( !g_globalXMMSaved && !g_globalMMXSaved);
|
||||
#endif
|
||||
|
||||
// Perform counters, ints, and IOP updates:
|
||||
bool retval = _cpuBranchTest_Shared();
|
||||
// Perform counters, interrupts, and IOP updates:
|
||||
_cpuBranchTest_Shared();
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
assert( !g_globalXMMSaved && !g_globalMMXSaved);
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
@ -568,7 +569,7 @@ u32 g_EEDispatchTemp;
|
|||
|
||||
// The address for all cleared blocks. It recompiles the current pc and then
|
||||
// dispatches to the recompiled block address.
|
||||
static __declspec(naked) void JITCompile()
|
||||
static __naked void JITCompile()
|
||||
{
|
||||
__asm {
|
||||
mov esi, dword ptr [cpuRegs.pc]
|
||||
|
@ -582,7 +583,7 @@ static __declspec(naked) void JITCompile()
|
|||
}
|
||||
}
|
||||
|
||||
static __declspec(naked) void JITCompileInBlock()
|
||||
static __naked void JITCompileInBlock()
|
||||
{
|
||||
__asm {
|
||||
jmp JITCompile
|
||||
|
@ -601,12 +602,23 @@ static void __naked DispatcherReg()
|
|||
}
|
||||
}
|
||||
|
||||
// [TODO] : Replace these functions with x86Emitter-generated code and we can compound this
|
||||
// function and DispatcherReg() into a fast fall-through case (removes the DispatcerReg jump
|
||||
// in this function, since execution will just fall right into the DispatcherReg implementation).
|
||||
//
|
||||
static void __naked DispatcherEvent()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
call recEventTest;
|
||||
jmp DispatcherReg;
|
||||
}
|
||||
}
|
||||
|
||||
void recExecute()
|
||||
{
|
||||
// Optimization note : Compared pushad against manually pushing the regs one-by-one.
|
||||
// Manually pushing is faster, especially on Core2's and such. :)
|
||||
do
|
||||
{
|
||||
g_EEFreezeRegs = true;
|
||||
__asm
|
||||
{
|
||||
|
@ -623,29 +635,6 @@ void recExecute()
|
|||
pop ebx
|
||||
}
|
||||
g_EEFreezeRegs = false;
|
||||
}
|
||||
while( !recEventTest() );
|
||||
}
|
||||
|
||||
static void recExecuteBlock()
|
||||
{
|
||||
g_EEFreezeRegs = true;
|
||||
__asm
|
||||
{
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
push ebp
|
||||
|
||||
call DispatcherReg
|
||||
|
||||
pop ebp
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
}
|
||||
g_EEFreezeRegs = false;
|
||||
recEventTest();
|
||||
}
|
||||
|
||||
#else // _MSC_VER
|
||||
|
@ -654,7 +643,6 @@ __forceinline void recExecute()
|
|||
{
|
||||
// Optimization note : Compared pushad against manually pushing the regs one-by-one.
|
||||
// Manually pushing is faster, especially on Core2's and such. :)
|
||||
do {
|
||||
g_EEFreezeRegs = true;
|
||||
__asm__
|
||||
(
|
||||
|
@ -673,32 +661,8 @@ __forceinline void recExecute()
|
|||
".att_syntax\n"
|
||||
);
|
||||
g_EEFreezeRegs = false;
|
||||
}
|
||||
while( !recEventTest() );
|
||||
}
|
||||
|
||||
static void recExecuteBlock()
|
||||
{
|
||||
g_EEFreezeRegs = true;
|
||||
__asm__
|
||||
(
|
||||
".intel_syntax noprefix\n"
|
||||
"push ebx\n"
|
||||
"push esi\n"
|
||||
"push edi\n"
|
||||
"push ebp\n"
|
||||
|
||||
"call DispatcherReg\n"
|
||||
|
||||
"pop ebp\n"
|
||||
"pop edi\n"
|
||||
"pop esi\n"
|
||||
"pop ebx\n"
|
||||
".att_syntax\n"
|
||||
);
|
||||
g_EEFreezeRegs = false;
|
||||
recEventTest();
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace R5900 {
|
||||
|
@ -1038,10 +1002,10 @@ static u32 eeScaleBlockCycles()
|
|||
// jump is assumed to be static, in which case the block will be "hardlinked" after
|
||||
// the first time it's dispatched.
|
||||
//
|
||||
// noDispatch - When set true, the jump to Dispatcher. Used by the recs
|
||||
// noDispatch - When set true, then jump to Dispatcher. Used by the recs
|
||||
// for blocks which perform exception checks without branching (it's enabled by
|
||||
// setting "branch = 2";
|
||||
static void iBranchTest(u32 newpc, bool noDispatch)
|
||||
static void iBranchTest(u32 newpc)
|
||||
{
|
||||
if( g_ExecBiosHack ) CheckForBIOSEnd();
|
||||
|
||||
|
@ -1050,13 +1014,46 @@ static void iBranchTest(u32 newpc, bool noDispatch)
|
|||
// cpuRegs.cycle += blockcycles;
|
||||
// if( cpuRegs.cycle > g_nextBranchCycle ) { DoEvents(); }
|
||||
|
||||
if (EmuConfig.Speedhacks.BIFC0 && s_nBlockFF) {
|
||||
if (EmuConfig.Speedhacks.BIFC0 && s_nBlockFF)
|
||||
{
|
||||
xMOV(eax, ptr32[&g_nextBranchCycle]);
|
||||
xADD(ptr32[&cpuRegs.cycle], eeScaleBlockCycles());
|
||||
xCMP(eax, ptr32[&cpuRegs.cycle]);
|
||||
xCMOVL(eax, ptr32[&cpuRegs.cycle]);
|
||||
xMOV(ptr32[&cpuRegs.cycle], eax);
|
||||
} else {
|
||||
|
||||
xJMP( DispatcherEvent );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Optimization -- we need to load cpuRegs.pc on static block links, but doing it inside
|
||||
// the if() block below (it would be paired with recBlocks.Link) breaks the sub/jcc
|
||||
// pairing that modern CPUs optimize (applies to all P4+ and AMD X2+ CPUs). So let's do
|
||||
// it up here instead. :D
|
||||
|
||||
if( newpc != 0xffffffff )
|
||||
xMOV( ptr32[&cpuRegs.pc], newpc );
|
||||
|
||||
xMOV(eax, &cpuRegs.cycle);
|
||||
xADD(eax, eeScaleBlockCycles());
|
||||
xMOV(&cpuRegs.cycle, eax); // update cycles
|
||||
xSUB(eax, &g_nextBranchCycle);
|
||||
|
||||
if (newpc == 0xffffffff)
|
||||
{
|
||||
xJNS( DispatcherEvent );
|
||||
xJMP( DispatcherReg );
|
||||
}
|
||||
else
|
||||
{
|
||||
recBlocks.Link( HWADDR(newpc), xJcc32( Jcc_Signed ) );
|
||||
xJMP( DispatcherEvent );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
else
|
||||
{
|
||||
xMOV(eax, &cpuRegs.cycle);
|
||||
xADD(eax, eeScaleBlockCycles());
|
||||
xMOV(&cpuRegs.cycle, eax); // update cycles
|
||||
|
@ -1072,7 +1069,10 @@ static void iBranchTest(u32 newpc, bool noDispatch)
|
|||
}
|
||||
}
|
||||
}
|
||||
xRET();
|
||||
xCALL( recEventTest );
|
||||
xJMP( DispatcherReg );
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
static void checkcodefn()
|
||||
|
@ -1622,7 +1622,7 @@ StartRecomp:
|
|||
// for actual branching instructions.
|
||||
|
||||
iFlushCall(FLUSH_EVERYTHING);
|
||||
iBranchTest(0xffffffff, true);
|
||||
iBranchTest();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1671,7 +1671,6 @@ R5900cpu recCpu = {
|
|||
recResetEE,
|
||||
recStep,
|
||||
recExecute,
|
||||
recExecuteBlock,
|
||||
recClear,
|
||||
recShutdown
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue