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:
Jake.Stine 2009-08-25 15:38:48 +00:00
parent 307346e19e
commit 9303bc5bf2
25 changed files with 620 additions and 972 deletions

View File

@ -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);

View File

@ -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();

View File

@ -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

View File

@ -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 );

View File

@ -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,

View File

@ -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)
@ -449,8 +450,8 @@ __forceinline bool rcntUpdate_vSync()
vsyncCounter.sCycle += vSyncInfo.Blank;
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) )
{

View File

@ -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);

View File

@ -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(

View File

@ -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

View File

@ -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
};

View File

@ -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...");
@ -507,19 +506,13 @@ sptr mtgsThreadObject::ExecuteTask()
memcpy_aligned( m_gsMem, PS2MEM_GS, sizeof(PS2MEM_GS) );
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;
}

View File

@ -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);
}
fp.Write( effeffs, sizeof(effeffs) );
}
u64 MemoryCard::GetCRC( uint mcd )

View File

@ -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

View File

@ -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__ */

View File

@ -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;

View File

@ -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();

View File

@ -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 );
}

View File

@ -161,6 +161,7 @@ public:
protected:
void LoadSave( IniInterface& ini );
void LoadSaveMemcards( IniInterface& ini );
};
class wxFileConfig; // forward declare.

View File

@ -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 );

View File

@ -36,7 +36,8 @@ END_DECLARE_EVENT_TYPES()
DEFINE_EVENT_TYPE(wxEVT_EnumeratedNext)
DEFINE_EVENT_TYPE(wxEVT_EnumerationFinished);
typedef s32 (CALLBACK* PluginTestFnptr)();
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 );

View File

@ -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:

View File

@ -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;
}

View File

@ -50,7 +50,10 @@ 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();
};

View File

@ -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,34 +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
{
push ebx
push esi
push edi
push ebp
call DispatcherReg
pop ebp
pop edi
pop esi
pop ebx
}
g_EEFreezeRegs = false;
}
while( !recEventTest() );
}
static void recExecuteBlock()
{
g_EEFreezeRegs = true;
__asm
{
@ -638,14 +628,13 @@ static void recExecuteBlock()
push ebp
call DispatcherReg
pop ebp
pop edi
pop esi
pop ebx
}
g_EEFreezeRegs = false;
recEventTest();
}
#else // _MSC_VER
@ -654,31 +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__
(
".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;
}
while( !recEventTest() );
}
static void recExecuteBlock()
{
g_EEFreezeRegs = true;
__asm__
(
@ -689,7 +653,7 @@ static void recExecuteBlock()
"push ebp\n"
"call DispatcherReg\n"
"pop ebp\n"
"pop edi\n"
"pop esi\n"
@ -697,8 +661,8 @@ static void recExecuteBlock()
".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
};