mirror of https://github.com/PCSX2/pcsx2.git
wxgui:
* Major cleanups and improvements to the Threading namespace. * Created CoreEmuThread class framework, which currently runs the EEcore, IOP, and VUs with threadsafe suspension, reset, and resume features. git-svn-id: http://pcsx2.googlecode.com/svn/branches/wxgui@1624 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
3544bcd118
commit
c415d8d694
|
@ -570,19 +570,14 @@ typedef struct _ptw32_handle_t {
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
// Added support for various operators so that the struct is
|
// Added support for various operators so that the struct is
|
||||||
// more pthreads-compliant in behavior. (air)
|
// more pthreads-compliant in behavior. (air)
|
||||||
const bool operator ==( const void* rightside )
|
const bool operator ==( const struct _ptw32_handle_t rightside ) const
|
||||||
{
|
{
|
||||||
return p == rightside;
|
return p == rightside.p;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool operator !=( const void* rightside )
|
const bool operator !=( const struct _ptw32_handle_t rightside ) const
|
||||||
{
|
{
|
||||||
return p != rightside;
|
return p != rightside.p;
|
||||||
}
|
|
||||||
|
|
||||||
bool operator =( void* rightside )
|
|
||||||
{
|
|
||||||
p = rightside;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -354,12 +354,16 @@ namespace Exception
|
||||||
explicit CreateStream(
|
explicit CreateStream(
|
||||||
const char* objname,
|
const char* objname,
|
||||||
const char* msg=wxLt("File could not be created or opened") ) :
|
const char* msg=wxLt("File could not be created or opened") ) :
|
||||||
Stream( wxString::FromAscii( objname ), msg ) {}
|
Stream( wxString::FromAscii( objname ), msg ) {}
|
||||||
|
|
||||||
explicit CreateStream(
|
explicit CreateStream(
|
||||||
const wxString& objname=wxString(),
|
const wxString& objname=wxString(),
|
||||||
const char* msg=wxLt("File could not be created or opened") ) :
|
const char* msg=wxLt("File could not be created or opened") ) :
|
||||||
Stream( objname, msg ) {}
|
Stream( objname, msg ) {}
|
||||||
|
|
||||||
|
explicit CreateStream(
|
||||||
|
const wxString& objname, const wxString& msg_eng, const wxString& msg_xlt ) :
|
||||||
|
Stream( objname, msg_eng, msg_xlt ) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Exception thrown when an attempt to open a non-existent file is made.
|
// Exception thrown when an attempt to open a non-existent file is made.
|
||||||
|
@ -373,8 +377,11 @@ namespace Exception
|
||||||
explicit FileNotFound(
|
explicit FileNotFound(
|
||||||
const wxString& objname=wxString(),
|
const wxString& objname=wxString(),
|
||||||
const char* msg="File not found" ) :
|
const char* msg="File not found" ) :
|
||||||
|
CreateStream( objname, msg ) {}
|
||||||
|
|
||||||
|
explicit FileNotFound( const wxString& objname, const wxString& msg_eng, const wxString& msg_xlt ) :
|
||||||
|
CreateStream( objname, msg_eng, msg_xlt ) {}
|
||||||
|
|
||||||
CreateStream( objname, msg ) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AccessDenied : public CreateStream
|
class AccessDenied : public CreateStream
|
||||||
|
|
|
@ -24,9 +24,28 @@
|
||||||
|
|
||||||
#include "Pcsx2Defs.h"
|
#include "Pcsx2Defs.h"
|
||||||
|
|
||||||
|
namespace Exception
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Thread termination exception, used to quickly terminate threads from anywhere in the
|
||||||
|
// thread's call stack. This exception is handled by the PCSX2 PersistentThread class. Threads
|
||||||
|
// not derived from that class will not handle this exception.
|
||||||
|
//
|
||||||
|
class ThreadTermination : public BaseException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~ThreadTermination() throw() {}
|
||||||
|
|
||||||
|
ThreadTermination( const ThreadTermination& src ) : BaseException( src ) {}
|
||||||
|
|
||||||
|
explicit ThreadTermination() :
|
||||||
|
BaseException( "Thread terminated" ) { }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace Threading
|
namespace Threading
|
||||||
{
|
{
|
||||||
///////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Define some useful object handles - wait events, mutexes.
|
// Define some useful object handles - wait events, mutexes.
|
||||||
|
|
||||||
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
|
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
|
||||||
|
@ -56,7 +75,8 @@ namespace Threading
|
||||||
void Post();
|
void Post();
|
||||||
void Post( int multiple );
|
void Post( int multiple );
|
||||||
void Wait();
|
void Wait();
|
||||||
int Count();
|
void WaitNoCancel();
|
||||||
|
int Count();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MutexLock
|
struct MutexLock
|
||||||
|
@ -84,42 +104,42 @@ namespace Threading
|
||||||
extern void Sleep( int ms );
|
extern void Sleep( int ms );
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Thread - Helper class for the basics of starting/managing simple threads.
|
// 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 Callback()'
|
// Use this as a base class for your threaded procedure, and implement the 'int ExecuteTask()'
|
||||||
// method. Use Start() and Close() 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_post_event
|
||||||
// internally to post/receive events for the thread (make a public accessor for it in your
|
// internally to post/receive events for the thread (make a public accessor for it in your
|
||||||
// derived class if your thread utilizes the post).
|
// derived class if your thread utilizes the post).
|
||||||
//
|
//
|
||||||
// Notes:
|
// Notes:
|
||||||
// * To ensure thread safety against C++'s bizarre and not-thread-friendly object
|
|
||||||
// constructors and destructors, you *must* use Start() and Close(). There is a built-
|
|
||||||
// in Close() called on destruction, which should work for very simple threads (that
|
|
||||||
// do not have any special shutdown code of their own), but
|
|
||||||
//
|
|
||||||
// * Constructing threads as static vars isn't recommended since it can potentially con-
|
// * Constructing threads as static vars isn't recommended since it can potentially con-
|
||||||
// fuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
|
// fuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
|
||||||
// no dependency options for ensuring correct static var initializations).
|
// no dependency options for ensuring correct static var initializations). Use heap
|
||||||
|
// allocation to create thread objects instead.
|
||||||
//
|
//
|
||||||
class Thread : NoncopyableObject
|
class PersistentThread : NoncopyableObject
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
typedef int (*PlainJoeFP)();
|
typedef int (*PlainJoeFP)();
|
||||||
pthread_t m_thread;
|
pthread_t m_thread;
|
||||||
int m_returncode; // value returned from the thread on close.
|
sptr m_returncode; // value returned from the thread on close.
|
||||||
bool m_terminated; // set true after the thread has been closed.
|
|
||||||
Semaphore m_post_event; // general wait event that's needed by most threads.
|
bool m_running;
|
||||||
|
Semaphore m_post_event; // general wait event that's needed by most threads.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~Thread();
|
virtual ~PersistentThread();
|
||||||
Thread();
|
PersistentThread();
|
||||||
|
|
||||||
virtual void Start();
|
virtual void Start();
|
||||||
virtual void Close();
|
virtual void Cancel( bool isBlocking = true );
|
||||||
|
|
||||||
// Gets the return code of the thread.
|
// Gets the return code of the thread.
|
||||||
// Throws std::logic_error if the thread has not terminated.
|
// Throws std::logic_error if the thread has not terminated.
|
||||||
int GetReturnCode() const;
|
virtual int GetReturnCode() const;
|
||||||
|
|
||||||
|
virtual bool IsRunning() const;
|
||||||
|
virtual sptr Block();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Used to dispatch the thread callback function.
|
// Used to dispatch the thread callback function.
|
||||||
|
@ -128,7 +148,20 @@ namespace Threading
|
||||||
static void* _internal_callback( void* func );
|
static void* _internal_callback( void* func );
|
||||||
|
|
||||||
// Implemented by derived class to handle threading actions!
|
// Implemented by derived class to handle threading actions!
|
||||||
virtual int Callback()=0;
|
virtual sptr ExecuteTask()=0;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Static Methods (PersistentThread)
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
public:
|
||||||
|
// performs a test on the given thread handle, returning true if the thread exists
|
||||||
|
// or false if the thread is dead/done/never existed.
|
||||||
|
static bool Exists( pthread_t pid )
|
||||||
|
{
|
||||||
|
// passing 0 to pthread_kill is a NOP, and returns the status of the thread only.
|
||||||
|
return ( ESRCH != pthread_kill( pid, 0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -136,22 +169,41 @@ namespace Threading
|
||||||
// Using this class provides an exception-safe (and generally clean) method of locking
|
// Using this class provides an exception-safe (and generally clean) method of locking
|
||||||
// code inside a function or conditional block.
|
// code inside a function or conditional block.
|
||||||
//
|
//
|
||||||
class ScopedLock : NoncopyableObject
|
class ScopedLock : public NoncopyableObject
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
MutexLock& m_lock;
|
MutexLock& m_lock;
|
||||||
|
bool m_IsLocked;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~ScopedLock()
|
virtual ~ScopedLock()
|
||||||
{
|
{
|
||||||
m_lock.Unlock();
|
if( m_IsLocked )
|
||||||
|
m_lock.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedLock( MutexLock& locker ) :
|
ScopedLock( MutexLock& locker ) :
|
||||||
m_lock( locker )
|
m_lock( locker )
|
||||||
|
, m_IsLocked( true )
|
||||||
{
|
{
|
||||||
m_lock.Lock();
|
m_lock.Lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Provides manual unlocking of a scoped lock prior to object destruction.
|
||||||
|
void Unlock()
|
||||||
|
{
|
||||||
|
if( !m_IsLocked ) return;
|
||||||
|
m_IsLocked = false;
|
||||||
|
m_lock.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
|
||||||
|
void Lock()
|
||||||
|
{
|
||||||
|
if( m_IsLocked ) return;
|
||||||
|
m_lock.Lock();
|
||||||
|
m_IsLocked = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -187,49 +239,49 @@ namespace Threading
|
||||||
// into smaller sections. For example, if you have 20,000 items to process, the task
|
// into smaller sections. For example, if you have 20,000 items to process, the task
|
||||||
// can be divided into two threads of 10,000 items each.
|
// can be divided into two threads of 10,000 items each.
|
||||||
//
|
//
|
||||||
class BaseTaskThread : public Thread
|
class BaseTaskThread : public PersistentThread
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
volatile bool m_done;
|
volatile bool m_Done;
|
||||||
volatile bool m_TaskComplete;
|
volatile bool m_TaskComplete;
|
||||||
|
Semaphore m_post_TaskComplete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~BaseTaskThread() {}
|
virtual ~BaseTaskThread() {}
|
||||||
BaseTaskThread() :
|
BaseTaskThread() :
|
||||||
m_done( false )
|
m_Done( false )
|
||||||
, m_TaskComplete( false )
|
, m_TaskComplete( false )
|
||||||
|
, m_post_TaskComplete()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tells the thread to exit and then waits for thread termination.
|
// Tells the thread to exit and then waits for thread termination.
|
||||||
// To force-terminate the thread without "nicely" waiting for the task to complete,
|
sptr Block()
|
||||||
// explicitly use the Thread::Close parent implementation instead.
|
|
||||||
void Close()
|
|
||||||
{
|
{
|
||||||
if( m_terminated ) return;
|
if( !m_running ) return m_returncode;
|
||||||
m_done = true;
|
m_Done = true;
|
||||||
m_post_event.Post();
|
m_post_event.Post();
|
||||||
pthread_join( m_thread, NULL );
|
return PersistentThread::Block();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initiates the new task. This should be called after your own StartTask has
|
// Initiates the new task. This should be called after your own StartTask has
|
||||||
// initialized internal variables / preparations for task execution.
|
// initialized internal variables / preparations for task execution.
|
||||||
void PostTask()
|
void PostTask()
|
||||||
{
|
{
|
||||||
jASSUME( !m_terminated );
|
jASSUME( m_running );
|
||||||
m_TaskComplete = false;
|
m_TaskComplete = false;
|
||||||
|
m_post_TaskComplete.Reset();
|
||||||
m_post_event.Post();
|
m_post_event.Post();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blocks current thread execution pending the completion of the parallel task.
|
// Blocks current thread execution pending the completion of the parallel task.
|
||||||
void WaitForResult() const
|
void WaitForResult()
|
||||||
{
|
{
|
||||||
if( m_terminated ) return;
|
if( !m_running ) return;
|
||||||
while( !m_TaskComplete )
|
if( !m_TaskComplete )
|
||||||
{
|
m_post_TaskComplete.Wait();
|
||||||
Timeslice();
|
else
|
||||||
SpinWait();
|
m_post_TaskComplete.Reset();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -237,18 +289,19 @@ namespace Threading
|
||||||
// all your necessary processing work here.
|
// all your necessary processing work here.
|
||||||
virtual void Task()=0;
|
virtual void Task()=0;
|
||||||
|
|
||||||
int Callback()
|
sptr ExecuteTask()
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// Wait for a job!
|
// Wait for a job!
|
||||||
m_post_event.Wait();
|
m_post_event.Wait();
|
||||||
|
|
||||||
if( m_done ) break;
|
if( m_Done ) break;
|
||||||
Task();
|
Task();
|
||||||
m_TaskComplete = true;
|
m_TaskComplete = true;
|
||||||
} while( !m_done );
|
m_post_TaskComplete.Post();
|
||||||
|
} while( !m_Done );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -80,7 +80,7 @@ namespace Exception
|
||||||
|
|
||||||
wxString Stream::DisplayMessage() const
|
wxString Stream::DisplayMessage() const
|
||||||
{
|
{
|
||||||
return m_message + L"\n" + StreamName.c_str();
|
return m_message + L"\n\n" + StreamName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
|
@ -65,15 +65,4 @@ namespace Threading
|
||||||
// performance hint and isn't required).
|
// performance hint and isn't required).
|
||||||
__asm__ ( "pause" );
|
__asm__ ( "pause" );
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Thread::_internal_callback( void* itsme )
|
|
||||||
{
|
|
||||||
jASSUME( itsme != NULL );
|
|
||||||
|
|
||||||
Thread& owner = *((Thread*)itsme);
|
|
||||||
owner.m_returncode = owner.Callback();
|
|
||||||
owner.m_terminated = true;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,40 +23,94 @@ using namespace Threading;
|
||||||
|
|
||||||
namespace Threading
|
namespace Threading
|
||||||
{
|
{
|
||||||
Thread::Thread() :
|
PersistentThread::PersistentThread() :
|
||||||
m_thread()
|
m_thread()
|
||||||
, m_returncode( 0 )
|
, m_returncode( 0 )
|
||||||
, m_terminated( false )
|
, m_running( false )
|
||||||
, m_post_event()
|
, m_post_event()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread::~Thread()
|
// Perform a blocking termination of the thread, to ensure full object cleanup.
|
||||||
|
PersistentThread::~PersistentThread()
|
||||||
{
|
{
|
||||||
Close();
|
Cancel( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::Start()
|
void PersistentThread::Start()
|
||||||
{
|
{
|
||||||
m_terminated = false;
|
|
||||||
if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 )
|
if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 )
|
||||||
throw Exception::ThreadCreationError();
|
throw Exception::ThreadCreationError();
|
||||||
|
|
||||||
|
m_running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::Close()
|
// Remarks:
|
||||||
|
// Provision of non-blocking Cancel() is probably academic, since destroying a PersistentThread
|
||||||
|
// object performs a blocking Cancel regardless of if you explicitly do a non-blocking Cancel()
|
||||||
|
// prior, since the ExecuteTask() method requires a valid object state. If you really need
|
||||||
|
// fire-and-forget behavior on threads, use pthreads directly for now.
|
||||||
|
// (TODO : make a DetachedThread class?)
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// isBlocking - indicates if the Cancel action should block for thread completion or not.
|
||||||
|
//
|
||||||
|
void PersistentThread::Cancel( bool isBlocking )
|
||||||
{
|
{
|
||||||
if( !m_terminated )
|
if( !m_running ) return;
|
||||||
pthread_cancel( m_thread );
|
m_running = false;
|
||||||
pthread_join( m_thread, NULL );
|
|
||||||
|
pthread_cancel( m_thread );
|
||||||
|
if( isBlocking )
|
||||||
|
pthread_join( m_thread, (void**)&m_returncode );
|
||||||
|
else
|
||||||
|
pthread_detach( m_thread );
|
||||||
}
|
}
|
||||||
|
|
||||||
int Thread::GetReturnCode() const
|
// Blocks execution of the calling thread until this thread completes its task. The
|
||||||
|
// caller should make sure to signal the thread to exit, or else blocking may deadlock the
|
||||||
|
// calling thread. Classes which extend PersistentThread should override this method
|
||||||
|
// and signal any necessary thread exit variables prior to blocking.
|
||||||
|
//
|
||||||
|
// Returns the return code of the thread.
|
||||||
|
// This method is roughly the equivalent of pthread_join().
|
||||||
|
//
|
||||||
|
sptr PersistentThread::Block()
|
||||||
{
|
{
|
||||||
if( !m_terminated )
|
bool isOwner = (pthread_self() == m_thread);
|
||||||
throw std::logic_error( "Thread is still running. No return code is available." );
|
DevAssert( !isOwner, "Thread deadlock detected; Block() should never be called by the owner thread." );
|
||||||
|
|
||||||
|
pthread_join( m_thread, (void**)&m_returncode );
|
||||||
|
return m_returncode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PersistentThread::IsRunning() const
|
||||||
|
{
|
||||||
|
return ( m_running && (ESRCH != pthread_kill( m_thread, 0 )) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exceptions:
|
||||||
|
// InvalidOperation - thrown if the thread is still running or has never been started.
|
||||||
|
//
|
||||||
|
sptr PersistentThread::GetReturnCode() const
|
||||||
|
{
|
||||||
|
if( !m_running )
|
||||||
|
throw Exception::InvalidOperation( "Thread.GetReturnCode : thread has not been started." );
|
||||||
|
|
||||||
|
if( IsRunning() )
|
||||||
|
throw Exception::InvalidOperation( "Thread.GetReturnCode : thread is still running." );
|
||||||
|
|
||||||
return m_returncode;
|
return m_returncode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* PersistentThread::_internal_callback( void* itsme )
|
||||||
|
{
|
||||||
|
jASSUME( itsme != NULL );
|
||||||
|
|
||||||
|
PersistentThread& owner = *((PersistentThread*)itsme);
|
||||||
|
owner.m_returncode = owner.ExecuteTask();
|
||||||
|
return (void*)owner.m_returncode;
|
||||||
|
}
|
||||||
|
|
||||||
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
|
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
|
||||||
// Let's not use it. (Air)
|
// Let's not use it. (Air)
|
||||||
|
@ -123,6 +177,22 @@ namespace Threading
|
||||||
sem_wait( &sema );
|
sem_wait( &sema );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
// to do a lot of no-cancel waits in a tight loop worker thread, for example.
|
||||||
|
void Semaphore::WaitNoCancel()
|
||||||
|
{
|
||||||
|
int oldstate;
|
||||||
|
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate );
|
||||||
|
Wait();
|
||||||
|
pthread_setcancelstate( oldstate, NULL );
|
||||||
|
}
|
||||||
|
|
||||||
int Semaphore::Count()
|
int Semaphore::Count()
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
|
@ -72,20 +72,5 @@ namespace Threading
|
||||||
{
|
{
|
||||||
__asm { pause };
|
__asm { pause };
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Thread::_internal_callback( void* itsme )
|
|
||||||
{
|
|
||||||
jASSUME( itsme != NULL );
|
|
||||||
|
|
||||||
//pthread_win32_thread_attach_np();
|
|
||||||
|
|
||||||
Thread& owner = *((Thread*)itsme);
|
|
||||||
owner.m_returncode = owner.Callback();
|
|
||||||
owner.m_terminated = true;
|
|
||||||
|
|
||||||
//pthread_win32_thread_detach_np();
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -526,7 +526,7 @@ void cdvdDetectDisk()
|
||||||
cdvd.Type = DoCDVDdetectDiskType();
|
cdvd.Type = DoCDVDdetectDiskType();
|
||||||
|
|
||||||
wxString str;
|
wxString str;
|
||||||
int result = GetPS2ElfName(str);
|
GetPS2ElfName(str);
|
||||||
|
|
||||||
// Now's a good time to reload the ELF info...
|
// Now's a good time to reload the ELF info...
|
||||||
if( ElfCRC == 0 )
|
if( ElfCRC == 0 )
|
||||||
|
|
220
pcsx2/Config.h
220
pcsx2/Config.h
|
@ -32,6 +32,14 @@ enum PluginsEnum_t
|
||||||
PluginId_Count
|
PluginId_Count
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This macro is actually useful for about any and every possible application of C++
|
||||||
|
// equality operators.
|
||||||
|
#define OpEqu( field ) (field == right.field)
|
||||||
|
|
||||||
|
//------------ DEFAULT sseMXCSR VALUES ---------------
|
||||||
|
#define DEFAULT_sseMXCSR 0xffc0 //FPU rounding > DaZ, FtZ, "chop"
|
||||||
|
#define DEFAULT_sseVUMXCSR 0xffc0 //VU rounding > DaZ, FtZ, "chop"
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Pcsx2Config
|
// Pcsx2Config
|
||||||
//
|
//
|
||||||
|
@ -50,28 +58,56 @@ class Pcsx2Config
|
||||||
public:
|
public:
|
||||||
struct ProfilerOptions
|
struct ProfilerOptions
|
||||||
{
|
{
|
||||||
bool
|
union
|
||||||
Enabled:1, // universal toggle for the profiler.
|
{
|
||||||
RecBlocks_EE:1, // Enables per-block profiling for the EE recompiler [unimplemented]
|
struct
|
||||||
RecBlocks_IOP:1, // Enables per-block profiling for the IOP recompiler [unimplemented]
|
{
|
||||||
RecBlocks_VU0:1, // Enables per-block profiling for the VU0 recompiler [unimplemented]
|
bool
|
||||||
RecBlocks_VU1:1; // Enables per-block profiling for the VU1 recompiler [unimplemented]
|
Enabled:1, // universal toggle for the profiler.
|
||||||
|
RecBlocks_EE:1, // Enables per-block profiling for the EE recompiler [unimplemented]
|
||||||
|
RecBlocks_IOP:1, // Enables per-block profiling for the IOP recompiler [unimplemented]
|
||||||
|
RecBlocks_VU0:1, // Enables per-block profiling for the VU0 recompiler [unimplemented]
|
||||||
|
RecBlocks_VU1:1; // Enables per-block profiling for the VU1 recompiler [unimplemented]
|
||||||
|
};
|
||||||
|
u8 bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
ProfilerOptions() : bits( 0 ) {}
|
||||||
|
|
||||||
void LoadSave( IniInterface& conf );
|
void LoadSave( IniInterface& conf );
|
||||||
|
|
||||||
|
bool operator ==( const ProfilerOptions& right ) const
|
||||||
|
{
|
||||||
|
return OpEqu( bits );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator !=( const ProfilerOptions& right ) const
|
||||||
|
{
|
||||||
|
return !this->operator ==( right );
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
struct RecompilerOptions
|
struct RecompilerOptions
|
||||||
{
|
{
|
||||||
bool
|
union
|
||||||
EnableEE:1,
|
{
|
||||||
EnableIOP:1,
|
struct
|
||||||
EnableVU0:1,
|
{
|
||||||
EnableVU1:1;
|
bool
|
||||||
|
EnableEE:1,
|
||||||
bool
|
EnableIOP:1,
|
||||||
UseMicroVU0:1,
|
EnableVU0:1,
|
||||||
UseMicroVU1:1;
|
EnableVU1:1;
|
||||||
|
|
||||||
|
bool
|
||||||
|
UseMicroVU0:1,
|
||||||
|
UseMicroVU1:1;
|
||||||
|
};
|
||||||
|
u8 bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
RecompilerOptions() : bits( 0 ) { }
|
||||||
|
|
||||||
void Load( const wxString& srcfile );
|
void Load( const wxString& srcfile );
|
||||||
void Load( const wxInputStream& srcstream );
|
void Load( const wxInputStream& srcstream );
|
||||||
|
@ -80,29 +116,64 @@ public:
|
||||||
|
|
||||||
void LoadSave( IniInterface& conf );
|
void LoadSave( IniInterface& conf );
|
||||||
|
|
||||||
|
bool operator ==( const RecompilerOptions& right ) const
|
||||||
|
{
|
||||||
|
return OpEqu( bits );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator !=( const RecompilerOptions& right ) const
|
||||||
|
{
|
||||||
|
return !this->operator ==( right );
|
||||||
|
}
|
||||||
|
|
||||||
} Recompiler;
|
} Recompiler;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
struct CpuOptions
|
struct CpuOptions
|
||||||
{
|
{
|
||||||
|
RecompilerOptions Recompiler;
|
||||||
|
|
||||||
u32 sseMXCSR;
|
u32 sseMXCSR;
|
||||||
u32 sseVUMXCSR;
|
u32 sseVUMXCSR;
|
||||||
|
|
||||||
bool
|
struct
|
||||||
vuOverflow:1,
|
{
|
||||||
vuExtraOverflow:1,
|
union
|
||||||
vuSignOverflow:1,
|
{
|
||||||
vuUnderflow:1;
|
bool
|
||||||
|
vuOverflow:1,
|
||||||
bool
|
vuExtraOverflow:1,
|
||||||
fpuOverflow:1,
|
vuSignOverflow:1,
|
||||||
fpuExtraOverflow:1,
|
vuUnderflow:1;
|
||||||
fpuFullMode:1;
|
|
||||||
|
bool
|
||||||
|
fpuOverflow:1,
|
||||||
|
fpuExtraOverflow:1,
|
||||||
|
fpuFullMode:1;
|
||||||
|
};
|
||||||
|
u8 bits;
|
||||||
|
};
|
||||||
|
|
||||||
ProfilerOptions Profiler;
|
CpuOptions() :
|
||||||
RecompilerOptions Recompiler;
|
sseMXCSR( DEFAULT_sseMXCSR )
|
||||||
|
, sseVUMXCSR( DEFAULT_sseVUMXCSR )
|
||||||
|
, bits( 0 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void LoadSave( IniInterface& conf );
|
void LoadSave( IniInterface& conf );
|
||||||
|
|
||||||
|
bool operator ==( const CpuOptions& right ) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
OpEqu( sseMXCSR ) && OpEqu( sseVUMXCSR ) &&
|
||||||
|
OpEqu( bits ) && OpEqu( Recompiler );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator !=( const CpuOptions& right ) const
|
||||||
|
{
|
||||||
|
return !this->operator ==( right );
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -128,36 +199,77 @@ public:
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
struct GamefixOptions
|
struct GamefixOptions
|
||||||
{
|
{
|
||||||
bool
|
union
|
||||||
VuAddSubHack:1, // Fix for Tri-ace games, they use an encryption algorithm that requires VU ADDI opcode to be bit-accurate.
|
{
|
||||||
VuClipFlagHack:1, // Fix for Digimon Rumble Arena 2, fixes spinning/hanging on intro-menu.
|
struct
|
||||||
FpuCompareHack:1, // Fix for Persona games, maybe others. It's to do with the VU clip flag (again).
|
{
|
||||||
FpuMulHack:1, // Fix for Tales of Destiny hangs.
|
bool
|
||||||
XgKickHack:1; // Fix for Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace games and others.
|
VuAddSubHack:1, // Fix for Tri-ace games, they use an encryption algorithm that requires VU ADDI opcode to be bit-accurate.
|
||||||
|
VuClipFlagHack:1, // Fix for Digimon Rumble Arena 2, fixes spinning/hanging on intro-menu.
|
||||||
|
FpuCompareHack:1, // Fix for Persona games, maybe others. It's to do with the VU clip flag (again).
|
||||||
|
FpuMulHack:1, // Fix for Tales of Destiny hangs.
|
||||||
|
XgKickHack:1; // Fix for Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace games and others.
|
||||||
|
};
|
||||||
|
u8 bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
GamefixOptions() : bits( 0 ) {}
|
||||||
|
|
||||||
void LoadSave( IniInterface& conf );
|
void LoadSave( IniInterface& conf );
|
||||||
|
|
||||||
|
bool operator ==( const GamefixOptions& right ) const
|
||||||
|
{
|
||||||
|
return OpEqu( bits );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator !=( const GamefixOptions& right ) const
|
||||||
|
{
|
||||||
|
return !this->operator ==( right );
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
struct SpeedhackOptions
|
struct SpeedhackOptions
|
||||||
{
|
{
|
||||||
int
|
union
|
||||||
EECycleRate:2, // EE cyclerate selector (1.0, 1.5, 2.0)
|
{
|
||||||
VUCycleSteal:3, // VU Cycle Stealer factor (0, 1, 2, or 3)
|
struct
|
||||||
IopCycleRate_X2:1, // enables the x2 multiplier of the IOP cyclerate
|
{
|
||||||
IntcStat:1, // tells Pcsx2 to fast-forward through intc_stat waits.
|
int
|
||||||
BIFC0:1, // enables BIFC0 detection and fast-forwarding
|
EECycleRate:2, // EE cyclerate selector (1.0, 1.5, 2.0)
|
||||||
|
VUCycleSteal:3, // VU Cycle Stealer factor (0, 1, 2, or 3)
|
||||||
vuMinMax:1, // microVU specific MinMax hack; Can cause SPS, Black Screens, etc...
|
IopCycleRate_X2:1, // enables the x2 multiplier of the IOP cyclerate
|
||||||
vuFlagHack:1; // MicroVU specific flag hack; Can cause Infinite loops, SPS, etc...
|
IntcStat:1, // tells Pcsx2 to fast-forward through intc_stat waits.
|
||||||
|
BIFC0:1, // enables BIFC0 detection and fast-forwarding
|
||||||
|
|
||||||
|
vuMinMax:1, // microVU specific MinMax hack; Can cause SPS, Black Screens, etc...
|
||||||
|
vuFlagHack:1; // MicroVU specific flag hack; Can cause Infinite loops, SPS, etc...
|
||||||
|
};
|
||||||
|
u16 bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
SpeedhackOptions() : bits( 0 ) {}
|
||||||
|
|
||||||
void LoadSave( IniInterface& conf );
|
void LoadSave( IniInterface& conf );
|
||||||
|
|
||||||
|
bool operator ==( const SpeedhackOptions& right ) const
|
||||||
|
{
|
||||||
|
return OpEqu( bits );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator !=( const SpeedhackOptions& right ) const
|
||||||
|
{
|
||||||
|
return !this->operator ==( right );
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool CdvdVerboseReads:1; // enables cdvd read activity verbosely dumped to the console
|
bool CdvdVerboseReads:1; // enables cdvd read activity verbosely dumped to the console
|
||||||
bool CdvdDumpBlocks:1;
|
bool CdvdDumpBlocks:1; // enables cdvd block dumping
|
||||||
bool EnablePatches:1;
|
bool EnablePatches:1; // enables patch detection and application
|
||||||
|
|
||||||
|
// when enabled performs bios stub execution, skipping full sony bios + splash screens
|
||||||
|
bool SkipBiosSplash:1;
|
||||||
|
|
||||||
// Closes the GS/Video port on escape (good for fullscreen activity)
|
// Closes the GS/Video port on escape (good for fullscreen activity)
|
||||||
bool closeGSonEsc:1;
|
bool closeGSonEsc:1;
|
||||||
|
@ -169,6 +281,7 @@ public:
|
||||||
VideoOptions Video;
|
VideoOptions Video;
|
||||||
SpeedhackOptions Speedhacks;
|
SpeedhackOptions Speedhacks;
|
||||||
GamefixOptions Gamefixes;
|
GamefixOptions Gamefixes;
|
||||||
|
ProfilerOptions Profiler;
|
||||||
|
|
||||||
void Load( const wxString& srcfile );
|
void Load( const wxString& srcfile );
|
||||||
void Load( const wxInputStream& srcstream );
|
void Load( const wxInputStream& srcstream );
|
||||||
|
@ -178,21 +291,6 @@ public:
|
||||||
void LoadSave( IniInterface& ini );
|
void LoadSave( IniInterface& ini );
|
||||||
};
|
};
|
||||||
|
|
||||||
// Pauses the emulation state at the next PS2 vsync, and returns control to the calling
|
|
||||||
// thread; or does nothing if the core is already suspended. Calling this thread from the
|
|
||||||
// Core thread will result in deadlock.
|
|
||||||
extern void Core_Suspend();
|
|
||||||
|
|
||||||
// Applies a full suite of new settings, which will automatically facilitate the necessary
|
|
||||||
// resets of the core and components (including plugins, if needed). The scope of resetting
|
|
||||||
// is determined by comparing the current settings against the new settings.
|
|
||||||
extern void Core_ApplySettings( const Pcsx2Config& src );
|
|
||||||
|
|
||||||
// Resumes the core execution state, or does nothing is the core is already running. If
|
|
||||||
// settings were changed, resets will be performed as needed and emulation state resumed from
|
|
||||||
// memory savestates.
|
|
||||||
extern void Core_Resume();
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Session Configuration Override Flags
|
// Session Configuration Override Flags
|
||||||
//
|
//
|
||||||
|
@ -244,10 +342,6 @@ extern SessionOverrideFlags g_Session;
|
||||||
#define CHECK_FPU_EXTRA_FLAGS 1 // Always enabled now // Sets D/I flags on FPU instructions
|
#define CHECK_FPU_EXTRA_FLAGS 1 // Always enabled now // Sets D/I flags on FPU instructions
|
||||||
#define CHECK_FPU_FULL (EmuConfig.Cpu.fpuFullMode)
|
#define CHECK_FPU_FULL (EmuConfig.Cpu.fpuFullMode)
|
||||||
|
|
||||||
//------------ DEFAULT sseMXCSR VALUES!!! ---------------
|
|
||||||
#define DEFAULT_sseMXCSR 0xffc0 //FPU rounding > DaZ, FtZ, "chop"
|
|
||||||
#define DEFAULT_sseVUMXCSR 0xffc0 //VU rounding > DaZ, FtZ, "chop"
|
|
||||||
|
|
||||||
//------------ EE Recompiler defines - Comment to disable a recompiler ---------------
|
//------------ EE Recompiler defines - Comment to disable a recompiler ---------------
|
||||||
|
|
||||||
#define SHIFT_RECOMPILE // Speed majorly reduced if disabled
|
#define SHIFT_RECOMPILE // Speed majorly reduced if disabled
|
||||||
|
|
|
@ -505,28 +505,27 @@ u32 loadElfCRC( const char* filename )
|
||||||
return crcval;
|
return crcval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int loadElfFile(const wxString& filename)
|
// Loads the elf binary data from the specified file into PS2 memory, and injects the ELF's
|
||||||
|
// starting execution point into cpuRegs.pc. If the filename is a cdrom URI in the form
|
||||||
|
// of "cdrom0:" or "cdrom1:" then the CDVD is used as the source; otherwise the ELF is loaded
|
||||||
|
// from the host filesystem.
|
||||||
|
//
|
||||||
|
// If the specified filename is empty then no action is taken (PS2 will continue booting
|
||||||
|
// normally as if it has no CD
|
||||||
|
//
|
||||||
|
// Throws exception on error:
|
||||||
|
//
|
||||||
|
void loadElfFile(const wxString& filename)
|
||||||
{
|
{
|
||||||
// Reset all recompilers prior to initiating a BIOS or new ELF. The cleaner the
|
if( filename.IsEmpty() ) return;
|
||||||
// slate, the happier the recompiler!
|
|
||||||
|
|
||||||
SysClearExecutionCache();
|
|
||||||
|
|
||||||
if( filename.IsEmpty() )
|
|
||||||
{
|
|
||||||
Console::Notice( "Running the PS2 BIOS..." );
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We still need to run the BIOS stub, so that all the EE hardware gets initialized correctly.
|
|
||||||
cpuExecuteBios();
|
|
||||||
|
|
||||||
int elfsize;
|
int elfsize;
|
||||||
Console::Status( wxsFormat( L"loadElfFile: %s", filename.c_str() ) );
|
Console::Status( wxsFormat( L"loadElfFile: %s", filename.c_str() ) );
|
||||||
|
|
||||||
const wxCharBuffer buffer( filename.ToAscii() );
|
const wxCharBuffer buffer( filename.ToAscii() );
|
||||||
const char* fnptr = buffer.data();
|
const char* fnptr = buffer.data();
|
||||||
|
bool useCdvdSource=false;
|
||||||
|
|
||||||
if( !filename.StartsWith( L"cdrom0:" ) && !filename.StartsWith( L"cdrom1:" ) )
|
if( !filename.StartsWith( L"cdrom0:" ) && !filename.StartsWith( L"cdrom1:" ) )
|
||||||
{
|
{
|
||||||
// Loading from a file (or non-cd image)
|
// Loading from a file (or non-cd image)
|
||||||
|
@ -536,23 +535,25 @@ int loadElfFile(const wxString& filename)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Loading from a CD rom or CD image.
|
// Loading from a CD rom or CD image.
|
||||||
|
useCdvdSource = true;
|
||||||
TocEntry toc;
|
TocEntry toc;
|
||||||
IsoFS_init( );
|
IsoFS_init( );
|
||||||
if ( IsoFS_findFile( fnptr + strlen( "cdromN:" ), &toc ) == -1 )
|
if ( IsoFS_findFile( fnptr + strlen( "cdromN:" ), &toc ) == -1 )
|
||||||
return -1;
|
throw Exception::FileNotFound( filename, wxLt("ELF file was not found on the CDVD source media.") );
|
||||||
elfsize = toc.fileSize;
|
elfsize = toc.fileSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console::Status( wxsFormat(L"loadElfFile: %d", elfsize) );
|
Console::Status( wxsFormat(L"loadElfFile: %d", elfsize) );
|
||||||
if( elfsize == 0 ) return -1;
|
if( elfsize == 0 )
|
||||||
|
throw Exception::BadStream( filename, wxLt("Unexpected end of ELF file: ") );
|
||||||
|
|
||||||
ElfObject elfobj( filename, elfsize );
|
ElfObject elfobj( filename, elfsize );
|
||||||
|
|
||||||
if( elfobj.proghead == NULL )
|
if( elfobj.proghead == NULL )
|
||||||
{
|
{
|
||||||
throw Exception::CpuStateShutdown(
|
throw Exception::BadStream( filename, useCdvdSource ?
|
||||||
wxsFormat( L"Invalid ELF header encountered in file:\n\t%s", elfobj.filename.c_str() ),
|
wxLt("Invalid ELF file header. The CD-Rom may be damaged, or the ISO image corrupted.") :
|
||||||
wxsFormat( L"Invalid ELF header, file: %s", elfobj.filename.c_str() )
|
wxLt("Invalid ELF file.")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,6 +584,6 @@ int loadElfFile(const wxString& filename)
|
||||||
|
|
||||||
ElfApplyPatches();
|
ElfApplyPatches();
|
||||||
|
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,9 @@ extern char args[256]; //to be filled by GUI
|
||||||
extern unsigned int args_ptr;
|
extern unsigned int args_ptr;
|
||||||
|
|
||||||
//-------------------
|
//-------------------
|
||||||
int loadElfFile(const wxString& filename);
|
extern void loadElfFile(const wxString& filename);
|
||||||
u32 loadElfCRC(const char *filename);
|
extern u32 loadElfCRC(const char *filename);
|
||||||
void ElfApplyPatches();
|
extern void ElfApplyPatches();
|
||||||
|
|
||||||
extern u32 ElfCRC;
|
extern u32 ElfCRC;
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,7 @@ enum GS_RINGTYPE
|
||||||
, GS_RINGTYPE_QUIT
|
, GS_RINGTYPE_QUIT
|
||||||
};
|
};
|
||||||
|
|
||||||
class mtgsThreadObject : public Threading::Thread
|
class mtgsThreadObject : public Threading::PersistentThread
|
||||||
{
|
{
|
||||||
friend class SaveState;
|
friend class SaveState;
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ public:
|
||||||
virtual ~mtgsThreadObject();
|
virtual ~mtgsThreadObject();
|
||||||
|
|
||||||
void Start();
|
void Start();
|
||||||
void Close();
|
void Cancel();
|
||||||
void Reset();
|
void Reset();
|
||||||
void GIFSoftReset( int mask );
|
void GIFSoftReset( int mask );
|
||||||
|
|
||||||
|
@ -276,7 +276,7 @@ protected:
|
||||||
uint _PrepForSimplePacket();
|
uint _PrepForSimplePacket();
|
||||||
void _FinishSimplePacket( uint future_writepos );
|
void _FinishSimplePacket( uint future_writepos );
|
||||||
|
|
||||||
int Callback();
|
sptr ExecuteTask();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern mtgsThreadObject* mtgsThread;
|
extern mtgsThreadObject* mtgsThread;
|
||||||
|
|
|
@ -177,7 +177,7 @@ typedef void (*GIFRegHandler)(const u32* data);
|
||||||
static GIFRegHandler s_GSHandlers[3] = { RegHandlerSIGNAL, RegHandlerFINISH, RegHandlerLABEL };
|
static GIFRegHandler s_GSHandlers[3] = { RegHandlerSIGNAL, RegHandlerFINISH, RegHandlerLABEL };
|
||||||
|
|
||||||
mtgsThreadObject::mtgsThreadObject() :
|
mtgsThreadObject::mtgsThreadObject() :
|
||||||
Thread()
|
PersistentThread()
|
||||||
, m_RingPos( 0 )
|
, m_RingPos( 0 )
|
||||||
, m_WritePos( 0 )
|
, m_WritePos( 0 )
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ mtgsThreadObject::mtgsThreadObject() :
|
||||||
|
|
||||||
void mtgsThreadObject::Start()
|
void mtgsThreadObject::Start()
|
||||||
{
|
{
|
||||||
Thread::Start();
|
PersistentThread::Start();
|
||||||
|
|
||||||
// Wait for the thread to finish initialization (it runs GSopen, which can take
|
// 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.
|
// some time since it's creating a new window and all), and then check for errors.
|
||||||
|
@ -217,10 +217,10 @@ void mtgsThreadObject::Start()
|
||||||
|
|
||||||
mtgsThreadObject::~mtgsThreadObject()
|
mtgsThreadObject::~mtgsThreadObject()
|
||||||
{
|
{
|
||||||
Close();
|
Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mtgsThreadObject::Close()
|
void mtgsThreadObject::Cancel()
|
||||||
{
|
{
|
||||||
Console::WriteLn( "MTGS > Closing GS thread..." );
|
Console::WriteLn( "MTGS > Closing GS thread..." );
|
||||||
SendSimplePacket( GS_RINGTYPE_QUIT, 0, 0, 0 );
|
SendSimplePacket( GS_RINGTYPE_QUIT, 0, 0, 0 );
|
||||||
|
@ -499,7 +499,7 @@ struct PacketTagType
|
||||||
#ifndef __LINUX__
|
#ifndef __LINUX__
|
||||||
extern bool renderswitch;
|
extern bool renderswitch;
|
||||||
#endif
|
#endif
|
||||||
int mtgsThreadObject::Callback()
|
sptr mtgsThreadObject::ExecuteTask()
|
||||||
{
|
{
|
||||||
Console::WriteLn("MTGS > Thread Started, Opening GS Plugin...");
|
Console::WriteLn("MTGS > Thread Started, Opening GS Plugin...");
|
||||||
|
|
||||||
|
|
|
@ -805,7 +805,7 @@ void memReset()
|
||||||
wxString Bios( g_Conf->FullpathToBios() );
|
wxString Bios( g_Conf->FullpathToBios() );
|
||||||
|
|
||||||
long filesize = Path::GetFileSize( Bios );
|
long filesize = Path::GetFileSize( Bios );
|
||||||
if( filesize <= 0 )
|
if( filesize > 0 )
|
||||||
{
|
{
|
||||||
wxFile fp( Bios.c_str() );
|
wxFile fp( Bios.c_str() );
|
||||||
fp.Read( PS2MEM_ROM, min( (long)Ps2MemSize::Rom, filesize ) );
|
fp.Read( PS2MEM_ROM, min( (long)Ps2MemSize::Rom, filesize ) );
|
||||||
|
@ -813,7 +813,14 @@ void memReset()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Translated: Bios file not found or not specified ... A bios is required for Pcsx2 to run!
|
// Translated: Bios file not found or not specified ... A bios is required for Pcsx2 to run!
|
||||||
throw Exception::FileNotFound( Bios, wxLt("Bios not found") );
|
throw Exception::FileNotFound( Bios,
|
||||||
|
L"Configured Bios file does not exist",
|
||||||
|
pxE( ".Error:BiosNotFound",
|
||||||
|
L"The configured BIOS file does not exist, or no BIOS has been configured.\n\n"
|
||||||
|
L"PCSX2 requires a PS2 BIOS to run; and the BIOS *must* be obtained from an actual PS2 unit\n"
|
||||||
|
L"that you own (borrowing doesn't count). Please consult the FAQs and Guides for further instructions."
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
BiosVersion = GetBiosVersion();
|
BiosVersion = GetBiosVersion();
|
||||||
|
|
|
@ -237,6 +237,10 @@ bool IsBIOS(const wxString& filename, wxString& description)
|
||||||
return false; //fail quietly
|
return false; //fail quietly
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return value:
|
||||||
|
// 0 - Invalid or unknown disc.
|
||||||
|
// 1 - PS1 CD
|
||||||
|
// 2 - PS2 CD
|
||||||
int GetPS2ElfName( wxString& name )
|
int GetPS2ElfName( wxString& name )
|
||||||
{
|
{
|
||||||
int f;
|
int f;
|
||||||
|
@ -262,7 +266,7 @@ int GetPS2ElfName( wxString& name )
|
||||||
if (pos==NULL){
|
if (pos==NULL){
|
||||||
pos=strstr(buffer, "BOOT");
|
pos=strstr(buffer, "BOOT");
|
||||||
if (pos==NULL) {
|
if (pos==NULL) {
|
||||||
Console::Error("Boot Error > This is not a PS2 game!");
|
Console::Error("Boot failed: This is not a Playstation or PS2 game!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -453,7 +457,7 @@ void ProcessFKeys(int fkey, struct KeyModifiers *keymod)
|
||||||
wxsFormat( L"Error! Could not load from saveslot %d\n", StatesC ) + ex.LogMessage(),
|
wxsFormat( L"Error! Could not load from saveslot %d\n", StatesC ) + ex.LogMessage(),
|
||||||
|
|
||||||
// translated message:
|
// translated message:
|
||||||
wxsFormat( L"Error loading saveslot %d. Emulator reset.", StatesC )
|
wxsFormat( _("Error loading saveslot %d. Emulator reset."), StatesC )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -76,7 +76,6 @@ void Pcsx2Config::CpuOptions::LoadSave( IniInterface& ini )
|
||||||
IniBitBool( fpuFullMode, false );
|
IniBitBool( fpuFullMode, false );
|
||||||
|
|
||||||
Recompiler.LoadSave( ini );
|
Recompiler.LoadSave( ini );
|
||||||
Profiler.LoadSave( ini );
|
|
||||||
|
|
||||||
ini.SetPath( L".." );
|
ini.SetPath( L".." );
|
||||||
}
|
}
|
||||||
|
@ -112,6 +111,7 @@ void Pcsx2Config::LoadSave( IniInterface& ini )
|
||||||
Cpu.LoadSave( ini );
|
Cpu.LoadSave( ini );
|
||||||
Video.LoadSave( ini );
|
Video.LoadSave( ini );
|
||||||
Gamefixes.LoadSave( ini );
|
Gamefixes.LoadSave( ini );
|
||||||
|
Profiler.LoadSave( ini );
|
||||||
|
|
||||||
ini.SetPath( L".." );
|
ini.SetPath( L".." );
|
||||||
ini.Flush();
|
ini.Flush();
|
||||||
|
|
|
@ -720,14 +720,7 @@ void InitPlugins()
|
||||||
return 0;*/
|
return 0;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
void OpenPlugins()
|
||||||
// Opens all plugins and initializes the CDVD plugin to use the given filename. If the filename is null
|
|
||||||
// then the cdvd plugin uses whatever file it has been configured to use. If plugin have not been
|
|
||||||
// initialized by an explicit call to InitializePlugins, this method will do so for you.
|
|
||||||
//
|
|
||||||
// fixme: the cdvd filename really should be passed to the cdvd plugin as a separate API call. >_<
|
|
||||||
//
|
|
||||||
void OpenPlugins(const char* cdvdFilename)
|
|
||||||
{
|
{
|
||||||
/*if (!plugins_initialized)
|
/*if (!plugins_initialized)
|
||||||
{
|
{
|
||||||
|
|
|
@ -113,7 +113,7 @@ extern PluginManager* g_plugins;
|
||||||
void LoadPlugins();
|
void LoadPlugins();
|
||||||
void ReleasePlugins();
|
void ReleasePlugins();
|
||||||
|
|
||||||
void OpenPlugins(const char* pTitleFilename);
|
void OpenPlugins();
|
||||||
void ClosePlugins( bool closegs );
|
void ClosePlugins( bool closegs );
|
||||||
void CloseGS();
|
void CloseGS();
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ PCSX2_ALIGNED16(fpuRegisters fpuRegs);
|
||||||
PCSX2_ALIGNED16(tlbs tlb[48]);
|
PCSX2_ALIGNED16(tlbs tlb[48]);
|
||||||
R5900cpu *Cpu = NULL;
|
R5900cpu *Cpu = NULL;
|
||||||
|
|
||||||
u32 bExecBIOS = 0; // set if the BIOS has already been executed
|
bool g_ExecBiosHack = false; // set if the BIOS has already been executed
|
||||||
|
|
||||||
static bool cpuIsInitialized = false;
|
static bool cpuIsInitialized = false;
|
||||||
static const uint eeWaitCycles = 3072;
|
static const uint eeWaitCycles = 3072;
|
||||||
|
@ -556,21 +556,27 @@ __forceinline void cpuTestHwInts() {
|
||||||
// memory and hardware. It forcefully breaks execution when the stub is finished, prior
|
// memory and hardware. It forcefully breaks execution when the stub is finished, prior
|
||||||
// to the PS2 logos being displayed. This allows us to "shortcut" right into a game
|
// to the PS2 logos being displayed. This allows us to "shortcut" right into a game
|
||||||
// without having to wait through the logos or endure game/bios localization checks.
|
// without having to wait through the logos or endure game/bios localization checks.
|
||||||
|
//
|
||||||
|
// Use of this function must be followed by the proper injection of the elf header's code
|
||||||
|
// execution entry point into cpuRegs.pc. Failure to modify cpuRegs.pc will result in the
|
||||||
|
// bios continuing its normal unimpeeded splashscreen execution.
|
||||||
|
//
|
||||||
void cpuExecuteBios()
|
void cpuExecuteBios()
|
||||||
{
|
{
|
||||||
// Set the video mode to user's default request:
|
// Set the video mode to user's default request:
|
||||||
gsSetRegionMode( (GS_RegionMode)EmuConfig.Video.DefaultRegionMode );
|
gsSetRegionMode( (GS_RegionMode)EmuConfig.Video.DefaultRegionMode );
|
||||||
|
|
||||||
Console::Notice( "* PCSX2 *: ExecuteBios" );
|
Console::Status( "Executing Bios Stub..." );
|
||||||
|
|
||||||
bExecBIOS = TRUE;
|
g_ExecBiosHack = true;
|
||||||
while (cpuRegs.pc != 0x00200008 &&
|
while( cpuRegs.pc != 0x00200008 &&
|
||||||
cpuRegs.pc != 0x00100008) {
|
cpuRegs.pc != 0x00100008 )
|
||||||
|
{
|
||||||
g_nextBranchCycle = cpuRegs.cycle;
|
g_nextBranchCycle = cpuRegs.cycle;
|
||||||
Cpu->ExecuteBlock();
|
Cpu->ExecuteBlock();
|
||||||
}
|
}
|
||||||
|
g_ExecBiosHack = false;
|
||||||
|
|
||||||
bExecBIOS = FALSE;
|
|
||||||
// {
|
// {
|
||||||
// FILE* f = fopen("eebios.bin", "wb");
|
// FILE* f = fopen("eebios.bin", "wb");
|
||||||
// fwrite(PSM(0x80000000), 0x100000, 1, f);
|
// fwrite(PSM(0x80000000), 0x100000, 1, f);
|
||||||
|
@ -586,12 +592,12 @@ void cpuExecuteBios()
|
||||||
// REC_CLEARM(0x00100008);
|
// REC_CLEARM(0x00100008);
|
||||||
// REC_CLEARM(cpuRegs.pc);
|
// REC_CLEARM(cpuRegs.pc);
|
||||||
|
|
||||||
// Reset the EErecs here, because the bios generates "slow" blocks that have hacky
|
// Reset the EErecs here, because the bios generates "slow" blocks that have
|
||||||
// bBiosEnd checks in them and stuff. This deletes them so that the recs replace them
|
// g_ExecBiosHack checks in them. This deletes them so that the recs replace them
|
||||||
// with new faster versions:
|
// with new faster versions:
|
||||||
Cpu->Reset();
|
Cpu->Reset();
|
||||||
|
|
||||||
Console::Notice("* PCSX2 *: ExecuteBios Complete");
|
Console::Notice("Execute Bios Stub Complete");
|
||||||
//GSprintf(5, "PCSX2 " PCSX2_VERSION "\nExecuteBios Complete\n");
|
//GSprintf(5, "PCSX2 " PCSX2_VERSION "\nExecuteBios Complete\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ extern const char* const bios[256];
|
||||||
|
|
||||||
extern s32 EEsCycle;
|
extern s32 EEsCycle;
|
||||||
extern u32 EEoCycle;
|
extern u32 EEoCycle;
|
||||||
extern u32 bExecBIOS;
|
extern bool g_ExecBiosHack;
|
||||||
|
|
||||||
union GPR_reg { // Declare union type GPR register
|
union GPR_reg { // Declare union type GPR register
|
||||||
u64 UD[2]; //128 bits
|
u64 UD[2]; //128 bits
|
||||||
|
|
|
@ -80,7 +80,7 @@ namespace StateRecovery {
|
||||||
void Recover()
|
void Recover()
|
||||||
{
|
{
|
||||||
// Just in case they weren't initialized earlier (no harm in calling this multiple times)
|
// Just in case they weren't initialized earlier (no harm in calling this multiple times)
|
||||||
OpenPlugins(NULL);
|
OpenPlugins();
|
||||||
|
|
||||||
if( g_RecoveryState != NULL )
|
if( g_RecoveryState != NULL )
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,7 +48,7 @@ static void _loadStateOrExcept( const wxString& file )
|
||||||
|
|
||||||
// Make sure the cpu and plugins are ready to be state-ified!
|
// Make sure the cpu and plugins are ready to be state-ified!
|
||||||
cpuReset();
|
cpuReset();
|
||||||
OpenPlugins( NULL );
|
OpenPlugins();
|
||||||
|
|
||||||
joe.FreezeAll();
|
joe.FreezeAll();
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
Pcsx2Config EmuConfig = {0};
|
Pcsx2Config EmuConfig;
|
||||||
|
|
||||||
// disable all session overrides by default...
|
// disable all session overrides by default...
|
||||||
SessionOverrideFlags g_Session = {false};
|
SessionOverrideFlags g_Session = {false};
|
||||||
|
@ -334,54 +334,6 @@ void SysEndExecution()
|
||||||
g_ReturnToGui = true;
|
g_ReturnToGui = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runs an ELF image directly (ISO or ELF program or BIN)
|
|
||||||
// Used by Run::FromCD, and Run->Execute when no active emulation state is present.
|
|
||||||
// elf_file - if NULL, the CDVD plugin is queried for the ELF file.
|
|
||||||
// use_bios - forces the game to boot through the PS2 bios, instead of bypassing it.
|
|
||||||
void SysPrepareExecution( const wxString& elf_file, bool use_bios )
|
|
||||||
{
|
|
||||||
if( !g_EmulationInProgress )
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
cpuReset();
|
|
||||||
}
|
|
||||||
catch( Exception::BaseException& ex )
|
|
||||||
{
|
|
||||||
Msgbox::Alert( ex.DisplayMessage() );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//g_Startup.BootMode = (elf_file) ? BootMode_Elf : BootMode_Normal;
|
|
||||||
|
|
||||||
OpenPlugins(NULL);
|
|
||||||
|
|
||||||
if( elf_file.IsEmpty() )
|
|
||||||
{
|
|
||||||
if( !StateRecovery::HasState() )
|
|
||||||
{
|
|
||||||
// Not recovering a state, so need to execute the bios and load the ELF information.
|
|
||||||
// (note: gsRecoveries are done from ExecuteCpu)
|
|
||||||
|
|
||||||
wxString ename;
|
|
||||||
if( !use_bios )
|
|
||||||
GetPS2ElfName( ename );
|
|
||||||
|
|
||||||
loadElfFile( ename );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Custom ELF specified (not using CDVD).
|
|
||||||
// Run the BIOS and load the ELF.
|
|
||||||
loadElfFile( elf_file );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StateRecovery::Recover();
|
|
||||||
HostGui::BeginExecution();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysRestorableReset()
|
void SysRestorableReset()
|
||||||
{
|
{
|
||||||
if( !g_EmulationInProgress ) return;
|
if( !g_EmulationInProgress ) return;
|
||||||
|
|
|
@ -35,8 +35,7 @@ extern void SysShutdownMem();
|
||||||
|
|
||||||
extern void SysRestorableReset(); // Saves the current emulation state prior to spu reset.
|
extern void SysRestorableReset(); // Saves the current emulation state prior to spu reset.
|
||||||
extern void SysClearExecutionCache(); // clears recompiled execution caches!
|
extern void SysClearExecutionCache(); // clears recompiled execution caches!
|
||||||
extern void SysEndExecution(); // terminates plugins, saves GS state (if enabled), and signals emulation loop to end.
|
extern void SysEndExecution(); // terminates plugins, saves GS state (if enabled), and signals emulation loop to end.
|
||||||
extern void SysPrepareExecution( const wxString& elf_file, bool use_bios=false );
|
|
||||||
|
|
||||||
// initiates high-speed execution of the emulation state. This function is currently
|
// initiates high-speed execution of the emulation state. This function is currently
|
||||||
// designed to be run from an event loop, but will eventually be re-tooled with threading
|
// designed to be run from an event loop, but will eventually be re-tooled with threading
|
||||||
|
@ -82,6 +81,8 @@ extern void vSyncDebugStuff( uint frame );
|
||||||
//
|
//
|
||||||
namespace Msgbox
|
namespace Msgbox
|
||||||
{
|
{
|
||||||
|
extern void OnEvent( wxCommandEvent& evt );
|
||||||
|
|
||||||
// Pops up an alert Dialog Box with a singular "OK" button.
|
// Pops up an alert Dialog Box with a singular "OK" button.
|
||||||
// Always returns false. Replacement for SysMessage.
|
// Always returns false. Replacement for SysMessage.
|
||||||
extern bool Alert( const wxString& text );
|
extern bool Alert( const wxString& text );
|
||||||
|
@ -91,3 +92,4 @@ namespace Msgbox
|
||||||
extern bool OkCancel( const wxString& text );
|
extern bool OkCancel( const wxString& text );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECLARE_EVENT_TYPE( pxEVT_MSGBOX, -1 );
|
||||||
|
|
|
@ -45,11 +45,11 @@ static const bool EnableThreadedLoggingTest = false; //true;
|
||||||
// ConsoleThreadTest -- useful class for unit testing the thread safety and general performance
|
// ConsoleThreadTest -- useful class for unit testing the thread safety and general performance
|
||||||
// of the console logger.
|
// of the console logger.
|
||||||
//
|
//
|
||||||
class ConsoleTestThread : public Thread
|
class ConsoleTestThread : public PersistentThread
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
volatile bool m_done;
|
volatile bool m_done;
|
||||||
int Callback();
|
sptr ExecuteTask();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConsoleTestThread() :
|
ConsoleTestThread() :
|
||||||
|
@ -275,6 +275,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
void ReadUserModeSettings();
|
void ReadUserModeSettings();
|
||||||
bool TryOpenConfigCwd();
|
bool TryOpenConfigCwd();
|
||||||
|
void OnMessageBox( wxCommandEvent& evt );
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_APP(Pcsx2App)
|
DECLARE_APP(Pcsx2App)
|
||||||
|
|
|
@ -45,7 +45,7 @@ DEFINE_EVENT_TYPE(wxEVT_SemaphoreWait);
|
||||||
using Console::Colors;
|
using Console::Colors;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
int ConsoleTestThread::Callback()
|
sptr ConsoleTestThread::ExecuteTask()
|
||||||
{
|
{
|
||||||
static int numtrack = 0;
|
static int numtrack = 0;
|
||||||
|
|
||||||
|
@ -602,17 +602,72 @@ namespace Console
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define wxEVT_BOX_ALERT 78
|
||||||
|
|
||||||
|
using namespace Threading;
|
||||||
|
|
||||||
|
DEFINE_EVENT_TYPE( pxEVT_MSGBOX );
|
||||||
|
|
||||||
namespace Msgbox
|
namespace Msgbox
|
||||||
{
|
{
|
||||||
|
struct InstanceData
|
||||||
|
{
|
||||||
|
Semaphore WaitForMe;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
InstanceData() :
|
||||||
|
WaitForMe(), result( 0 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// parameters:
|
||||||
|
// flags - messagebox type flags, such as wxOK, wxCANCEL, etc.
|
||||||
|
//
|
||||||
|
static int ThreadedMessageBox( int flags, const wxString& text )
|
||||||
|
{
|
||||||
|
// must pass the message to the main gui thread, and then stall this thread, to avoid
|
||||||
|
// threaded chaos where our thread keeps running while the popup is awaiting input.
|
||||||
|
|
||||||
|
InstanceData instdat;
|
||||||
|
wxCommandEvent tevt( pxEVT_MSGBOX );
|
||||||
|
tevt.SetString( text );
|
||||||
|
tevt.SetClientData( &instdat );
|
||||||
|
tevt.SetExtraLong( flags );
|
||||||
|
wxGetApp().AddPendingEvent( tevt );
|
||||||
|
instdat.WaitForMe.WaitNoCancel(); // Important! disable cancellation since we're using local stack vars.
|
||||||
|
return instdat.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEvent( wxCommandEvent& evt )
|
||||||
|
{
|
||||||
|
// Must be called from the GUI thread ONLY.
|
||||||
|
wxASSERT( wxThread::IsMain() );
|
||||||
|
|
||||||
|
int result = Alert( evt.GetString() );
|
||||||
|
InstanceData* instdat = (InstanceData*)evt.GetClientData();
|
||||||
|
instdat->result = result;
|
||||||
|
instdat->WaitForMe.Post();
|
||||||
|
}
|
||||||
|
|
||||||
bool Alert( const wxString& text )
|
bool Alert( const wxString& text )
|
||||||
{
|
{
|
||||||
wxMessageBox( text, L"Pcsx2 Message", wxOK, wxGetApp().GetTopWindow() );
|
if( wxThread::IsMain() )
|
||||||
|
wxMessageBox( text, L"Pcsx2 Message", wxOK, wxGetApp().GetTopWindow() );
|
||||||
|
else
|
||||||
|
ThreadedMessageBox( wxOK, text );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OkCancel( const wxString& text )
|
bool OkCancel( const wxString& text )
|
||||||
{
|
{
|
||||||
int result = wxMessageBox( text, L"Pcsx2 Message", wxOK | wxCANCEL, wxGetApp().GetTopWindow() );
|
if( wxThread::IsMain() )
|
||||||
return result == wxOK;
|
{
|
||||||
|
return wxOK == wxMessageBox( text, L"Pcsx2 Message", wxOK | wxCANCEL, wxGetApp().GetTopWindow() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return wxOK == ThreadedMessageBox( wxOK | wxCANCEL, text );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
#include "App.h"
|
#include "Mainframe.h"
|
||||||
|
|
||||||
// This API is likely obsolete for the most part, so I've just included a few dummies
|
// This API is likely obsolete for the most part, so I've just included a few dummies
|
||||||
// to keep things compiling until I can get to the point of tying up loose ends.
|
// to keep things compiling until I can get to the point of tying up loose ends.
|
||||||
|
@ -44,6 +44,8 @@ namespace HostGui
|
||||||
|
|
||||||
void BeginExecution()
|
void BeginExecution()
|
||||||
{
|
{
|
||||||
|
wxASSERT( g_EmuThread != NULL );
|
||||||
|
g_EmuThread->Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void __fastcall KeyEvent( keyEvent* ev )
|
void __fastcall KeyEvent( keyEvent* ev )
|
||||||
|
|
|
@ -167,8 +167,7 @@ void MainEmuFrame::ConnectMenus()
|
||||||
ConnectMenu( Menu_RunELF, Menu_OpenELF_Click );
|
ConnectMenu( Menu_RunELF, Menu_OpenELF_Click );
|
||||||
ConnectMenu( Menu_Run_Exit, Menu_Exit_Click );
|
ConnectMenu( Menu_Run_Exit, Menu_Exit_Click );
|
||||||
|
|
||||||
ConnectMenu( Menu_SuspendExec, Menu_Suspend_Click );
|
ConnectMenu( Menu_PauseExec, Menu_Pause_Click );
|
||||||
ConnectMenu( Menu_ResumeExec, Menu_Resume_Click );
|
|
||||||
ConnectMenu( Menu_Reset, Menu_Reset_Click );
|
ConnectMenu( Menu_Reset, Menu_Reset_Click );
|
||||||
|
|
||||||
ConnectMenu( Menu_State_LoadOther, Menu_LoadStateOther_Click );
|
ConnectMenu( Menu_State_LoadOther, Menu_LoadStateOther_Click );
|
||||||
|
@ -224,7 +223,9 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
|
||||||
m_LoadStatesSubmenu( *MakeStatesSubMenu( Menu_State_Load01 ) ),
|
m_LoadStatesSubmenu( *MakeStatesSubMenu( Menu_State_Load01 ) ),
|
||||||
m_SaveStatesSubmenu( *MakeStatesSubMenu( Menu_State_Save01 ) ),
|
m_SaveStatesSubmenu( *MakeStatesSubMenu( Menu_State_Save01 ) ),
|
||||||
|
|
||||||
m_MenuItem_Console( *new wxMenuItem( &m_menuMisc, Menu_Console, L"Show Console", wxEmptyString, wxITEM_CHECK ) )
|
m_MenuItem_Console( *new wxMenuItem( &m_menuMisc, Menu_Console, L"Show Console", wxEmptyString, wxITEM_CHECK ) ),
|
||||||
|
|
||||||
|
m_IsPaused( false )
|
||||||
{
|
{
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Initial menubar setup. This needs to be done first so that the menu bar's visible size
|
// Initial menubar setup. This needs to be done first so that the menu bar's visible size
|
||||||
|
@ -275,15 +276,14 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
|
||||||
|
|
||||||
m_menuRun.Append(Menu_RunIso, _("Run ISO"), MakeIsoMenu() );
|
m_menuRun.Append(Menu_RunIso, _("Run ISO"), MakeIsoMenu() );
|
||||||
m_menuRun.Append(Menu_BootCDVD, _("Run CDVD"), MakeCdvdMenu() );
|
m_menuRun.Append(Menu_BootCDVD, _("Run CDVD"), MakeCdvdMenu() );
|
||||||
m_menuRun.Append(Menu_RunWithoutDisc,_("Run without Disc"), _("Use this to access the PS2 system configuration menu"));
|
m_menuRun.Append(Menu_SkipBiosToggle,_("ELF Injection Hack"), _("Skips PS2 splash screens when booting from Iso or CDVD media"));
|
||||||
m_menuRun.Append(Menu_RunELF, _("Run ELF File..."), _("For running raw PS2 binaries."));
|
|
||||||
|
|
||||||
m_menuRun.AppendSeparator();
|
m_menuRun.AppendSeparator();
|
||||||
m_menuRun.Append(Menu_SkipBiosToggle,_("Skip Bios on Boot"), _("Enable this to skip PS2 bootup screens (may hurt compat)"));
|
m_menuRun.Append(Menu_RunWithoutDisc,_("Boot without Disc"), _("Use this to access the PS2 system configuration menu"));
|
||||||
|
m_menuRun.Append(Menu_RunELF, _("Run ELF File..."), _("For running raw binaries"));
|
||||||
|
|
||||||
m_menuRun.AppendSeparator();
|
m_menuRun.AppendSeparator();
|
||||||
m_menuRun.Append(Menu_SuspendExec, _("Suspend"), _("Stops emulation dead in its tracks"));
|
m_menuRun.Append(Menu_PauseExec, _("Pause"), _("Stops emulation dead in its tracks"));
|
||||||
m_menuRun.Append(Menu_ResumeExec, _("Resume"), _("Resumes suspended emulation"));
|
|
||||||
m_menuRun.Append(Menu_States, _("States"), MakeStatesMenu(), wxEmptyString);
|
m_menuRun.Append(Menu_States, _("States"), MakeStatesMenu(), wxEmptyString);
|
||||||
m_menuRun.Append(Menu_Reset, _("Reset"), _("Resets emulation state and reloads plugins"));
|
m_menuRun.Append(Menu_Reset, _("Reset"), _("Resets emulation state and reloads plugins"));
|
||||||
|
|
||||||
|
@ -337,4 +337,3 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
|
||||||
Connect( wxEVT_MOVE, wxMoveEventHandler (MainEmuFrame::OnMoveAround) );
|
Connect( wxEVT_MOVE, wxMoveEventHandler (MainEmuFrame::OnMoveAround) );
|
||||||
Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler(MainEmuFrame::OnCloseWindow) );
|
Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler(MainEmuFrame::OnCloseWindow) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@
|
||||||
#include <wx/docview.h>
|
#include <wx/docview.h>
|
||||||
|
|
||||||
#include "App.h"
|
#include "App.h"
|
||||||
|
#include "PS2/CoreEmuThread.h"
|
||||||
|
|
||||||
|
extern CoreEmuThread* g_EmuThread;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
@ -50,8 +53,7 @@ protected:
|
||||||
Menu_RunELF,
|
Menu_RunELF,
|
||||||
Menu_SkipBiosToggle, // enables the Bios Skip speedhack
|
Menu_SkipBiosToggle, // enables the Bios Skip speedhack
|
||||||
Menu_EnableSkipBios, // check marked menu that toggles Skip Bios boot feature.
|
Menu_EnableSkipBios, // check marked menu that toggles Skip Bios boot feature.
|
||||||
Menu_SuspendExec, // suspends active emulation
|
Menu_PauseExec, // suspends/resumes active emulation
|
||||||
Menu_ResumeExec, // restores active emulation
|
|
||||||
Menu_Reset, // Issues a complete reset.
|
Menu_Reset, // Issues a complete reset.
|
||||||
Menu_States, // Opens states submenu
|
Menu_States, // Opens states submenu
|
||||||
Menu_Run_Exit = wxID_EXIT,
|
Menu_Run_Exit = wxID_EXIT,
|
||||||
|
@ -134,6 +136,8 @@ protected:
|
||||||
|
|
||||||
wxMenuItem& m_MenuItem_Console;
|
wxMenuItem& m_MenuItem_Console;
|
||||||
|
|
||||||
|
bool m_IsPaused;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// MainEmuFrame Constructors and Member Methods
|
// MainEmuFrame Constructors and Member Methods
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -142,6 +146,8 @@ public:
|
||||||
MainEmuFrame(wxWindow* parent, const wxString& title);
|
MainEmuFrame(wxWindow* parent, const wxString& title);
|
||||||
void OnLogBoxHidden();
|
void OnLogBoxHidden();
|
||||||
|
|
||||||
|
bool IsPaused() const { return m_IsPaused; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void InitLogBoxPosition( AppConfig::ConsoleLogOptions& conf );
|
void InitLogBoxPosition( AppConfig::ConsoleLogOptions& conf );
|
||||||
|
|
||||||
|
@ -160,8 +166,7 @@ protected:
|
||||||
void Menu_SaveStateOther_Click(wxCommandEvent &event);
|
void Menu_SaveStateOther_Click(wxCommandEvent &event);
|
||||||
void Menu_Exit_Click(wxCommandEvent &event);
|
void Menu_Exit_Click(wxCommandEvent &event);
|
||||||
|
|
||||||
void Menu_Suspend_Click(wxCommandEvent &event);
|
void Menu_Pause_Click(wxCommandEvent &event);
|
||||||
void Menu_Resume_Click(wxCommandEvent &event);
|
|
||||||
void Menu_Reset_Click(wxCommandEvent &event);
|
void Menu_Reset_Click(wxCommandEvent &event);
|
||||||
|
|
||||||
void Menu_Debug_Open_Click(wxCommandEvent &event);
|
void Menu_Debug_Open_Click(wxCommandEvent &event);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
|
#include "HostGui.h"
|
||||||
#include "CDVD/CDVD.h"
|
#include "CDVD/CDVD.h"
|
||||||
|
|
||||||
#include "MainFrame.h"
|
#include "MainFrame.h"
|
||||||
|
@ -37,20 +38,63 @@ static const wxChar* isoFilterTypes =
|
||||||
|
|
||||||
void MainEmuFrame::Menu_RunIso_Click(wxCommandEvent &event)
|
void MainEmuFrame::Menu_RunIso_Click(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
|
g_EmuThread->Suspend();
|
||||||
|
|
||||||
Console::Status( L"Default Folder: " + g_Conf->Folders.RunIso.ToString() );
|
Console::Status( L"Default Folder: " + g_Conf->Folders.RunIso.ToString() );
|
||||||
wxFileDialog ctrl( this, _("Run PS2 Iso..."), g_Conf->Folders.RunIso.ToString(), wxEmptyString,
|
wxFileDialog ctrl( this, _("Run PS2 Iso..."), g_Conf->Folders.RunIso.ToString(), wxEmptyString,
|
||||||
isoFilterTypes, wxFD_OPEN | wxFD_FILE_MUST_EXIST );
|
isoFilterTypes, wxFD_OPEN | wxFD_FILE_MUST_EXIST );
|
||||||
|
|
||||||
if( ctrl.ShowModal() == wxID_CANCEL ) return;
|
if( ctrl.ShowModal() == wxID_CANCEL ) return;
|
||||||
g_Conf->Folders.RunIso = ctrl.GetPath();
|
g_Conf->Folders.RunIso = ctrl.GetPath();
|
||||||
|
|
||||||
//g_Conf->Save();
|
//g_Conf->Save();
|
||||||
|
|
||||||
|
if( EmuConfig.SkipBiosSplash )
|
||||||
|
{
|
||||||
|
// Fetch the ELF filename and CD type from the CDVD provider.
|
||||||
|
wxString ename( ctrl.GetFilename() );
|
||||||
|
int result = GetPS2ElfName( ename );
|
||||||
|
g_EmuThread->SetElfFile( wxEmptyString );
|
||||||
|
switch( result )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Msgbox::Alert( _("Boot failed: CDVD image is not a PS1 or PS2 game.") );
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
Msgbox::Alert( _("Boot failed: PCSX2 does not support emulation of PS1 games.") );
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// PS2 game. Valid!
|
||||||
|
g_EmuThread->SetElfFile( ename );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::Menu_RunWithoutDisc_Click(wxCommandEvent &event)
|
void MainEmuFrame::Menu_RunWithoutDisc_Click(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
|
if( g_EmuThread->IsRunning() )
|
||||||
|
{
|
||||||
|
g_EmuThread->Suspend();
|
||||||
|
|
||||||
|
// [TODO] : Add one of 'dems checkboxes that read like "[x] don't show this stupid shit again, kthx."
|
||||||
|
bool result = Msgbox::OkCancel( pxE( ".Popup:ConfirmEmuReset", L"This will reset the emulator and your current emulation session will be lost. Are you sure?") );
|
||||||
|
|
||||||
|
if( !result )
|
||||||
|
{
|
||||||
|
if( !IsPaused() )
|
||||||
|
g_EmuThread->Resume();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_EmuThread->Reset();
|
||||||
CDVDsys_ChangeSource( CDVDsrc_NoDisc );
|
CDVDsys_ChangeSource( CDVDsrc_NoDisc );
|
||||||
SysPrepareExecution( wxEmptyString, true );
|
g_EmuThread->Resume();
|
||||||
|
|
||||||
|
//HostGui::BeginExecution();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::Menu_IsoRecent_Click(wxCommandEvent &event)
|
void MainEmuFrame::Menu_IsoRecent_Click(wxCommandEvent &event)
|
||||||
|
@ -76,11 +120,7 @@ void MainEmuFrame::Menu_Exit_Click(wxCommandEvent &event)
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::Menu_Suspend_Click(wxCommandEvent &event)
|
void MainEmuFrame::Menu_Pause_Click(wxCommandEvent &event)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainEmuFrame::Menu_Resume_Click(wxCommandEvent &event)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -306,7 +306,7 @@ namespace Panels
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class EnumThread : public Threading::Thread
|
class EnumThread : public Threading::PersistentThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EnumeratedPluginInfo* Results; // array of plugin results.
|
EnumeratedPluginInfo* Results; // array of plugin results.
|
||||||
|
@ -317,10 +317,10 @@ namespace Panels
|
||||||
public:
|
public:
|
||||||
virtual ~EnumThread();
|
virtual ~EnumThread();
|
||||||
EnumThread( PluginSelectorPanel& master );
|
EnumThread( PluginSelectorPanel& master );
|
||||||
void Close();
|
void Cancel();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int Callback();
|
sptr ExecuteTask();
|
||||||
};
|
};
|
||||||
|
|
||||||
// This panel contains all of the plugin combo boxes. We stick them
|
// This panel contains all of the plugin combo boxes. We stick them
|
||||||
|
|
|
@ -337,7 +337,7 @@ void Panels::PluginSelectorPanel::OnProgress( wxCommandEvent& evt )
|
||||||
// EnumThread Method Implementations
|
// EnumThread Method Implementations
|
||||||
|
|
||||||
Panels::PluginSelectorPanel::EnumThread::EnumThread( PluginSelectorPanel& master ) :
|
Panels::PluginSelectorPanel::EnumThread::EnumThread( PluginSelectorPanel& master ) :
|
||||||
Thread()
|
PersistentThread()
|
||||||
, Results( new EnumeratedPluginInfo[master.FileCount()] )
|
, Results( new EnumeratedPluginInfo[master.FileCount()] )
|
||||||
, m_master( master )
|
, m_master( master )
|
||||||
, m_cancel( false )
|
, m_cancel( false )
|
||||||
|
@ -347,17 +347,17 @@ Panels::PluginSelectorPanel::EnumThread::EnumThread( PluginSelectorPanel& master
|
||||||
Panels::PluginSelectorPanel::EnumThread::~EnumThread()
|
Panels::PluginSelectorPanel::EnumThread::~EnumThread()
|
||||||
{
|
{
|
||||||
safe_delete_array( Results );
|
safe_delete_array( Results );
|
||||||
Close();
|
Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panels::PluginSelectorPanel::EnumThread::Close()
|
void Panels::PluginSelectorPanel::EnumThread::Cancel()
|
||||||
{
|
{
|
||||||
m_cancel = true;
|
m_cancel = true;
|
||||||
Threading::Sleep( 1 );
|
Threading::Sleep( 1 );
|
||||||
Thread::Close();
|
PersistentThread::Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Panels::PluginSelectorPanel::EnumThread::Callback()
|
sptr Panels::PluginSelectorPanel::EnumThread::ExecuteTask()
|
||||||
{
|
{
|
||||||
for( int curidx=0; curidx < m_master.FileCount() && !m_cancel; ++curidx )
|
for( int curidx=0; curidx < m_master.FileCount() && !m_cancel; ++curidx )
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,11 +30,12 @@ IMPLEMENT_APP(Pcsx2App)
|
||||||
|
|
||||||
AppConfig* g_Conf = NULL;
|
AppConfig* g_Conf = NULL;
|
||||||
wxFileHistory* g_RecentIsoList = NULL;
|
wxFileHistory* g_RecentIsoList = NULL;
|
||||||
|
CoreEmuThread* g_EmuThread = NULL;
|
||||||
|
|
||||||
namespace Exception
|
namespace Exception
|
||||||
{
|
{
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// Exception used to perfom an "errorless" termination of the app during OnInit
|
// Exception used to perform an "errorless" termination of the app during OnInit
|
||||||
// procedures. This happens when a user cancels out of startup prompts/wizards.
|
// procedures. This happens when a user cancels out of startup prompts/wizards.
|
||||||
//
|
//
|
||||||
class StartupAborted : public BaseException
|
class StartupAborted : public BaseException
|
||||||
|
@ -166,6 +167,7 @@ bool Pcsx2App::OnInit()
|
||||||
wxApp::OnInit();
|
wxApp::OnInit();
|
||||||
|
|
||||||
g_Conf = new AppConfig();
|
g_Conf = new AppConfig();
|
||||||
|
g_EmuThread = new CoreEmuThread();
|
||||||
|
|
||||||
wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
|
wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
|
||||||
|
|
||||||
|
@ -231,10 +233,17 @@ bool Pcsx2App::OnInit()
|
||||||
{
|
{
|
||||||
Dialogs::ConfigurationDialog( m_MainFrame ).ShowModal();
|
Dialogs::ConfigurationDialog( m_MainFrame ).ShowModal();
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
Connect( pxEVT_MSGBOX, wxCommandEventHandler( Pcsx2App::OnMessageBox ) );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Pcsx2App::OnMessageBox( wxCommandEvent& evt )
|
||||||
|
{
|
||||||
|
Msgbox::OnEvent( evt );
|
||||||
|
}
|
||||||
|
|
||||||
// Common exit handler which can be called from any event (though really it should
|
// Common exit handler which can be called from any event (though really it should
|
||||||
// be called only from CloseWindow handlers since that's the more appropriate way
|
// be called only from CloseWindow handlers since that's the more appropriate way
|
||||||
// to handle window closures)
|
// to handle window closures)
|
||||||
|
|
|
@ -0,0 +1,212 @@
|
||||||
|
/* Pcsx2 - Pc Ps2 Emulator
|
||||||
|
* Copyright (C) 2002-2009 Pcsx2 Team
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PrecompiledHeader.h"
|
||||||
|
#include "System.h"
|
||||||
|
#include "SaveState.h"
|
||||||
|
#include "ElfHeader.h"
|
||||||
|
#include "Plugins.h"
|
||||||
|
#include "CoreEmuThread.h"
|
||||||
|
|
||||||
|
#include "R5900.h"
|
||||||
|
#include "R3000A.h"
|
||||||
|
#include "VUmicro.h"
|
||||||
|
|
||||||
|
sptr CoreEmuThread::ExecuteTask()
|
||||||
|
{
|
||||||
|
while( !m_Done && (m_ExecMode != ExecMode_Running) )
|
||||||
|
{
|
||||||
|
m_ResumeEvent.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cpuReset();
|
||||||
|
SysClearExecutionCache();
|
||||||
|
OpenPlugins();
|
||||||
|
|
||||||
|
if( StateRecovery::HasState() )
|
||||||
|
{
|
||||||
|
// no need to boot bios or detect CDs when loading savestates.
|
||||||
|
// [TODO] : It might be useful to detect game SLUS/CRC and compare it against
|
||||||
|
// the savestate info, and issue a warning to the user since, chances are, they
|
||||||
|
// don't really want to run a game with the wrong ISO loaded into the emu.
|
||||||
|
StateRecovery::Recover();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScopedLock lock( m_lock_elf_file );
|
||||||
|
if( !m_elf_file.IsEmpty() )
|
||||||
|
{
|
||||||
|
// Skip Bios Hack -- Runs the PS2 BIOS stub, and then manually loads the ELF
|
||||||
|
// executable data, and injects the cpuRegs.pc with the address of the
|
||||||
|
// execution start point.
|
||||||
|
//
|
||||||
|
// This hack is necessary for non-CD ELF files, and is optional for game CDs
|
||||||
|
// (though not recommended for games because of rare ill side effects).
|
||||||
|
|
||||||
|
cpuExecuteBios();
|
||||||
|
loadElfFile( m_elf_file );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch( Exception::BaseException& ex )
|
||||||
|
{
|
||||||
|
Msgbox::Alert( ex.DisplayMessage() );
|
||||||
|
}
|
||||||
|
|
||||||
|
StateCheck();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreEmuThread::StateCheck()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
ScopedLock locker( m_lock_ExecMode );
|
||||||
|
|
||||||
|
switch( m_ExecMode )
|
||||||
|
{
|
||||||
|
case ExecMode_Idle:
|
||||||
|
// threads should never have an idle execution state set while the
|
||||||
|
// thread is in any way active or alive.
|
||||||
|
DevAssert( false, "Invalid execution state detected." );
|
||||||
|
break;
|
||||||
|
|
||||||
|
// These are not the case statements you're looking for. Move along.
|
||||||
|
case ExecMode_Running: break;
|
||||||
|
case ExecMode_Suspended: break;
|
||||||
|
|
||||||
|
case ExecMode_Suspending:
|
||||||
|
m_ExecMode = ExecMode_Suspended;
|
||||||
|
m_SuspendEvent.Post();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while( (m_ExecMode == ExecMode_Suspended) && !m_Done )
|
||||||
|
{
|
||||||
|
m_ResumeEvent.Wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreEmuThread::Start()
|
||||||
|
{
|
||||||
|
if( IsRunning() ) return;
|
||||||
|
|
||||||
|
m_running = false;
|
||||||
|
m_ExecMode = ExecMode_Idle;
|
||||||
|
m_Done = false;
|
||||||
|
m_resetProfilers = false;
|
||||||
|
m_resetRecompilers = false;
|
||||||
|
m_elf_file = wxEmptyString;
|
||||||
|
|
||||||
|
m_ResumeEvent.Reset();
|
||||||
|
m_SuspendEvent.Reset();
|
||||||
|
PersistentThread::Start();
|
||||||
|
|
||||||
|
pthread_detach( m_thread );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreEmuThread::Reset()
|
||||||
|
{
|
||||||
|
Cancel();
|
||||||
|
StateRecovery::Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resumes the core execution state, or does nothing is the core is already running. If
|
||||||
|
// settings were changed, resets will be performed as needed and emulation state resumed from
|
||||||
|
// memory savestates.
|
||||||
|
void CoreEmuThread::Resume()
|
||||||
|
{
|
||||||
|
Start();
|
||||||
|
|
||||||
|
{
|
||||||
|
ScopedLock locker( m_lock_ExecMode );
|
||||||
|
|
||||||
|
if( m_ExecMode == ExecMode_Running )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( m_ExecMode == ExecMode_Suspending )
|
||||||
|
{
|
||||||
|
// if there are resets to be done, then we need to make sure and wait for the
|
||||||
|
// emuThread to enter a fully suspended state before continuing...
|
||||||
|
|
||||||
|
if( m_resetRecompilers || m_resetProfilers )
|
||||||
|
{
|
||||||
|
locker.Unlock(); // no deadlocks please, thanks. :)
|
||||||
|
m_SuspendEvent.Wait();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_ExecMode = ExecMode_Running;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DevAssert( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Idle),
|
||||||
|
"EmuCoreThread is not in a suspended or idle state? wtf!" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_resetRecompilers || m_resetProfilers )
|
||||||
|
{
|
||||||
|
SysClearExecutionCache();
|
||||||
|
m_resetRecompilers = false;
|
||||||
|
m_resetProfilers = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ExecMode = ExecMode_Running;
|
||||||
|
m_ResumeEvent.Post();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pauses the emulation state at the next PS2 vsync, and returns control to the calling
|
||||||
|
// thread; or does nothing if the core is already suspended. Calling this thread from the
|
||||||
|
// Core thread will result in deadlock.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// isNonblocking - if set to true then the function will not block for emulation suspension.
|
||||||
|
// Defaults to false if parameter is not specified. Performing non-blocking suspension
|
||||||
|
// is mostly useful for starting certain non-Emu related gui activities (improves gui
|
||||||
|
// responsiveness).
|
||||||
|
//
|
||||||
|
void CoreEmuThread::Suspend( bool isBlocking )
|
||||||
|
{
|
||||||
|
{
|
||||||
|
ScopedLock locker( m_lock_ExecMode );
|
||||||
|
|
||||||
|
if( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Idle) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( m_ExecMode == ExecMode_Running )
|
||||||
|
m_ExecMode = ExecMode_Suspending;
|
||||||
|
|
||||||
|
DevAssert( m_ExecMode == ExecMode_Suspending, "ExecMode should be nothing other than Suspended..." );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_SuspendEvent.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Applies a full suite of new settings, which will automatically facilitate the necessary
|
||||||
|
// resets of the core and components (including plugins, if needed). The scope of resetting
|
||||||
|
// is determined by comparing the current settings against the new settings.
|
||||||
|
void CoreEmuThread::ApplySettings( const Pcsx2Config& src )
|
||||||
|
{
|
||||||
|
m_resetRecompilers = ( src.Cpu != EmuConfig.Cpu ) || ( src.Gamefixes != EmuConfig.Gamefixes ) || ( src.Speedhacks != EmuConfig.Speedhacks );
|
||||||
|
m_resetProfilers = (src.Profiler != EmuConfig.Profiler );
|
||||||
|
EmuConfig = src;
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/* Pcsx2 - Pc Ps2 Emulator
|
||||||
|
* Copyright (C) 2002-2009 Pcsx2 Team
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Utilities/Threading.h"
|
||||||
|
|
||||||
|
using namespace Threading;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CoreEmuThread
|
||||||
|
//
|
||||||
|
class CoreEmuThread : public PersistentThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum ExecutionMode
|
||||||
|
{
|
||||||
|
ExecMode_Idle,
|
||||||
|
ExecMode_Running,
|
||||||
|
ExecMode_Suspending,
|
||||||
|
ExecMode_Suspended
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
volatile ExecutionMode m_ExecMode;
|
||||||
|
volatile bool m_Done;
|
||||||
|
|
||||||
|
Semaphore m_ResumeEvent;
|
||||||
|
Semaphore m_SuspendEvent;
|
||||||
|
|
||||||
|
bool m_resetRecompilers;
|
||||||
|
bool m_resetProfilers;
|
||||||
|
|
||||||
|
wxString m_elf_file;
|
||||||
|
|
||||||
|
MutexLock m_lock_elf_file;
|
||||||
|
MutexLock m_lock_ExecMode;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CoreEmuThread() :
|
||||||
|
m_ExecMode( ExecMode_Idle )
|
||||||
|
, m_Done( false )
|
||||||
|
, m_ResumeEvent()
|
||||||
|
, m_SuspendEvent()
|
||||||
|
, m_resetRecompilers( false )
|
||||||
|
, m_resetProfilers( false )
|
||||||
|
|
||||||
|
, m_elf_file()
|
||||||
|
, m_lock_elf_file()
|
||||||
|
, m_lock_ExecMode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetElfFile( const wxString& text )
|
||||||
|
{
|
||||||
|
ScopedLock lock( m_lock_elf_file );
|
||||||
|
m_elf_file = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start();
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
bool IsSuspended() const { return (m_ExecMode == ExecMode_Suspended); }
|
||||||
|
void Suspend( bool isBlocking = true );
|
||||||
|
void Resume();
|
||||||
|
void ApplySettings( const Pcsx2Config& src );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
sptr ExecuteTask();
|
||||||
|
void StateCheck();
|
||||||
|
};
|
|
@ -262,62 +262,6 @@
|
||||||
<Filter
|
<Filter
|
||||||
Name="Misc"
|
Name="Misc"
|
||||||
>
|
>
|
||||||
<File
|
|
||||||
RelativePath="..\..\AsciiString.cpp"
|
|
||||||
>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
ExcludedFromBuild="true"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Devel|Win32"
|
|
||||||
ExcludedFromBuild="true"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32"
|
|
||||||
ExcludedFromBuild="true"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\AsciiString.h"
|
|
||||||
>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
ExcludedFromBuild="true"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Devel|Win32"
|
|
||||||
ExcludedFromBuild="true"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32"
|
|
||||||
ExcludedFromBuild="true"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\Dump.cpp"
|
RelativePath="..\..\Dump.cpp"
|
||||||
>
|
>
|
||||||
|
@ -1098,6 +1042,14 @@
|
||||||
RelativePath="..\..\x86\BaseblockEx.h"
|
RelativePath="..\..\x86\BaseblockEx.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\ps2\CoreEmuThread.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\ps2\CoreEmuThread.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\MemoryCard.cpp"
|
RelativePath="..\..\MemoryCard.cpp"
|
||||||
>
|
>
|
||||||
|
@ -1974,10 +1926,6 @@
|
||||||
RelativePath="..\..\gui\i18n.cpp"
|
RelativePath="..\..\gui\i18n.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\gui\i18n.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\gui\IniInterface.cpp"
|
RelativePath="..\..\gui\IniInterface.cpp"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1043,7 +1043,7 @@ static u32 eeScaleBlockCycles()
|
||||||
// setting "branch = 2";
|
// setting "branch = 2";
|
||||||
static void iBranchTest(u32 newpc, bool noDispatch)
|
static void iBranchTest(u32 newpc, bool noDispatch)
|
||||||
{
|
{
|
||||||
if( bExecBIOS ) CheckForBIOSEnd();
|
if( g_ExecBiosHack ) CheckForBIOSEnd();
|
||||||
|
|
||||||
// Check the Event scheduler if our "cycle target" has been reached.
|
// Check the Event scheduler if our "cycle target" has been reached.
|
||||||
// Equiv code to:
|
// Equiv code to:
|
||||||
|
|
Loading…
Reference in New Issue