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
|
||||
// Added support for various operators so that the struct is
|
||||
// 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;
|
||||
}
|
||||
|
||||
bool operator =( void* rightside )
|
||||
{
|
||||
p = rightside;
|
||||
return p != rightside.p;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -354,12 +354,16 @@ namespace Exception
|
|||
explicit CreateStream(
|
||||
const char* objname,
|
||||
const char* msg=wxLt("File could not be created or opened") ) :
|
||||
Stream( wxString::FromAscii( objname ), msg ) {}
|
||||
Stream( wxString::FromAscii( objname ), msg ) {}
|
||||
|
||||
explicit CreateStream(
|
||||
const wxString& objname=wxString(),
|
||||
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.
|
||||
|
@ -373,8 +377,11 @@ namespace Exception
|
|||
explicit FileNotFound(
|
||||
const wxString& objname=wxString(),
|
||||
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
|
||||
|
|
|
@ -24,9 +24,28 @@
|
|||
|
||||
#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
|
||||
{
|
||||
///////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Define some useful object handles - wait events, mutexes.
|
||||
|
||||
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
|
||||
|
@ -56,7 +75,8 @@ namespace Threading
|
|||
void Post();
|
||||
void Post( int multiple );
|
||||
void Wait();
|
||||
int Count();
|
||||
void WaitNoCancel();
|
||||
int Count();
|
||||
};
|
||||
|
||||
struct MutexLock
|
||||
|
@ -84,42 +104,42 @@ namespace Threading
|
|||
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()'
|
||||
// method. Use Start() and Close() to start and shutdown the thread, and use m_post_event
|
||||
// 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
|
||||
// internally to post/receive events for the thread (make a public accessor for it in your
|
||||
// derived class if your thread utilizes the post).
|
||||
//
|
||||
// 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-
|
||||
// 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:
|
||||
typedef int (*PlainJoeFP)();
|
||||
pthread_t m_thread;
|
||||
int 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.
|
||||
pthread_t m_thread;
|
||||
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.
|
||||
|
||||
public:
|
||||
virtual ~Thread();
|
||||
Thread();
|
||||
virtual ~PersistentThread();
|
||||
PersistentThread();
|
||||
|
||||
virtual void Start();
|
||||
virtual void Close();
|
||||
virtual void Cancel( bool isBlocking = true );
|
||||
|
||||
// Gets the return code of the thread.
|
||||
// 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:
|
||||
// Used to dispatch the thread callback function.
|
||||
|
@ -128,7 +148,20 @@ namespace Threading
|
|||
static void* _internal_callback( void* func );
|
||||
|
||||
// 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
|
||||
// code inside a function or conditional block.
|
||||
//
|
||||
class ScopedLock : NoncopyableObject
|
||||
class ScopedLock : public NoncopyableObject
|
||||
{
|
||||
protected:
|
||||
MutexLock& m_lock;
|
||||
bool m_IsLocked;
|
||||
|
||||
public:
|
||||
virtual ~ScopedLock()
|
||||
{
|
||||
m_lock.Unlock();
|
||||
if( m_IsLocked )
|
||||
m_lock.Unlock();
|
||||
}
|
||||
|
||||
ScopedLock( MutexLock& locker ) :
|
||||
m_lock( locker )
|
||||
m_lock( locker )
|
||||
, m_IsLocked( true )
|
||||
{
|
||||
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
|
||||
// can be divided into two threads of 10,000 items each.
|
||||
//
|
||||
class BaseTaskThread : public Thread
|
||||
class BaseTaskThread : public PersistentThread
|
||||
{
|
||||
protected:
|
||||
volatile bool m_done;
|
||||
volatile bool m_Done;
|
||||
volatile bool m_TaskComplete;
|
||||
Semaphore m_post_TaskComplete;
|
||||
|
||||
public:
|
||||
virtual ~BaseTaskThread() {}
|
||||
BaseTaskThread() :
|
||||
m_done( false )
|
||||
m_Done( false )
|
||||
, m_TaskComplete( false )
|
||||
, m_post_TaskComplete()
|
||||
{
|
||||
}
|
||||
|
||||
// Tells the thread to exit and then waits for thread termination.
|
||||
// To force-terminate the thread without "nicely" waiting for the task to complete,
|
||||
// explicitly use the Thread::Close parent implementation instead.
|
||||
void Close()
|
||||
sptr Block()
|
||||
{
|
||||
if( m_terminated ) return;
|
||||
m_done = true;
|
||||
if( !m_running ) return m_returncode;
|
||||
m_Done = true;
|
||||
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
|
||||
// initialized internal variables / preparations for task execution.
|
||||
void PostTask()
|
||||
{
|
||||
jASSUME( !m_terminated );
|
||||
jASSUME( m_running );
|
||||
m_TaskComplete = false;
|
||||
m_post_TaskComplete.Reset();
|
||||
m_post_event.Post();
|
||||
}
|
||||
|
||||
// Blocks current thread execution pending the completion of the parallel task.
|
||||
void WaitForResult() const
|
||||
void WaitForResult()
|
||||
{
|
||||
if( m_terminated ) return;
|
||||
while( !m_TaskComplete )
|
||||
{
|
||||
Timeslice();
|
||||
SpinWait();
|
||||
}
|
||||
if( !m_running ) return;
|
||||
if( !m_TaskComplete )
|
||||
m_post_TaskComplete.Wait();
|
||||
else
|
||||
m_post_TaskComplete.Reset();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -237,18 +289,19 @@ namespace Threading
|
|||
// all your necessary processing work here.
|
||||
virtual void Task()=0;
|
||||
|
||||
int Callback()
|
||||
sptr ExecuteTask()
|
||||
{
|
||||
do
|
||||
{
|
||||
// Wait for a job!
|
||||
m_post_event.Wait();
|
||||
|
||||
if( m_done ) break;
|
||||
if( m_Done ) break;
|
||||
Task();
|
||||
m_TaskComplete = true;
|
||||
} while( !m_done );
|
||||
|
||||
m_post_TaskComplete.Post();
|
||||
} while( !m_Done );
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace Exception
|
|||
|
||||
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).
|
||||
__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
|
||||
{
|
||||
Thread::Thread() :
|
||||
PersistentThread::PersistentThread() :
|
||||
m_thread()
|
||||
, m_returncode( 0 )
|
||||
, m_terminated( false )
|
||||
, m_running( false )
|
||||
, 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 )
|
||||
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 )
|
||||
pthread_cancel( m_thread );
|
||||
pthread_join( m_thread, NULL );
|
||||
if( !m_running ) return;
|
||||
m_running = false;
|
||||
|
||||
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 )
|
||||
throw std::logic_error( "Thread is still running. No return code is available." );
|
||||
bool isOwner = (pthread_self() == m_thread);
|
||||
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;
|
||||
}
|
||||
|
||||
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.
|
||||
// Let's not use it. (Air)
|
||||
|
@ -123,6 +177,22 @@ namespace Threading
|
|||
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 retval;
|
||||
|
|
|
@ -72,20 +72,5 @@ namespace Threading
|
|||
{
|
||||
__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();
|
||||
|
||||
wxString str;
|
||||
int result = GetPS2ElfName(str);
|
||||
GetPS2ElfName(str);
|
||||
|
||||
// Now's a good time to reload the ELF info...
|
||||
if( ElfCRC == 0 )
|
||||
|
|
220
pcsx2/Config.h
220
pcsx2/Config.h
|
@ -32,6 +32,14 @@ enum PluginsEnum_t
|
|||
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
|
||||
//
|
||||
|
@ -50,28 +58,56 @@ class Pcsx2Config
|
|||
public:
|
||||
struct ProfilerOptions
|
||||
{
|
||||
bool
|
||||
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]
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
bool
|
||||
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 );
|
||||
|
||||
bool operator ==( const ProfilerOptions& right ) const
|
||||
{
|
||||
return OpEqu( bits );
|
||||
}
|
||||
|
||||
bool operator !=( const ProfilerOptions& right ) const
|
||||
{
|
||||
return !this->operator ==( right );
|
||||
}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
struct RecompilerOptions
|
||||
{
|
||||
bool
|
||||
EnableEE:1,
|
||||
EnableIOP:1,
|
||||
EnableVU0:1,
|
||||
EnableVU1:1;
|
||||
|
||||
bool
|
||||
UseMicroVU0:1,
|
||||
UseMicroVU1:1;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
bool
|
||||
EnableEE:1,
|
||||
EnableIOP:1,
|
||||
EnableVU0:1,
|
||||
EnableVU1:1;
|
||||
|
||||
bool
|
||||
UseMicroVU0:1,
|
||||
UseMicroVU1:1;
|
||||
};
|
||||
u8 bits;
|
||||
};
|
||||
|
||||
RecompilerOptions() : bits( 0 ) { }
|
||||
|
||||
void Load( const wxString& srcfile );
|
||||
void Load( const wxInputStream& srcstream );
|
||||
|
@ -80,29 +116,64 @@ public:
|
|||
|
||||
void LoadSave( IniInterface& conf );
|
||||
|
||||
bool operator ==( const RecompilerOptions& right ) const
|
||||
{
|
||||
return OpEqu( bits );
|
||||
}
|
||||
|
||||
bool operator !=( const RecompilerOptions& right ) const
|
||||
{
|
||||
return !this->operator ==( right );
|
||||
}
|
||||
|
||||
} Recompiler;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
struct CpuOptions
|
||||
{
|
||||
RecompilerOptions Recompiler;
|
||||
|
||||
u32 sseMXCSR;
|
||||
u32 sseVUMXCSR;
|
||||
|
||||
bool
|
||||
vuOverflow:1,
|
||||
vuExtraOverflow:1,
|
||||
vuSignOverflow:1,
|
||||
vuUnderflow:1;
|
||||
|
||||
bool
|
||||
fpuOverflow:1,
|
||||
fpuExtraOverflow:1,
|
||||
fpuFullMode:1;
|
||||
struct
|
||||
{
|
||||
union
|
||||
{
|
||||
bool
|
||||
vuOverflow:1,
|
||||
vuExtraOverflow:1,
|
||||
vuSignOverflow:1,
|
||||
vuUnderflow:1;
|
||||
|
||||
bool
|
||||
fpuOverflow:1,
|
||||
fpuExtraOverflow:1,
|
||||
fpuFullMode:1;
|
||||
};
|
||||
u8 bits;
|
||||
};
|
||||
|
||||
ProfilerOptions Profiler;
|
||||
RecompilerOptions Recompiler;
|
||||
CpuOptions() :
|
||||
sseMXCSR( DEFAULT_sseMXCSR )
|
||||
, sseVUMXCSR( DEFAULT_sseVUMXCSR )
|
||||
, bits( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
bool
|
||||
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.
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
bool
|
||||
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 );
|
||||
|
||||
bool operator ==( const GamefixOptions& right ) const
|
||||
{
|
||||
return OpEqu( bits );
|
||||
}
|
||||
|
||||
bool operator !=( const GamefixOptions& right ) const
|
||||
{
|
||||
return !this->operator ==( right );
|
||||
}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
struct SpeedhackOptions
|
||||
{
|
||||
int
|
||||
EECycleRate:2, // EE cyclerate selector (1.0, 1.5, 2.0)
|
||||
VUCycleSteal:3, // VU Cycle Stealer factor (0, 1, 2, or 3)
|
||||
IopCycleRate_X2:1, // enables the x2 multiplier of the IOP cyclerate
|
||||
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...
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int
|
||||
EECycleRate:2, // EE cyclerate selector (1.0, 1.5, 2.0)
|
||||
VUCycleSteal:3, // VU Cycle Stealer factor (0, 1, 2, or 3)
|
||||
IopCycleRate_X2:1, // enables the x2 multiplier of the IOP cyclerate
|
||||
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 );
|
||||
|
||||
bool operator ==( const SpeedhackOptions& right ) const
|
||||
{
|
||||
return OpEqu( bits );
|
||||
}
|
||||
|
||||
bool operator !=( const SpeedhackOptions& right ) const
|
||||
{
|
||||
return !this->operator ==( right );
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
bool CdvdVerboseReads:1; // enables cdvd read activity verbosely dumped to the console
|
||||
bool CdvdDumpBlocks:1;
|
||||
bool EnablePatches:1;
|
||||
bool CdvdDumpBlocks:1; // enables cdvd block dumping
|
||||
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)
|
||||
bool closeGSonEsc:1;
|
||||
|
@ -169,6 +281,7 @@ public:
|
|||
VideoOptions Video;
|
||||
SpeedhackOptions Speedhacks;
|
||||
GamefixOptions Gamefixes;
|
||||
ProfilerOptions Profiler;
|
||||
|
||||
void Load( const wxString& srcfile );
|
||||
void Load( const wxInputStream& srcstream );
|
||||
|
@ -178,21 +291,6 @@ public:
|
|||
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
|
||||
//
|
||||
|
@ -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_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 ---------------
|
||||
|
||||
#define SHIFT_RECOMPILE // Speed majorly reduced if disabled
|
||||
|
|
|
@ -505,28 +505,27 @@ u32 loadElfCRC( const char* filename )
|
|||
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
|
||||
// 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();
|
||||
|
||||
if( filename.IsEmpty() ) return;
|
||||
|
||||
int elfsize;
|
||||
Console::Status( wxsFormat( L"loadElfFile: %s", filename.c_str() ) );
|
||||
|
||||
const wxCharBuffer buffer( filename.ToAscii() );
|
||||
const char* fnptr = buffer.data();
|
||||
|
||||
bool useCdvdSource=false;
|
||||
|
||||
if( !filename.StartsWith( L"cdrom0:" ) && !filename.StartsWith( L"cdrom1:" ) )
|
||||
{
|
||||
// Loading from a file (or non-cd image)
|
||||
|
@ -536,23 +535,25 @@ int loadElfFile(const wxString& filename)
|
|||
else
|
||||
{
|
||||
// Loading from a CD rom or CD image.
|
||||
useCdvdSource = true;
|
||||
TocEntry toc;
|
||||
IsoFS_init( );
|
||||
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;
|
||||
}
|
||||
|
||||
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 );
|
||||
|
||||
if( elfobj.proghead == NULL )
|
||||
{
|
||||
throw Exception::CpuStateShutdown(
|
||||
wxsFormat( L"Invalid ELF header encountered in file:\n\t%s", elfobj.filename.c_str() ),
|
||||
wxsFormat( L"Invalid ELF header, file: %s", elfobj.filename.c_str() )
|
||||
throw Exception::BadStream( filename, useCdvdSource ?
|
||||
wxLt("Invalid ELF file header. The CD-Rom may be damaged, or the ISO image corrupted.") :
|
||||
wxLt("Invalid ELF file.")
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -583,6 +584,6 @@ int loadElfFile(const wxString& filename)
|
|||
|
||||
ElfApplyPatches();
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,9 +24,9 @@ extern char args[256]; //to be filled by GUI
|
|||
extern unsigned int args_ptr;
|
||||
|
||||
//-------------------
|
||||
int loadElfFile(const wxString& filename);
|
||||
u32 loadElfCRC(const char *filename);
|
||||
void ElfApplyPatches();
|
||||
extern void loadElfFile(const wxString& filename);
|
||||
extern u32 loadElfCRC(const char *filename);
|
||||
extern void ElfApplyPatches();
|
||||
|
||||
extern u32 ElfCRC;
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@ enum GS_RINGTYPE
|
|||
, GS_RINGTYPE_QUIT
|
||||
};
|
||||
|
||||
class mtgsThreadObject : public Threading::Thread
|
||||
class mtgsThreadObject : public Threading::PersistentThread
|
||||
{
|
||||
friend class SaveState;
|
||||
|
||||
|
@ -225,7 +225,7 @@ public:
|
|||
virtual ~mtgsThreadObject();
|
||||
|
||||
void Start();
|
||||
void Close();
|
||||
void Cancel();
|
||||
void Reset();
|
||||
void GIFSoftReset( int mask );
|
||||
|
||||
|
@ -276,7 +276,7 @@ protected:
|
|||
uint _PrepForSimplePacket();
|
||||
void _FinishSimplePacket( uint future_writepos );
|
||||
|
||||
int Callback();
|
||||
sptr ExecuteTask();
|
||||
};
|
||||
|
||||
extern mtgsThreadObject* mtgsThread;
|
||||
|
|
|
@ -177,7 +177,7 @@ typedef void (*GIFRegHandler)(const u32* data);
|
|||
static GIFRegHandler s_GSHandlers[3] = { RegHandlerSIGNAL, RegHandlerFINISH, RegHandlerLABEL };
|
||||
|
||||
mtgsThreadObject::mtgsThreadObject() :
|
||||
Thread()
|
||||
PersistentThread()
|
||||
, m_RingPos( 0 )
|
||||
, m_WritePos( 0 )
|
||||
|
||||
|
@ -204,7 +204,7 @@ mtgsThreadObject::mtgsThreadObject() :
|
|||
|
||||
void mtgsThreadObject::Start()
|
||||
{
|
||||
Thread::Start();
|
||||
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.
|
||||
|
@ -217,10 +217,10 @@ void mtgsThreadObject::Start()
|
|||
|
||||
mtgsThreadObject::~mtgsThreadObject()
|
||||
{
|
||||
Close();
|
||||
Cancel();
|
||||
}
|
||||
|
||||
void mtgsThreadObject::Close()
|
||||
void mtgsThreadObject::Cancel()
|
||||
{
|
||||
Console::WriteLn( "MTGS > Closing GS thread..." );
|
||||
SendSimplePacket( GS_RINGTYPE_QUIT, 0, 0, 0 );
|
||||
|
@ -499,7 +499,7 @@ struct PacketTagType
|
|||
#ifndef __LINUX__
|
||||
extern bool renderswitch;
|
||||
#endif
|
||||
int mtgsThreadObject::Callback()
|
||||
sptr mtgsThreadObject::ExecuteTask()
|
||||
{
|
||||
Console::WriteLn("MTGS > Thread Started, Opening GS Plugin...");
|
||||
|
||||
|
|
|
@ -805,7 +805,7 @@ void memReset()
|
|||
wxString Bios( g_Conf->FullpathToBios() );
|
||||
|
||||
long filesize = Path::GetFileSize( Bios );
|
||||
if( filesize <= 0 )
|
||||
if( filesize > 0 )
|
||||
{
|
||||
wxFile fp( Bios.c_str() );
|
||||
fp.Read( PS2MEM_ROM, min( (long)Ps2MemSize::Rom, filesize ) );
|
||||
|
@ -813,7 +813,14 @@ void memReset()
|
|||
else
|
||||
{
|
||||
// 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();
|
||||
|
|
|
@ -237,6 +237,10 @@ bool IsBIOS(const wxString& filename, wxString& description)
|
|||
return false; //fail quietly
|
||||
}
|
||||
|
||||
// return value:
|
||||
// 0 - Invalid or unknown disc.
|
||||
// 1 - PS1 CD
|
||||
// 2 - PS2 CD
|
||||
int GetPS2ElfName( wxString& name )
|
||||
{
|
||||
int f;
|
||||
|
@ -262,7 +266,7 @@ int GetPS2ElfName( wxString& name )
|
|||
if (pos==NULL){
|
||||
pos=strstr(buffer, "BOOT");
|
||||
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 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(),
|
||||
|
||||
// translated message:
|
||||
wxsFormat( L"Error loading saveslot %d. Emulator reset.", StatesC )
|
||||
wxsFormat( _("Error loading saveslot %d. Emulator reset."), StatesC )
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -76,7 +76,6 @@ void Pcsx2Config::CpuOptions::LoadSave( IniInterface& ini )
|
|||
IniBitBool( fpuFullMode, false );
|
||||
|
||||
Recompiler.LoadSave( ini );
|
||||
Profiler.LoadSave( ini );
|
||||
|
||||
ini.SetPath( L".." );
|
||||
}
|
||||
|
@ -112,6 +111,7 @@ void Pcsx2Config::LoadSave( IniInterface& ini )
|
|||
Cpu.LoadSave( ini );
|
||||
Video.LoadSave( ini );
|
||||
Gamefixes.LoadSave( ini );
|
||||
Profiler.LoadSave( ini );
|
||||
|
||||
ini.SetPath( L".." );
|
||||
ini.Flush();
|
||||
|
|
|
@ -720,14 +720,7 @@ void InitPlugins()
|
|||
return 0;*/
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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)
|
||||
void OpenPlugins()
|
||||
{
|
||||
/*if (!plugins_initialized)
|
||||
{
|
||||
|
|
|
@ -113,7 +113,7 @@ extern PluginManager* g_plugins;
|
|||
void LoadPlugins();
|
||||
void ReleasePlugins();
|
||||
|
||||
void OpenPlugins(const char* pTitleFilename);
|
||||
void OpenPlugins();
|
||||
void ClosePlugins( bool closegs );
|
||||
void CloseGS();
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ PCSX2_ALIGNED16(fpuRegisters fpuRegs);
|
|||
PCSX2_ALIGNED16(tlbs tlb[48]);
|
||||
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 const uint eeWaitCycles = 3072;
|
||||
|
@ -556,21 +556,27 @@ __forceinline void cpuTestHwInts() {
|
|||
// 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
|
||||
// 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()
|
||||
{
|
||||
// Set the video mode to user's default request:
|
||||
gsSetRegionMode( (GS_RegionMode)EmuConfig.Video.DefaultRegionMode );
|
||||
|
||||
Console::Notice( "* PCSX2 *: ExecuteBios" );
|
||||
Console::Status( "Executing Bios Stub..." );
|
||||
|
||||
bExecBIOS = TRUE;
|
||||
while (cpuRegs.pc != 0x00200008 &&
|
||||
cpuRegs.pc != 0x00100008) {
|
||||
g_ExecBiosHack = true;
|
||||
while( cpuRegs.pc != 0x00200008 &&
|
||||
cpuRegs.pc != 0x00100008 )
|
||||
{
|
||||
g_nextBranchCycle = cpuRegs.cycle;
|
||||
Cpu->ExecuteBlock();
|
||||
}
|
||||
g_ExecBiosHack = false;
|
||||
|
||||
bExecBIOS = FALSE;
|
||||
// {
|
||||
// FILE* f = fopen("eebios.bin", "wb");
|
||||
// fwrite(PSM(0x80000000), 0x100000, 1, f);
|
||||
|
@ -586,12 +592,12 @@ void cpuExecuteBios()
|
|||
// REC_CLEARM(0x00100008);
|
||||
// REC_CLEARM(cpuRegs.pc);
|
||||
|
||||
// Reset the EErecs here, because the bios generates "slow" blocks that have hacky
|
||||
// bBiosEnd checks in them and stuff. This deletes them so that the recs replace them
|
||||
// Reset the EErecs here, because the bios generates "slow" blocks that have
|
||||
// g_ExecBiosHack checks in them. This deletes them so that the recs replace them
|
||||
// with new faster versions:
|
||||
Cpu->Reset();
|
||||
|
||||
Console::Notice("* PCSX2 *: ExecuteBios Complete");
|
||||
Console::Notice("Execute Bios Stub Complete");
|
||||
//GSprintf(5, "PCSX2 " PCSX2_VERSION "\nExecuteBios Complete\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ extern const char* const bios[256];
|
|||
|
||||
extern s32 EEsCycle;
|
||||
extern u32 EEoCycle;
|
||||
extern u32 bExecBIOS;
|
||||
extern bool g_ExecBiosHack;
|
||||
|
||||
union GPR_reg { // Declare union type GPR register
|
||||
u64 UD[2]; //128 bits
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace StateRecovery {
|
|||
void Recover()
|
||||
{
|
||||
// Just in case they weren't initialized earlier (no harm in calling this multiple times)
|
||||
OpenPlugins(NULL);
|
||||
OpenPlugins();
|
||||
|
||||
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!
|
||||
cpuReset();
|
||||
OpenPlugins( NULL );
|
||||
OpenPlugins();
|
||||
|
||||
joe.FreezeAll();
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
Pcsx2Config EmuConfig = {0};
|
||||
Pcsx2Config EmuConfig;
|
||||
|
||||
// disable all session overrides by default...
|
||||
SessionOverrideFlags g_Session = {false};
|
||||
|
@ -334,54 +334,6 @@ void SysEndExecution()
|
|||
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()
|
||||
{
|
||||
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 SysClearExecutionCache(); // clears recompiled execution caches!
|
||||
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 );
|
||||
extern void SysEndExecution(); // terminates plugins, saves GS state (if enabled), and signals emulation loop to end.
|
||||
|
||||
// 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
|
||||
|
@ -82,6 +81,8 @@ extern void vSyncDebugStuff( uint frame );
|
|||
//
|
||||
namespace Msgbox
|
||||
{
|
||||
extern void OnEvent( wxCommandEvent& evt );
|
||||
|
||||
// Pops up an alert Dialog Box with a singular "OK" button.
|
||||
// Always returns false. Replacement for SysMessage.
|
||||
extern bool Alert( const wxString& text );
|
||||
|
@ -91,3 +92,4 @@ namespace Msgbox
|
|||
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
|
||||
// of the console logger.
|
||||
//
|
||||
class ConsoleTestThread : public Thread
|
||||
class ConsoleTestThread : public PersistentThread
|
||||
{
|
||||
protected:
|
||||
volatile bool m_done;
|
||||
int Callback();
|
||||
sptr ExecuteTask();
|
||||
|
||||
public:
|
||||
ConsoleTestThread() :
|
||||
|
@ -275,6 +275,7 @@ public:
|
|||
protected:
|
||||
void ReadUserModeSettings();
|
||||
bool TryOpenConfigCwd();
|
||||
void OnMessageBox( wxCommandEvent& evt );
|
||||
};
|
||||
|
||||
DECLARE_APP(Pcsx2App)
|
||||
|
|
|
@ -45,7 +45,7 @@ DEFINE_EVENT_TYPE(wxEVT_SemaphoreWait);
|
|||
using Console::Colors;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
int ConsoleTestThread::Callback()
|
||||
sptr ConsoleTestThread::ExecuteTask()
|
||||
{
|
||||
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
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool OkCancel( const wxString& text )
|
||||
{
|
||||
int result = wxMessageBox( text, L"Pcsx2 Message", wxOK | wxCANCEL, wxGetApp().GetTopWindow() );
|
||||
return result == wxOK;
|
||||
if( wxThread::IsMain() )
|
||||
{
|
||||
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 "App.h"
|
||||
#include "Mainframe.h"
|
||||
|
||||
// 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.
|
||||
|
@ -44,6 +44,8 @@ namespace HostGui
|
|||
|
||||
void BeginExecution()
|
||||
{
|
||||
wxASSERT( g_EmuThread != NULL );
|
||||
g_EmuThread->Resume();
|
||||
}
|
||||
|
||||
void __fastcall KeyEvent( keyEvent* ev )
|
||||
|
|
|
@ -167,8 +167,7 @@ void MainEmuFrame::ConnectMenus()
|
|||
ConnectMenu( Menu_RunELF, Menu_OpenELF_Click );
|
||||
ConnectMenu( Menu_Run_Exit, Menu_Exit_Click );
|
||||
|
||||
ConnectMenu( Menu_SuspendExec, Menu_Suspend_Click );
|
||||
ConnectMenu( Menu_ResumeExec, Menu_Resume_Click );
|
||||
ConnectMenu( Menu_PauseExec, Menu_Pause_Click );
|
||||
ConnectMenu( Menu_Reset, Menu_Reset_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_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
|
||||
|
@ -275,15 +276,14 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
|
|||
|
||||
m_menuRun.Append(Menu_RunIso, _("Run ISO"), MakeIsoMenu() );
|
||||
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_RunELF, _("Run ELF File..."), _("For running raw PS2 binaries."));
|
||||
m_menuRun.Append(Menu_SkipBiosToggle,_("ELF Injection Hack"), _("Skips PS2 splash screens when booting from Iso or CDVD media"));
|
||||
|
||||
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.Append(Menu_SuspendExec, _("Suspend"), _("Stops emulation dead in its tracks"));
|
||||
m_menuRun.Append(Menu_ResumeExec, _("Resume"), _("Resumes suspended emulation"));
|
||||
m_menuRun.Append(Menu_PauseExec, _("Pause"), _("Stops emulation dead in its tracks"));
|
||||
m_menuRun.Append(Menu_States, _("States"), MakeStatesMenu(), wxEmptyString);
|
||||
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_CLOSE_WINDOW, wxCloseEventHandler(MainEmuFrame::OnCloseWindow) );
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#include <wx/docview.h>
|
||||
|
||||
#include "App.h"
|
||||
#include "PS2/CoreEmuThread.h"
|
||||
|
||||
extern CoreEmuThread* g_EmuThread;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
@ -50,8 +53,7 @@ protected:
|
|||
Menu_RunELF,
|
||||
Menu_SkipBiosToggle, // enables the Bios Skip speedhack
|
||||
Menu_EnableSkipBios, // check marked menu that toggles Skip Bios boot feature.
|
||||
Menu_SuspendExec, // suspends active emulation
|
||||
Menu_ResumeExec, // restores active emulation
|
||||
Menu_PauseExec, // suspends/resumes active emulation
|
||||
Menu_Reset, // Issues a complete reset.
|
||||
Menu_States, // Opens states submenu
|
||||
Menu_Run_Exit = wxID_EXIT,
|
||||
|
@ -134,6 +136,8 @@ protected:
|
|||
|
||||
wxMenuItem& m_MenuItem_Console;
|
||||
|
||||
bool m_IsPaused;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// MainEmuFrame Constructors and Member Methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -142,6 +146,8 @@ public:
|
|||
MainEmuFrame(wxWindow* parent, const wxString& title);
|
||||
void OnLogBoxHidden();
|
||||
|
||||
bool IsPaused() const { return m_IsPaused; }
|
||||
|
||||
protected:
|
||||
void InitLogBoxPosition( AppConfig::ConsoleLogOptions& conf );
|
||||
|
||||
|
@ -160,8 +166,7 @@ protected:
|
|||
void Menu_SaveStateOther_Click(wxCommandEvent &event);
|
||||
void Menu_Exit_Click(wxCommandEvent &event);
|
||||
|
||||
void Menu_Suspend_Click(wxCommandEvent &event);
|
||||
void Menu_Resume_Click(wxCommandEvent &event);
|
||||
void Menu_Pause_Click(wxCommandEvent &event);
|
||||
void Menu_Reset_Click(wxCommandEvent &event);
|
||||
|
||||
void Menu_Debug_Open_Click(wxCommandEvent &event);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "HostGui.h"
|
||||
#include "CDVD/CDVD.h"
|
||||
|
||||
#include "MainFrame.h"
|
||||
|
@ -37,20 +38,63 @@ static const wxChar* isoFilterTypes =
|
|||
|
||||
void MainEmuFrame::Menu_RunIso_Click(wxCommandEvent &event)
|
||||
{
|
||||
g_EmuThread->Suspend();
|
||||
|
||||
Console::Status( L"Default Folder: " + g_Conf->Folders.RunIso.ToString() );
|
||||
wxFileDialog ctrl( this, _("Run PS2 Iso..."), g_Conf->Folders.RunIso.ToString(), wxEmptyString,
|
||||
isoFilterTypes, wxFD_OPEN | wxFD_FILE_MUST_EXIST );
|
||||
|
||||
if( ctrl.ShowModal() == wxID_CANCEL ) return;
|
||||
g_Conf->Folders.RunIso = ctrl.GetPath();
|
||||
|
||||
|
||||
//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)
|
||||
{
|
||||
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 );
|
||||
SysPrepareExecution( wxEmptyString, true );
|
||||
g_EmuThread->Resume();
|
||||
|
||||
//HostGui::BeginExecution();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_IsoRecent_Click(wxCommandEvent &event)
|
||||
|
@ -76,11 +120,7 @@ void MainEmuFrame::Menu_Exit_Click(wxCommandEvent &event)
|
|||
Close();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_Suspend_Click(wxCommandEvent &event)
|
||||
{
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_Resume_Click(wxCommandEvent &event)
|
||||
void MainEmuFrame::Menu_Pause_Click(wxCommandEvent &event)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -306,7 +306,7 @@ namespace Panels
|
|||
}
|
||||
};
|
||||
|
||||
class EnumThread : public Threading::Thread
|
||||
class EnumThread : public Threading::PersistentThread
|
||||
{
|
||||
public:
|
||||
EnumeratedPluginInfo* Results; // array of plugin results.
|
||||
|
@ -317,10 +317,10 @@ namespace Panels
|
|||
public:
|
||||
virtual ~EnumThread();
|
||||
EnumThread( PluginSelectorPanel& master );
|
||||
void Close();
|
||||
void Cancel();
|
||||
|
||||
protected:
|
||||
int Callback();
|
||||
sptr ExecuteTask();
|
||||
};
|
||||
|
||||
// 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
|
||||
|
||||
Panels::PluginSelectorPanel::EnumThread::EnumThread( PluginSelectorPanel& master ) :
|
||||
Thread()
|
||||
PersistentThread()
|
||||
, Results( new EnumeratedPluginInfo[master.FileCount()] )
|
||||
, m_master( master )
|
||||
, m_cancel( false )
|
||||
|
@ -347,17 +347,17 @@ Panels::PluginSelectorPanel::EnumThread::EnumThread( PluginSelectorPanel& master
|
|||
Panels::PluginSelectorPanel::EnumThread::~EnumThread()
|
||||
{
|
||||
safe_delete_array( Results );
|
||||
Close();
|
||||
Cancel();
|
||||
}
|
||||
|
||||
void Panels::PluginSelectorPanel::EnumThread::Close()
|
||||
void Panels::PluginSelectorPanel::EnumThread::Cancel()
|
||||
{
|
||||
m_cancel = true;
|
||||
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 )
|
||||
{
|
||||
|
|
|
@ -30,11 +30,12 @@ IMPLEMENT_APP(Pcsx2App)
|
|||
|
||||
AppConfig* g_Conf = NULL;
|
||||
wxFileHistory* g_RecentIsoList = NULL;
|
||||
CoreEmuThread* g_EmuThread = NULL;
|
||||
|
||||
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.
|
||||
//
|
||||
class StartupAborted : public BaseException
|
||||
|
@ -166,6 +167,7 @@ bool Pcsx2App::OnInit()
|
|||
wxApp::OnInit();
|
||||
|
||||
g_Conf = new AppConfig();
|
||||
g_EmuThread = new CoreEmuThread();
|
||||
|
||||
wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
|
||||
|
||||
|
@ -231,10 +233,17 @@ bool Pcsx2App::OnInit()
|
|||
{
|
||||
Dialogs::ConfigurationDialog( m_MainFrame ).ShowModal();
|
||||
}*/
|
||||
|
||||
Connect( pxEVT_MSGBOX, wxCommandEventHandler( Pcsx2App::OnMessageBox ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Pcsx2App::OnMessageBox( wxCommandEvent& evt )
|
||||
{
|
||||
Msgbox::OnEvent( evt );
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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
|
||||
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
|
||||
RelativePath="..\..\Dump.cpp"
|
||||
>
|
||||
|
@ -1098,6 +1042,14 @@
|
|||
RelativePath="..\..\x86\BaseblockEx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\ps2\CoreEmuThread.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\ps2\CoreEmuThread.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\MemoryCard.cpp"
|
||||
>
|
||||
|
@ -1974,10 +1926,6 @@
|
|||
RelativePath="..\..\gui\i18n.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\i18n.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\IniInterface.cpp"
|
||||
>
|
||||
|
|
|
@ -1043,7 +1043,7 @@ static u32 eeScaleBlockCycles()
|
|||
// setting "branch = 2";
|
||||
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.
|
||||
// Equiv code to:
|
||||
|
|
Loading…
Reference in New Issue