mirror of https://github.com/PCSX2/pcsx2.git
Reorganized the exception/signal handlers, setjmp/longjmp, and SysCoreThread stuff:
* Exception/Signal handling now uses an EventSource, so that multiple handlers can be registered. This is in preparation for (eventual) more complete MIPS TLB support in the VTLB memory model. * Improved code isolation, so that recompiler-specific code is primarily in iR5900-32.cpp (cleans up Counters.cpp and SysCoreThread.cpp) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2063 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
cdb2d8f276
commit
efc35405f8
|
@ -84,10 +84,10 @@
|
||||||
<Unit filename="../../../3rdparty/google/type_traits.h" />
|
<Unit filename="../../../3rdparty/google/type_traits.h" />
|
||||||
<Unit filename="../../include/Utilities/Console.h" />
|
<Unit filename="../../include/Utilities/Console.h" />
|
||||||
<Unit filename="../../include/Utilities/Dependencies.h" />
|
<Unit filename="../../include/Utilities/Dependencies.h" />
|
||||||
|
<Unit filename="../../include/Utilities/EventSource.h" />
|
||||||
<Unit filename="../../include/Utilities/Exceptions.h" />
|
<Unit filename="../../include/Utilities/Exceptions.h" />
|
||||||
<Unit filename="../../include/Utilities/General.h" />
|
<Unit filename="../../include/Utilities/General.h" />
|
||||||
<Unit filename="../../include/Utilities/HashMap.h" />
|
<Unit filename="../../include/Utilities/HashMap.h" />
|
||||||
<Unit filename="../../include/Utilities/Listeners.h" />
|
|
||||||
<Unit filename="../../include/Utilities/MemcpyFast.h" />
|
<Unit filename="../../include/Utilities/MemcpyFast.h" />
|
||||||
<Unit filename="../../include/Utilities/Path.h" />
|
<Unit filename="../../include/Utilities/Path.h" />
|
||||||
<Unit filename="../../include/Utilities/RedtapeWindows.h" />
|
<Unit filename="../../include/Utilities/RedtapeWindows.h" />
|
||||||
|
|
|
@ -425,6 +425,10 @@
|
||||||
RelativePath="..\..\include\Utilities\Dependencies.h"
|
RelativePath="..\..\include\Utilities\Dependencies.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\include\Utilities\EventSource.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\include\Utilities\Exceptions.h"
|
RelativePath="..\..\include\Utilities\Exceptions.h"
|
||||||
>
|
>
|
||||||
|
@ -441,10 +445,6 @@
|
||||||
RelativePath="..\..\include\intrin_x86.h"
|
RelativePath="..\..\include\intrin_x86.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\include\Utilities\Listeners.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\include\Utilities\lnx_memzero.h"
|
RelativePath="..\..\include\Utilities\lnx_memzero.h"
|
||||||
>
|
>
|
||||||
|
|
|
@ -16,12 +16,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <wx/event.h>
|
|
||||||
|
class wxCommandEvent;
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// EventListener< typename EvtType >
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
template< typename EvtType >
|
template< typename EvtType >
|
||||||
struct EventListener
|
struct EventListener
|
||||||
{
|
{
|
||||||
typedef void FuncType( void* object, const EvtType& evt );
|
typedef void __fastcall FuncType( void* object, EvtType& evt );
|
||||||
|
|
||||||
void* object;
|
void* object;
|
||||||
FuncType* OnEvent;
|
FuncType* OnEvent;
|
||||||
|
@ -49,6 +54,10 @@ struct EventListener
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// EventSource< template EvtType >
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
template< typename EvtType >
|
template< typename EvtType >
|
||||||
class EventSource
|
class EventSource
|
||||||
{
|
{
|
||||||
|
@ -58,23 +67,38 @@ public:
|
||||||
typedef typename ListenerList::iterator Handle;
|
typedef typename ListenerList::iterator Handle;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
typedef typename ListenerList::const_iterator ConstIterator;
|
||||||
|
|
||||||
ListenerList m_listeners;
|
ListenerList m_listeners;
|
||||||
|
|
||||||
|
// This is a cached copy of the listener list used to handle standard dispatching, which
|
||||||
|
// allows for self-modification of the EventSource's listener list by the listeners.
|
||||||
|
// Translation: The dispatcher uses this copy instead, to avoid iterator invalidation.
|
||||||
|
ListenerList m_cache_copy;
|
||||||
|
bool m_cache_valid;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
EventSource() : m_cache_valid( false )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~EventSource() throw() {}
|
virtual ~EventSource() throw() {}
|
||||||
|
|
||||||
virtual void Remove( const ListenerType& listener )
|
virtual void Remove( const ListenerType& listener )
|
||||||
{
|
{
|
||||||
|
m_cache_valid = false;
|
||||||
m_listeners.remove( listener );
|
m_listeners.remove( listener );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Remove( const Handle& listenerHandle )
|
virtual void Remove( const Handle& listenerHandle )
|
||||||
{
|
{
|
||||||
|
m_cache_valid = false;
|
||||||
m_listeners.erase( listenerHandle );
|
m_listeners.erase( listenerHandle );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Handle AddFast( const ListenerType& listener )
|
virtual Handle AddFast( const ListenerType& listener )
|
||||||
{
|
{
|
||||||
|
m_cache_valid = false;
|
||||||
m_listeners.push_front( listener );
|
m_listeners.push_front( listener );
|
||||||
return m_listeners.begin();
|
return m_listeners.begin();
|
||||||
}
|
}
|
||||||
|
@ -93,14 +117,21 @@ public:
|
||||||
Remove( ListenerType( objhandle, fnptr ) );
|
Remove( ListenerType( objhandle, fnptr ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dispatch( const EvtType& evt ) const
|
void Dispatch( EvtType& evt )
|
||||||
{
|
{
|
||||||
// Have to make a complete copy of the list, because the event stack can change:
|
if( !m_cache_valid )
|
||||||
|
{
|
||||||
|
m_cache_copy = m_listeners;
|
||||||
|
m_cache_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
ListenerList list( m_listeners );
|
_DispatchRaw( m_cache_copy.begin(), m_cache_copy.end(), evt );
|
||||||
|
}
|
||||||
|
|
||||||
typename ListenerList::const_iterator iter = list.begin();
|
protected:
|
||||||
while( iter != list.end() )
|
__forceinline void _DispatchRaw( ConstIterator& iter, const ConstIterator& iend, EvtType& evt )
|
||||||
|
{
|
||||||
|
while( iter != iend )
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -118,14 +149,15 @@ public:
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// EventListenerBinding
|
// EventListenerBinding< typename EvtType ?
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Encapsulated event listener binding, provides the "benefits" of object unwinding.
|
// Encapsulated event listener binding, provides the "benefits" of object unwinding.
|
||||||
//
|
//
|
||||||
template< typename EvtType = wxCommandEvent >
|
template< typename EvtType >
|
||||||
class EventListenerBinding
|
class EventListenerBinding
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -211,9 +243,7 @@ public:
|
||||||
template< typename EvtType >
|
template< typename EvtType >
|
||||||
void EventSource<EvtType>::RemoveObject( const void* object )
|
void EventSource<EvtType>::RemoveObject( const void* object )
|
||||||
{
|
{
|
||||||
// Iso C++ rules regarding temporaries, specifically that non-const temporaries are disallowed,
|
m_cache_valid = false;
|
||||||
// also removes any actual convenience factor that unary predicates may have actually offered. >_<
|
|
||||||
|
|
||||||
m_listeners.remove_if( PredicatesAreTheThingsOfNightmares<EvtType>( object ) );
|
m_listeners.remove_if( PredicatesAreTheThingsOfNightmares<EvtType>( object ) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,6 +280,7 @@ namespace Threading
|
||||||
bool IsRunning() const;
|
bool IsRunning() const;
|
||||||
bool IsSelf() const;
|
bool IsSelf() const;
|
||||||
wxString GetName() const;
|
wxString GetName() const;
|
||||||
|
bool HasPendingException() const { return !!m_except; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Extending classes should always implement your own OnStart(), which is called by
|
// Extending classes should always implement your own OnStart(), which is called by
|
||||||
|
|
|
@ -142,6 +142,8 @@ void Threading::PersistentThread::Start()
|
||||||
Detach(); // clean up previous thread handle, if one exists.
|
Detach(); // clean up previous thread handle, if one exists.
|
||||||
OnStart();
|
OnStart();
|
||||||
|
|
||||||
|
m_except = NULL;
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,10 @@
|
||||||
// use Freeze/Thaw in MMXRegisters, XMMRegisters, & Registers.
|
// use Freeze/Thaw in MMXRegisters, XMMRegisters, & Registers.
|
||||||
|
|
||||||
|
|
||||||
|
// used to disable register freezing during cpuBranchTests (registers
|
||||||
|
// are safe then since they've been completely flushed)
|
||||||
|
bool g_EEFreezeRegs = false;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
// MMX Register Freezing
|
// MMX Register Freezing
|
||||||
//
|
//
|
||||||
|
|
|
@ -440,8 +440,6 @@ __forceinline void rcntUpdate_hScanline()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CoreCancelDamnit = false;
|
|
||||||
|
|
||||||
__forceinline void rcntUpdate_vSync()
|
__forceinline void rcntUpdate_vSync()
|
||||||
{
|
{
|
||||||
s32 diff = (cpuRegs.cycle - vsyncCounter.sCycle);
|
s32 diff = (cpuRegs.cycle - vsyncCounter.sCycle);
|
||||||
|
@ -449,28 +447,7 @@ __forceinline void rcntUpdate_vSync()
|
||||||
|
|
||||||
if (vsyncCounter.Mode == MODE_VSYNC)
|
if (vsyncCounter.Mode == MODE_VSYNC)
|
||||||
{
|
{
|
||||||
eeRecIsReset = false;
|
Cpu->CheckExecutionState();
|
||||||
|
|
||||||
#ifndef PCSX2_SEH
|
|
||||||
if( CoreCancelDamnit || SysCoreThread::Get().HasPendingStateChangeRequest() )
|
|
||||||
{
|
|
||||||
longjmp( SetJmp_StateCheck, 1 );
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
mtgsThread.RethrowException();
|
|
||||||
SysCoreThread::Get().StateCheckInThread();
|
|
||||||
#endif
|
|
||||||
if( eeRecIsReset )
|
|
||||||
{
|
|
||||||
eeRecIsReset = false;
|
|
||||||
cpuSetBranch();
|
|
||||||
|
|
||||||
#ifndef PCSX2_SEH
|
|
||||||
longjmp( SetJmp_RecExecute, SetJmp_Dispatcher );
|
|
||||||
#else
|
|
||||||
throw Exception::ForceDispatcherReg();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
VSyncEnd(vsyncCounter.sCycle);
|
VSyncEnd(vsyncCounter.sCycle);
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,8 @@ public:
|
||||||
mtgsThreadObject();
|
mtgsThreadObject();
|
||||||
virtual ~mtgsThreadObject() throw();
|
virtual ~mtgsThreadObject() throw();
|
||||||
|
|
||||||
|
static mtgsThreadObject& Get();
|
||||||
|
|
||||||
// Waits for the GS to empty out the entire ring buffer contents.
|
// Waits for the GS to empty out the entire ring buffer contents.
|
||||||
// Used primarily for plugin startup/shutdown.
|
// Used primarily for plugin startup/shutdown.
|
||||||
void WaitGS();
|
void WaitGS();
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "R5900.h"
|
#include "R5900.h"
|
||||||
#include "R5900OpcodeTables.h"
|
#include "R5900OpcodeTables.h"
|
||||||
|
#include "System/SysThreads.h"
|
||||||
|
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
|
@ -30,6 +31,8 @@ static int branch2 = 0;
|
||||||
static u32 cpuBlockCycles = 0; // 3 bit fixed point version of cycle count
|
static u32 cpuBlockCycles = 0; // 3 bit fixed point version of cycle count
|
||||||
static std::string disOut;
|
static std::string disOut;
|
||||||
|
|
||||||
|
static void intEventTest();
|
||||||
|
|
||||||
// These macros are used to assemble the repassembler functions
|
// These macros are used to assemble the repassembler functions
|
||||||
|
|
||||||
static void debugI()
|
static void debugI()
|
||||||
|
@ -356,24 +359,24 @@ void JALR()
|
||||||
|
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void intAlloc()
|
static void intAlloc()
|
||||||
{
|
{
|
||||||
// fixme : detect cpu for use the optimize asm code
|
// fixme : detect cpu for use the optimize asm code
|
||||||
}
|
}
|
||||||
|
|
||||||
void intReset()
|
static void intReset()
|
||||||
{
|
{
|
||||||
cpuRegs.branch = 0;
|
cpuRegs.branch = 0;
|
||||||
branch2 = 0;
|
branch2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void intEventTest()
|
static void intEventTest()
|
||||||
{
|
{
|
||||||
// Perform counters, ints, and IOP updates:
|
// Perform counters, ints, and IOP updates:
|
||||||
_cpuBranchTest_Shared();
|
_cpuBranchTest_Shared();
|
||||||
}
|
}
|
||||||
|
|
||||||
void intExecute()
|
static void intExecute()
|
||||||
{
|
{
|
||||||
g_EEFreezeRegs = false;
|
g_EEFreezeRegs = false;
|
||||||
|
|
||||||
|
@ -386,6 +389,11 @@ void intExecute()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void intCheckExecutionState()
|
||||||
|
{
|
||||||
|
SysCoreThread::Get().StateCheckInThread();
|
||||||
|
}
|
||||||
|
|
||||||
static void intStep()
|
static void intStep()
|
||||||
{
|
{
|
||||||
g_EEFreezeRegs = false;
|
g_EEFreezeRegs = false;
|
||||||
|
@ -404,6 +412,7 @@ R5900cpu intCpu = {
|
||||||
intReset,
|
intReset,
|
||||||
intStep,
|
intStep,
|
||||||
intExecute,
|
intExecute,
|
||||||
|
intCheckExecutionState,
|
||||||
intClear,
|
intClear,
|
||||||
intShutdown
|
intShutdown
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,36 +23,34 @@ extern void SignalExit(int sig);
|
||||||
|
|
||||||
static const uptr m_pagemask = getpagesize()-1;
|
static const uptr m_pagemask = getpagesize()-1;
|
||||||
|
|
||||||
void InstallLinuxExceptionHandler()
|
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
|
||||||
|
static void SysPageFaultSignalFilter( int signal, siginfo_t *info, void * )
|
||||||
|
{
|
||||||
|
// Note: Use of most stdio functions isn't safe here. Avoid console logs,
|
||||||
|
// assertions, file logs, or just about anything else useful.
|
||||||
|
|
||||||
|
PageFaultInfo info( (uptr)info->si_addr & ~m_pagemask );
|
||||||
|
Source_AccessViolation.DispatchException( info );
|
||||||
|
|
||||||
|
// resumes execution right where we left off (re-executes instruction that
|
||||||
|
// caused the SIGSEGV).
|
||||||
|
if( info.handled ) return;
|
||||||
|
|
||||||
|
// Bad mojo! Completely invalid address.
|
||||||
|
// Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
|
||||||
|
|
||||||
|
wxTrap();
|
||||||
|
if( !IsDebugBuild ) raise( SIGKILL );
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstallSignalHandler()
|
||||||
{
|
{
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_flags = SA_SIGINFO;
|
sa.sa_flags = SA_SIGINFO;
|
||||||
sa.sa_sigaction = &SysPageFaultExceptionFilter;
|
sa.sa_sigaction = SysPageFaultSignalFilter;
|
||||||
sigaction(SIGSEGV, &sa, NULL);
|
sigaction(SIGSEGV, &sa, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReleaseLinuxExceptionHandler()
|
void NTFS_CompressFile( const wxString& file, bool compressStatus=true ) {}
|
||||||
{
|
|
||||||
// Code this later.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
|
|
||||||
void SysPageFaultExceptionFilter( int signal, siginfo_t *info, void * )
|
|
||||||
{
|
|
||||||
// get bad virtual address
|
|
||||||
uptr offset = (u8*)info->si_addr - psM;
|
|
||||||
|
|
||||||
if (offset>=Ps2MemSize::Base)
|
|
||||||
{
|
|
||||||
// Bad mojo! Completely invalid address.
|
|
||||||
// Instigate a crash or abort emulation or something.
|
|
||||||
wxTrap();
|
|
||||||
if( !IsDebugBuild )
|
|
||||||
raise( SIGKILL );
|
|
||||||
}
|
|
||||||
|
|
||||||
DevCon.Status( "Protected memory cleanup. Offset 0x%x", offset );
|
|
||||||
mmap_ClearCpuBlock( offset & ~m_pagemask );
|
|
||||||
}
|
|
||||||
|
|
|
@ -236,7 +236,9 @@
|
||||||
<Unit filename="../StringUtils.h" />
|
<Unit filename="../StringUtils.h" />
|
||||||
<Unit filename="../System.cpp" />
|
<Unit filename="../System.cpp" />
|
||||||
<Unit filename="../System.h" />
|
<Unit filename="../System.h" />
|
||||||
<Unit filename="../System/SysThreads.cpp" />
|
<Unit filename="../System/PageFaultSource.h" />
|
||||||
|
<Unit filename="../System/SysCoreThread.cpp" />
|
||||||
|
<Unit filename="../System/SysThreadBase.cpp" />
|
||||||
<Unit filename="../System/SysThreads.h" />
|
<Unit filename="../System/SysThreads.h" />
|
||||||
<Unit filename="../Tags.h" />
|
<Unit filename="../Tags.h" />
|
||||||
<Unit filename="../Utilities/AsciiFile.h" />
|
<Unit filename="../Utilities/AsciiFile.h" />
|
||||||
|
|
|
@ -86,6 +86,14 @@ extern bool renderswitch;
|
||||||
std::list<uint> ringposStack;
|
std::list<uint> ringposStack;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static __threadlocal mtgsThreadObject* tls_mtgsThread = NULL;
|
||||||
|
|
||||||
|
mtgsThreadObject& mtgsThreadObject::Get()
|
||||||
|
{
|
||||||
|
pxAssertMsg( tls_mtgsThread != NULL, L"This function must be called from the context of a running mtgsThreadObject." );
|
||||||
|
return *tls_mtgsThread;
|
||||||
|
}
|
||||||
|
|
||||||
mtgsThreadObject::mtgsThreadObject() :
|
mtgsThreadObject::mtgsThreadObject() :
|
||||||
SysThreadBase()
|
SysThreadBase()
|
||||||
, m_RingPos( 0 )
|
, m_RingPos( 0 )
|
||||||
|
@ -162,8 +170,8 @@ void mtgsThreadObject::PostVsyncEnd( bool updategs )
|
||||||
if( m_WritePos == volatize( m_RingPos ) )
|
if( m_WritePos == volatize( m_RingPos ) )
|
||||||
{
|
{
|
||||||
// MTGS ringbuffer is empty, but we still have queued frames in the counter? Ouch!
|
// MTGS ringbuffer is empty, but we still have queued frames in the counter? Ouch!
|
||||||
Console.Error( "MTGS > Queued framecount mismatch = %d", m_QueuedFrames );
|
int count = AtomicExchange( m_QueuedFrames, 0 );
|
||||||
m_QueuedFrames = 0;
|
Console.Error( "MTGS > Queued framecount mismatch = %d", count );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Threading::Sleep( 2 ); // Sleep off quite a bit of time, since we're obviously *waaay* ahead.
|
Threading::Sleep( 2 ); // Sleep off quite a bit of time, since we're obviously *waaay* ahead.
|
||||||
|
@ -226,14 +234,20 @@ void mtgsThreadObject::OpenPlugin()
|
||||||
|
|
||||||
void mtgsThreadObject::ExecuteTaskInThread()
|
void mtgsThreadObject::ExecuteTaskInThread()
|
||||||
{
|
{
|
||||||
|
tls_mtgsThread = this;
|
||||||
|
|
||||||
#ifdef RINGBUF_DEBUG_STACK
|
#ifdef RINGBUF_DEBUG_STACK
|
||||||
PacketTagType prevCmd;
|
PacketTagType prevCmd;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while( true )
|
while( true )
|
||||||
{
|
{
|
||||||
m_sem_event.WaitRaw(); // ... because this does a cancel test itself..
|
// Performance note: Both of these perform cancellation tests, but pthread_testcancel
|
||||||
StateCheckInThread( false ); // false disables cancel test here!
|
// is very optimized (only 1 instruction test in most cases), so no point in trying
|
||||||
|
// to avoid it.
|
||||||
|
|
||||||
|
m_sem_event.WaitRaw();
|
||||||
|
StateCheckInThread();
|
||||||
|
|
||||||
m_RingBufferIsBusy = true;
|
m_RingBufferIsBusy = true;
|
||||||
|
|
||||||
|
@ -268,8 +282,7 @@ void mtgsThreadObject::ExecuteTaskInThread()
|
||||||
|
|
||||||
// stall for a bit to let the MainThread have time to update the g_pGSWritePos.
|
// stall for a bit to let the MainThread have time to update the g_pGSWritePos.
|
||||||
m_lock_RingRestart.Wait();
|
m_lock_RingRestart.Wait();
|
||||||
|
StateCheckInThread();
|
||||||
StateCheckInThread( false ); // disable cancel since the above locks are cancelable already
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GS_RINGTYPE_P1:
|
case GS_RINGTYPE_P1:
|
||||||
|
@ -427,6 +440,7 @@ void mtgsThreadObject::OnResumeInThread( bool isSuspended )
|
||||||
void mtgsThreadObject::OnCleanupInThread()
|
void mtgsThreadObject::OnCleanupInThread()
|
||||||
{
|
{
|
||||||
ClosePlugin();
|
ClosePlugin();
|
||||||
|
tls_mtgsThread = NULL;
|
||||||
_parent::OnCleanupInThread();
|
_parent::OnCleanupInThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ BIOS
|
||||||
#include "VUmicro.h"
|
#include "VUmicro.h"
|
||||||
#include "GS.h"
|
#include "GS.h"
|
||||||
#include "IPU/IPU.h"
|
#include "IPU/IPU.h"
|
||||||
#include "AppConfig.h"
|
#include "System/PageFaultSource.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef ENABLECACHE
|
#ifdef ENABLECACHE
|
||||||
|
@ -574,6 +574,8 @@ void memClearPageAddr(u32 vaddr)
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// PS2 Memory Init / Reset / Shutdown
|
// PS2 Memory Init / Reset / Shutdown
|
||||||
|
|
||||||
|
static void __fastcall mmap_OnPageFault( void* basemem, PageFaultInfo& info );
|
||||||
|
|
||||||
static const uint m_allMemSize =
|
static const uint m_allMemSize =
|
||||||
Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2 + Ps2MemSize::ERom +
|
Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2 + Ps2MemSize::ERom +
|
||||||
Ps2MemSize::Base + Ps2MemSize::Hardware + Ps2MemSize::Scratch;
|
Ps2MemSize::Base + Ps2MemSize::Hardware + Ps2MemSize::Scratch;
|
||||||
|
@ -596,10 +598,14 @@ void memAlloc()
|
||||||
psER = curpos; curpos += Ps2MemSize::ERom;
|
psER = curpos; curpos += Ps2MemSize::ERom;
|
||||||
psH = curpos; curpos += Ps2MemSize::Hardware;
|
psH = curpos; curpos += Ps2MemSize::Hardware;
|
||||||
psS = curpos; //curpos += Ps2MemSize::Scratch;
|
psS = curpos; //curpos += Ps2MemSize::Scratch;
|
||||||
|
|
||||||
|
Source_PageFault.Add( EventListener<PageFaultInfo>((void*)psM, mmap_OnPageFault) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void memShutdown()
|
void memShutdown()
|
||||||
{
|
{
|
||||||
|
Source_PageFault.Remove( EventListener<PageFaultInfo>((void*)psM, mmap_OnPageFault) );
|
||||||
|
|
||||||
vtlb_free( m_psAllMem, m_allMemSize );
|
vtlb_free( m_psAllMem, m_allMemSize );
|
||||||
m_psAllMem = NULL;
|
m_psAllMem = NULL;
|
||||||
psM = psR = psR1 = psR2 = psER = psS = psH = NULL;
|
psM = psR = psR1 = psR2 = psER = psS = psH = NULL;
|
||||||
|
@ -623,8 +629,7 @@ void memBindConditionalHandlers()
|
||||||
void memReset()
|
void memReset()
|
||||||
{
|
{
|
||||||
// VTLB Protection Preparations.
|
// VTLB Protection Preparations.
|
||||||
|
//HostSys::MemProtect( m_psAllMem, m_allMemSize, Protect_ReadWrite );
|
||||||
HostSys::MemProtect( m_psAllMem, m_allMemSize, Protect_ReadWrite );
|
|
||||||
|
|
||||||
// Note!! Ideally the vtlb should only be initialized once, and then subsequent
|
// Note!! Ideally the vtlb should only be initialized once, and then subsequent
|
||||||
// resets of the system hardware would only clear vtlb mappings, but since the
|
// resets of the system hardware would only clear vtlb mappings, but since the
|
||||||
|
@ -874,28 +879,33 @@ void mmap_MarkCountedRamPage( u32 paddr )
|
||||||
HostSys::MemProtect( &psM[rampage<<12], 1, Protect_ReadOnly );
|
HostSys::MemProtect( &psM[rampage<<12], 1, Protect_ReadOnly );
|
||||||
}
|
}
|
||||||
|
|
||||||
// offset - offset of address relative to psM. The exception handler for the platform/host
|
// offset - offset of address relative to psM.
|
||||||
// OS should ensure that only addresses within psM address space are passed. Anything else
|
static __forceinline void mmap_ClearCpuBlock( uint offset )
|
||||||
// will produce undefined results (ie, crashes).
|
|
||||||
void mmap_ClearCpuBlock( uint offset )
|
|
||||||
{
|
{
|
||||||
int rampage = offset >> 12;
|
int rampage = offset >> 12;
|
||||||
|
|
||||||
// Assertion: This function should never be run on a block that's already under
|
// Assertion: This function should never be run on a block that's already under
|
||||||
// manual protection. Indicates a logic error in the recompiler or protection code.
|
// manual protection. Indicates a logic error in the recompiler or protection code.
|
||||||
jASSUME( m_PageProtectInfo[rampage].Mode != ProtMode_Manual );
|
pxAssertMsg( m_PageProtectInfo[rampage].Mode != ProtMode_Manual,
|
||||||
|
"Attempted to clear a block that is already under manual protection." );
|
||||||
//#ifndef __LINUX__ // this function is called from the signal handler
|
|
||||||
//DbgCon.WriteLn( "Manual page @ 0x%05x", m_PageProtectInfo[rampage].ReverseRamMap>>12 );
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
HostSys::MemProtect( &psM[rampage<<12], 1, Protect_ReadWrite );
|
HostSys::MemProtect( &psM[rampage<<12], 1, Protect_ReadWrite );
|
||||||
m_PageProtectInfo[rampage].Mode = ProtMode_Manual;
|
m_PageProtectInfo[rampage].Mode = ProtMode_Manual;
|
||||||
Cpu->Clear( m_PageProtectInfo[rampage].ReverseRamMap, 0x400 );
|
Cpu->Clear( m_PageProtectInfo[rampage].ReverseRamMap, 0x400 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __fastcall mmap_OnPageFault( void* basemem, PageFaultInfo& info )
|
||||||
|
{
|
||||||
|
// get bad virtual address
|
||||||
|
uptr offset = info.addr - (uptr)basemem;
|
||||||
|
if( offset >= Ps2MemSize::Base ) return;
|
||||||
|
|
||||||
|
mmap_ClearCpuBlock( offset );
|
||||||
|
info.handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Clears all block tracking statuses, manual protection flags, and write protection.
|
// Clears all block tracking statuses, manual protection flags, and write protection.
|
||||||
// This does not clear any recompiler blocks. IT is assumed (and necessary) for the caller
|
// This does not clear any recompiler blocks. It is assumed (and necessary) for the caller
|
||||||
// to ensure the EErec is also reset in conjunction with calling this function.
|
// to ensure the EErec is also reset in conjunction with calling this function.
|
||||||
void mmap_ResetBlockTracking()
|
void mmap_ResetBlockTracking()
|
||||||
{
|
{
|
||||||
|
|
|
@ -134,7 +134,6 @@ extern void memMapVUmicro();
|
||||||
extern int mmap_GetRamPageInfo( u32 paddr );
|
extern int mmap_GetRamPageInfo( u32 paddr );
|
||||||
extern void mmap_MarkCountedRamPage( u32 paddr );
|
extern void mmap_MarkCountedRamPage( u32 paddr );
|
||||||
extern void mmap_ResetBlockTracking();
|
extern void mmap_ResetBlockTracking();
|
||||||
extern void mmap_ClearCpuBlock( uint offset );
|
|
||||||
|
|
||||||
#define memRead8 vtlb_memRead8
|
#define memRead8 vtlb_memRead8
|
||||||
#define memRead16 vtlb_memRead16
|
#define memRead16 vtlb_memRead16
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
#include "SPR.h"
|
#include "SPR.h"
|
||||||
#include "Sif.h"
|
#include "Sif.h"
|
||||||
|
|
||||||
|
#include "System/SysThreads.h"
|
||||||
|
|
||||||
#include "R5900Exceptions.h"
|
#include "R5900Exceptions.h"
|
||||||
|
|
||||||
using namespace R5900; // for R5900 disasm tools
|
using namespace R5900; // for R5900 disasm tools
|
||||||
|
@ -61,6 +63,8 @@ void cpuReset()
|
||||||
if( mtgsThread.IsOpen() )
|
if( mtgsThread.IsOpen() )
|
||||||
mtgsThread.WaitGS(); // GS better be done processing before we reset the EE, just in case.
|
mtgsThread.WaitGS(); // GS better be done processing before we reset the EE, just in case.
|
||||||
|
|
||||||
|
SysClearExecutionCache();
|
||||||
|
|
||||||
cpuIsInitialized = true;
|
cpuIsInitialized = true;
|
||||||
|
|
||||||
memReset();
|
memReset();
|
||||||
|
@ -560,7 +564,6 @@ void cpuExecuteBios()
|
||||||
|
|
||||||
Console.Status( "Executing Bios Stub..." );
|
Console.Status( "Executing Bios Stub..." );
|
||||||
|
|
||||||
PCSX2_MEM_PROTECT_BEGIN();
|
|
||||||
g_ExecBiosHack = true;
|
g_ExecBiosHack = true;
|
||||||
while( cpuRegs.pc != 0x00200008 &&
|
while( cpuRegs.pc != 0x00200008 &&
|
||||||
cpuRegs.pc != 0x00100008 )
|
cpuRegs.pc != 0x00100008 )
|
||||||
|
@ -568,7 +571,6 @@ void cpuExecuteBios()
|
||||||
Cpu->Execute();
|
Cpu->Execute();
|
||||||
}
|
}
|
||||||
g_ExecBiosHack = false;
|
g_ExecBiosHack = false;
|
||||||
PCSX2_MEM_PROTECT_END();
|
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// FILE* f = fopen("eebios.bin", "wb");
|
// FILE* f = fopen("eebios.bin", "wb");
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
|
|
||||||
extern bool g_EEFreezeRegs;
|
extern bool g_EEFreezeRegs;
|
||||||
extern bool g_ExecBiosHack;
|
extern bool g_ExecBiosHack;
|
||||||
extern volatile bool eeRecIsReset;
|
|
||||||
|
|
||||||
namespace Exception
|
namespace Exception
|
||||||
{
|
{
|
||||||
|
@ -256,7 +255,6 @@ extern bool eeEventTestIsActive;
|
||||||
extern u32 s_iLastCOP0Cycle;
|
extern u32 s_iLastCOP0Cycle;
|
||||||
extern u32 s_iLastPERFCycle[2];
|
extern u32 s_iLastPERFCycle[2];
|
||||||
|
|
||||||
void intEventTest();
|
|
||||||
void intSetBranch();
|
void intSetBranch();
|
||||||
|
|
||||||
// This is a special form of the interpreter's doBranch that is run from various
|
// This is a special form of the interpreter's doBranch that is run from various
|
||||||
|
@ -272,6 +270,7 @@ struct R5900cpu
|
||||||
void (*Reset)();
|
void (*Reset)();
|
||||||
void (*Step)();
|
void (*Step)();
|
||||||
void (*Execute)();
|
void (*Execute)();
|
||||||
|
void (*CheckExecutionState)();
|
||||||
void (*Clear)(u32 Addr, u32 Size);
|
void (*Clear)(u32 Addr, u32 Size);
|
||||||
void (*Shutdown)(); // deallocates memory reserved by Allocate
|
void (*Shutdown)(); // deallocates memory reserved by Allocate
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,7 +34,7 @@ int sys_resume_lock = 0;
|
||||||
|
|
||||||
static FnType_OnThreadComplete* Callback_FreezeFinished = NULL;
|
static FnType_OnThreadComplete* Callback_FreezeFinished = NULL;
|
||||||
|
|
||||||
static void StateThread_OnAppStatus( void* thr, const enum AppEventType& stat )
|
static void __fastcall StateThread_OnAppStatus( void* thr, AppEventType& stat )
|
||||||
{
|
{
|
||||||
if( (thr == NULL) || (stat != AppStatus_Exiting) ) return;
|
if( (thr == NULL) || (stat != AppStatus_Exiting) ) return;
|
||||||
((PersistentThread*)thr)->Cancel();
|
((PersistentThread*)thr)->Cancel();
|
||||||
|
|
|
@ -25,8 +25,10 @@
|
||||||
#include "sVU_zerorec.h" // for SuperVUReset
|
#include "sVU_zerorec.h" // for SuperVUReset
|
||||||
|
|
||||||
#include "R5900Exceptions.h"
|
#include "R5900Exceptions.h"
|
||||||
|
|
||||||
#include "CDVD/CDVD.h"
|
#include "CDVD/CDVD.h"
|
||||||
|
#include "System/PageFaultSource.h"
|
||||||
|
|
||||||
|
SrcType_PageFault Source_PageFault;
|
||||||
|
|
||||||
#if _MSC_VER
|
#if _MSC_VER
|
||||||
# include "svnrev.h"
|
# include "svnrev.h"
|
||||||
|
@ -106,6 +108,8 @@ static wxString GetMemoryErrorVM()
|
||||||
|
|
||||||
SysCoreAllocations::SysCoreAllocations()
|
SysCoreAllocations::SysCoreAllocations()
|
||||||
{
|
{
|
||||||
|
InstallSignalHandler();
|
||||||
|
|
||||||
Console.Status( "Initializing PS2 virtual machine..." );
|
Console.Status( "Initializing PS2 virtual machine..." );
|
||||||
|
|
||||||
RecSuccess_EE = false;
|
RecSuccess_EE = false;
|
||||||
|
|
|
@ -60,62 +60,35 @@ extern void SysClearExecutionCache(); // clears recompiled execution caches!
|
||||||
|
|
||||||
extern u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed");
|
extern u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed");
|
||||||
extern void vSyncDebugStuff( uint frame );
|
extern void vSyncDebugStuff( uint frame );
|
||||||
|
extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true );
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Memory Protection (Used by VTLB, Recompilers, and Texture caches)
|
// PCSX2_SEH - Defines existence of "built in" Structured Exception Handling support.
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
#ifdef __LINUX__
|
|
||||||
|
|
||||||
# include <signal.h>
|
|
||||||
|
|
||||||
extern void SysPageFaultExceptionFilter( int signal, siginfo_t *info, void * );
|
|
||||||
extern void __fastcall InstallLinuxExceptionHandler();
|
|
||||||
extern void __fastcall ReleaseLinuxExceptionHandler();
|
|
||||||
static void NTFS_CompressFile( const wxString& file, bool compressStatus=true ) {}
|
|
||||||
|
|
||||||
# define PCSX2_MEM_PROTECT_BEGIN() InstallLinuxExceptionHandler()
|
|
||||||
# define PCSX2_MEM_PROTECT_END() ReleaseLinuxExceptionHandler()
|
|
||||||
|
|
||||||
#elif defined( _WIN32 )
|
|
||||||
|
|
||||||
extern int SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps);
|
|
||||||
extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true );
|
|
||||||
|
|
||||||
# define PCSX2_MEM_PROTECT_BEGIN() __try {
|
|
||||||
# define PCSX2_MEM_PROTECT_END() } __except(SysPageFaultExceptionFilter(GetExceptionInformation())) {}
|
|
||||||
|
|
||||||
#else
|
|
||||||
# error PCSX2 - Unsupported operating system platform.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
// PCSX2_SEH - Defines existence of "built in" Structed Exception Handling support.
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// This should be available on Windows, via Microsoft or Intel compilers (I'm pretty sure Intel
|
// This should be available on Windows, via Microsoft or Intel compilers (I'm pretty sure Intel
|
||||||
// supports native SEH model). GNUC in Windows, or any compiler in a non-windows platform, will
|
// supports native SEH model). GNUC in Windows, or any compiler in a non-windows platform, will
|
||||||
// need to use setjmp/longjmp instead to exit recompiled code.
|
// need to use setjmp/longjmp instead to exit recompiled code.
|
||||||
//
|
//
|
||||||
#if defined(_WIN32) && !defined(__GNUC__)
|
|
||||||
# define PCSX2_SEH
|
|
||||||
#else
|
|
||||||
|
|
||||||
# include <setjmp.h>
|
//#define PCSX2_SEH 0 // use this to force disable SEH on win32, to test setjmp functionality.
|
||||||
|
|
||||||
// Platforms without SEH need to use SetJmp / LongJmp to deal with exiting the recompiled
|
#ifndef PCSX2_SEH
|
||||||
// code execution pipelines in an efficient manner, since standard C++ exceptions cannot
|
# if defined(_WIN32) && !defined(__GNUC__)
|
||||||
// unwind across dynamically recompiled code.
|
# define PCSX2_SEH 1
|
||||||
|
# else
|
||||||
enum
|
# define PCSX2_SEH 0
|
||||||
{
|
# endif
|
||||||
SetJmp_Dispatcher = 1,
|
#endif
|
||||||
SetJmp_Exit,
|
|
||||||
};
|
// special macro which disables inlining on functions that require their own function stackframe.
|
||||||
|
// This is due to how Win32 handles structured exception handling. Linux uses signals instead
|
||||||
extern jmp_buf SetJmp_RecExecute;
|
// of SEH, and so these functions can be inlined.
|
||||||
extern jmp_buf SetJmp_StateCheck;
|
#ifdef _WIN32
|
||||||
|
# define __unique_stackframe __noinline
|
||||||
|
#else
|
||||||
|
# define __unique_stackframe
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class pxMessageBoxEvent;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Different types of message boxes that the emulator can employ from the friendly confines
|
// Different types of message boxes that the emulator can employ from the friendly confines
|
||||||
|
@ -123,6 +96,9 @@ class pxMessageBoxEvent;
|
||||||
// blocking behavior -- they prompt the user for action and only return after the user has
|
// blocking behavior -- they prompt the user for action and only return after the user has
|
||||||
// responded to the prompt.
|
// responded to the prompt.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
class pxMessageBoxEvent;
|
||||||
|
|
||||||
namespace Msgbox
|
namespace Msgbox
|
||||||
{
|
{
|
||||||
extern void OnEvent( pxMessageBoxEvent& evt );
|
extern void OnEvent( pxMessageBoxEvent& evt );
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2002-2009 PCSX2 Dev Team
|
||||||
|
*
|
||||||
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// =====================================================================================================
|
||||||
|
// Cross-Platform Memory Protection (Used by VTLB, Recompilers and Texture caches)
|
||||||
|
// =====================================================================================================
|
||||||
|
// Win32 platforms use the SEH model: __try {} __except {}
|
||||||
|
// Linux platforms use the POSIX Signals model: sigaction()
|
||||||
|
|
||||||
|
#include "Utilities/EventSource.h"
|
||||||
|
|
||||||
|
struct PageFaultInfo
|
||||||
|
{
|
||||||
|
uptr addr;
|
||||||
|
bool handled;
|
||||||
|
|
||||||
|
PageFaultInfo( uptr address )
|
||||||
|
{
|
||||||
|
addr = address;
|
||||||
|
handled = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SrcType_PageFault : public EventSource<PageFaultInfo>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SrcType_PageFault() {}
|
||||||
|
virtual ~SrcType_PageFault() throw() { }
|
||||||
|
|
||||||
|
void DispatchException( PageFaultInfo& evt )
|
||||||
|
{
|
||||||
|
if( m_listeners.empty() ) return;
|
||||||
|
|
||||||
|
ConstIterator iter( m_listeners.begin() );
|
||||||
|
const ConstIterator iend( m_listeners.end() );
|
||||||
|
|
||||||
|
do {
|
||||||
|
iter->OnEvent( iter->object, evt );
|
||||||
|
} while( (++iter != iend) && !evt.handled );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SrcType_PageFault Source_PageFault;
|
||||||
|
|
||||||
|
extern void InstallSignalHandler();
|
||||||
|
|
||||||
|
#ifdef __LINUX__
|
||||||
|
|
||||||
|
# define PCSX2_PAGEFAULT_PROTECT()
|
||||||
|
# define PCSX2_PAGEFAULT_EXCEPT()
|
||||||
|
|
||||||
|
#elif defined( _WIN32 )
|
||||||
|
|
||||||
|
extern int SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps);
|
||||||
|
|
||||||
|
# define PCSX2_PAGEFAULT_PROTECT __try
|
||||||
|
# define PCSX2_PAGEFAULT_EXCEPT __except(SysPageFaultExceptionFilter(GetExceptionInformation())) {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error PCSX2 - Unsupported operating system platform.
|
||||||
|
#endif
|
|
@ -0,0 +1,234 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2002-2009 PCSX2 Dev Team
|
||||||
|
*
|
||||||
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PrecompiledHeader.h"
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
#include "System.h"
|
||||||
|
#include "PageFaultSource.h"
|
||||||
|
#include "SysThreads.h"
|
||||||
|
|
||||||
|
#include "SaveState.h"
|
||||||
|
#include "Elfheader.h"
|
||||||
|
#include "Plugins.h"
|
||||||
|
#include "R5900.h"
|
||||||
|
#include "R3000A.h"
|
||||||
|
#include "VUmicro.h"
|
||||||
|
|
||||||
|
#include "GS.h"
|
||||||
|
|
||||||
|
static __threadlocal SysCoreThread* tls_coreThread = NULL;
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// SysCoreThread *External Thread* Implementations
|
||||||
|
// (Called from outside the context of this thread)
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SysCoreThread::SysCoreThread() :
|
||||||
|
m_resetRecompilers( true )
|
||||||
|
, m_resetProfilers( true )
|
||||||
|
, m_resetVirtualMachine( true )
|
||||||
|
, m_hasValidState( false )
|
||||||
|
{
|
||||||
|
m_name = L"EE Core";
|
||||||
|
}
|
||||||
|
|
||||||
|
SysCoreThread::~SysCoreThread() throw()
|
||||||
|
{
|
||||||
|
SysCoreThread::Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysCoreThread::Cancel( bool isBlocking )
|
||||||
|
{
|
||||||
|
m_CoreCancelDamnit = true;
|
||||||
|
_parent::Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysCoreThread::Start()
|
||||||
|
{
|
||||||
|
if( g_plugins == NULL ) return;
|
||||||
|
g_plugins->Init();
|
||||||
|
m_CoreCancelDamnit = false; // belongs in OnStart actually, but I'm tired :P
|
||||||
|
_parent::Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Exceptions (can occur on first call only):
|
||||||
|
// PluginInitError - thrown if a plugin fails init (init is performed on the current thread
|
||||||
|
// on the first time the thread is resumed from it's initial idle state)
|
||||||
|
// ThreadCreationError - Insufficient system resources to create thread.
|
||||||
|
//
|
||||||
|
void SysCoreThread::OnResumeReady()
|
||||||
|
{
|
||||||
|
if( m_resetVirtualMachine )
|
||||||
|
{
|
||||||
|
cpuReset();
|
||||||
|
m_resetVirtualMachine = false;
|
||||||
|
m_hasValidState = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !m_hasValidState )
|
||||||
|
m_resetRecompilers = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysCoreThread::Reset()
|
||||||
|
{
|
||||||
|
Suspend();
|
||||||
|
m_resetVirtualMachine = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 SysCoreThread::ApplySettings( const Pcsx2Config& src )
|
||||||
|
{
|
||||||
|
if( src == EmuConfig ) return;
|
||||||
|
|
||||||
|
const bool resumeWhenDone = Suspend();
|
||||||
|
|
||||||
|
m_resetRecompilers = ( src.Cpu != EmuConfig.Cpu ) || ( src.Gamefixes != EmuConfig.Gamefixes ) || ( src.Speedhacks != EmuConfig.Speedhacks );
|
||||||
|
m_resetProfilers = (src.Profiler != EmuConfig.Profiler );
|
||||||
|
|
||||||
|
const_cast<Pcsx2Config&>(EmuConfig) = src;
|
||||||
|
|
||||||
|
if( resumeWhenDone ) Resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// EECoreThread *Worker* Implementations
|
||||||
|
// (Called from the context of this thread only)
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
SysCoreThread& SysCoreThread::Get()
|
||||||
|
{
|
||||||
|
pxAssertMsg( tls_coreThread != NULL, L"This function must be called from the context of a running SysCoreThread." );
|
||||||
|
return *tls_coreThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SysCoreThread::HasPendingStateChangeRequest() const
|
||||||
|
{
|
||||||
|
return m_CoreCancelDamnit || mtgsThread.HasPendingException() || _parent::HasPendingStateChangeRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SysCoreThread::CpuInitializeMess()
|
||||||
|
{
|
||||||
|
if( m_hasValidState ) return;
|
||||||
|
|
||||||
|
// Some recompiler mess might be left over -- nuke it here:
|
||||||
|
SysClearExecutionCache();
|
||||||
|
memBindConditionalHandlers();
|
||||||
|
m_resetRecompilers = false;
|
||||||
|
m_resetProfilers = false;
|
||||||
|
|
||||||
|
wxString elf_file;
|
||||||
|
if( EmuConfig.SkipBiosSplash )
|
||||||
|
{
|
||||||
|
// Fetch the ELF filename and CD type from the CDVD provider.
|
||||||
|
wxString ename;
|
||||||
|
int result = GetPS2ElfName( ename );
|
||||||
|
switch( result )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
throw Exception::RuntimeError( wxLt("Fast Boot failed: CDVD image is not a PS1 or PS2 game.") );
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
throw Exception::RuntimeError( wxLt("Fast Boot failed: PCSX2 does not support emulation of PS1 games.") );
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// PS2 game. Valid!
|
||||||
|
elf_file = ename;
|
||||||
|
break;
|
||||||
|
|
||||||
|
jNO_DEFAULT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !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).
|
||||||
|
|
||||||
|
m_hasValidState = true;
|
||||||
|
cpuExecuteBios();
|
||||||
|
m_hasValidState = false; // because loadElfFile might error...
|
||||||
|
loadElfFile( elf_file );
|
||||||
|
}
|
||||||
|
m_hasValidState = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysCoreThread::StateCheckInThread()
|
||||||
|
{
|
||||||
|
mtgsThread.RethrowException();
|
||||||
|
_parent::StateCheckInThread();
|
||||||
|
if( !m_hasValidState )
|
||||||
|
throw Exception::RuntimeError( "Invalid emulation state detected; Virtual machine threads have been cancelled." );
|
||||||
|
|
||||||
|
if( m_resetRecompilers || m_resetProfilers )
|
||||||
|
{
|
||||||
|
SysClearExecutionCache();
|
||||||
|
memBindConditionalHandlers();
|
||||||
|
m_resetRecompilers = false;
|
||||||
|
m_resetProfilers = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysCoreThread::ExecuteTaskInThread()
|
||||||
|
{
|
||||||
|
Threading::EnableHiresScheduler();
|
||||||
|
|
||||||
|
tls_coreThread = this;
|
||||||
|
|
||||||
|
m_sem_event.WaitRaw();
|
||||||
|
PCSX2_PAGEFAULT_PROTECT {
|
||||||
|
StateCheckInThread();
|
||||||
|
Cpu->Execute();
|
||||||
|
} PCSX2_PAGEFAULT_EXCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysCoreThread::OnSuspendInThread()
|
||||||
|
{
|
||||||
|
if( g_plugins != NULL )
|
||||||
|
g_plugins->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysCoreThread::OnResumeInThread( bool isSuspended )
|
||||||
|
{
|
||||||
|
if( isSuspended && g_plugins != NULL )
|
||||||
|
{
|
||||||
|
g_plugins->Open();
|
||||||
|
CpuInitializeMess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Invoked by the pthread_exit or pthread_cancel.
|
||||||
|
void SysCoreThread::OnCleanupInThread()
|
||||||
|
{
|
||||||
|
Threading::DisableHiresScheduler();
|
||||||
|
|
||||||
|
if( g_plugins != NULL )
|
||||||
|
g_plugins->Close();
|
||||||
|
|
||||||
|
tls_coreThread = NULL;
|
||||||
|
_parent::OnCleanupInThread();
|
||||||
|
}
|
||||||
|
|
|
@ -14,18 +14,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
#include "Common.h"
|
|
||||||
#include "System.h"
|
#include "System.h"
|
||||||
#include "SysThreads.h"
|
#include "SysThreads.h"
|
||||||
#include "SaveState.h"
|
|
||||||
#include "Elfheader.h"
|
|
||||||
#include "Plugins.h"
|
|
||||||
|
|
||||||
#include "R5900.h"
|
|
||||||
#include "R3000A.h"
|
|
||||||
#include "VUmicro.h"
|
|
||||||
|
|
||||||
static __threadlocal SysCoreThread* tls_coreThread = NULL;
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// SysThreadBase *External Thread* Implementations
|
// SysThreadBase *External Thread* Implementations
|
||||||
|
@ -267,7 +258,7 @@ void SysThreadBase::OnCleanupInThread()
|
||||||
void SysThreadBase::OnSuspendInThread() {}
|
void SysThreadBase::OnSuspendInThread() {}
|
||||||
void SysThreadBase::OnResumeInThread( bool isSuspended ) {}
|
void SysThreadBase::OnResumeInThread( bool isSuspended ) {}
|
||||||
|
|
||||||
void SysThreadBase::StateCheckInThread( bool isCancelable )
|
void SysThreadBase::StateCheckInThread()
|
||||||
{
|
{
|
||||||
switch( m_ExecMode )
|
switch( m_ExecMode )
|
||||||
{
|
{
|
||||||
|
@ -283,7 +274,6 @@ void SysThreadBase::StateCheckInThread( bool isCancelable )
|
||||||
case ExecMode_Opened:
|
case ExecMode_Opened:
|
||||||
// Yup, need this a second time. Variable state could have changed while we
|
// Yup, need this a second time. Variable state could have changed while we
|
||||||
// were trying to acquire the lock above.
|
// were trying to acquire the lock above.
|
||||||
if( isCancelable )
|
|
||||||
TestCancel();
|
TestCancel();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -324,197 +314,3 @@ void SysThreadBase::StateCheckInThread( bool isCancelable )
|
||||||
jNO_DEFAULT;
|
jNO_DEFAULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
// EECoreThread *External Thread* Implementations
|
|
||||||
// (Called from outside the context of this thread)
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
SysCoreThread::SysCoreThread() :
|
|
||||||
m_resetRecompilers( true )
|
|
||||||
, m_resetProfilers( true )
|
|
||||||
, m_resetVirtualMachine( true )
|
|
||||||
, m_hasValidState( false )
|
|
||||||
{
|
|
||||||
m_name = L"EE Core";
|
|
||||||
}
|
|
||||||
|
|
||||||
SysCoreThread::~SysCoreThread() throw()
|
|
||||||
{
|
|
||||||
SysCoreThread::Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern bool CoreCancelDamnit;
|
|
||||||
void SysCoreThread::Cancel( bool isBlocking )
|
|
||||||
{
|
|
||||||
CoreCancelDamnit = true;
|
|
||||||
_parent::Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysCoreThread::Start()
|
|
||||||
{
|
|
||||||
if( g_plugins == NULL ) return;
|
|
||||||
g_plugins->Init();
|
|
||||||
CoreCancelDamnit = false; // belongs in OnStart actually, but I'm tired :P
|
|
||||||
_parent::Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
//
|
|
||||||
// Exceptions (can occur on first call only):
|
|
||||||
// PluginInitError - thrown if a plugin fails init (init is performed on the current thread
|
|
||||||
// on the first time the thread is resumed from it's initial idle state)
|
|
||||||
// ThreadCreationError - Insufficient system resources to create thread.
|
|
||||||
//
|
|
||||||
void SysCoreThread::OnResumeReady()
|
|
||||||
{
|
|
||||||
if( m_resetVirtualMachine )
|
|
||||||
{
|
|
||||||
cpuReset();
|
|
||||||
m_resetVirtualMachine = false;
|
|
||||||
m_hasValidState = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( m_resetRecompilers || m_resetProfilers || !m_hasValidState )
|
|
||||||
{
|
|
||||||
SysClearExecutionCache();
|
|
||||||
memBindConditionalHandlers();
|
|
||||||
m_resetRecompilers = false;
|
|
||||||
m_resetProfilers = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysCoreThread::Reset()
|
|
||||||
{
|
|
||||||
Suspend();
|
|
||||||
m_resetVirtualMachine = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 SysCoreThread::ApplySettings( const Pcsx2Config& src )
|
|
||||||
{
|
|
||||||
if( src == EmuConfig ) return;
|
|
||||||
|
|
||||||
const bool resumeWhenDone = Suspend();
|
|
||||||
|
|
||||||
m_resetRecompilers = ( src.Cpu != EmuConfig.Cpu ) || ( src.Gamefixes != EmuConfig.Gamefixes ) || ( src.Speedhacks != EmuConfig.Speedhacks );
|
|
||||||
m_resetProfilers = (src.Profiler != EmuConfig.Profiler );
|
|
||||||
|
|
||||||
const_cast<Pcsx2Config&>(EmuConfig) = src;
|
|
||||||
|
|
||||||
if( resumeWhenDone ) Resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
// EECoreThread *Worker* Implementations
|
|
||||||
// (Called from the context of this thread only)
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
SysCoreThread& SysCoreThread::Get()
|
|
||||||
{
|
|
||||||
pxAssertMsg( tls_coreThread != NULL, L"This function must be called from the context of a running SysCoreThread." );
|
|
||||||
return *tls_coreThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysCoreThread::CpuInitializeMess()
|
|
||||||
{
|
|
||||||
if( m_hasValidState ) return;
|
|
||||||
|
|
||||||
wxString elf_file;
|
|
||||||
if( EmuConfig.SkipBiosSplash )
|
|
||||||
{
|
|
||||||
// Fetch the ELF filename and CD type from the CDVD provider.
|
|
||||||
wxString ename;
|
|
||||||
int result = GetPS2ElfName( ename );
|
|
||||||
switch( result )
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
throw Exception::RuntimeError( wxLt("Fast Boot failed: CDVD image is not a PS1 or PS2 game.") );
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
throw Exception::RuntimeError( wxLt("Fast Boot failed: PCSX2 does not support emulation of PS1 games.") );
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
// PS2 game. Valid!
|
|
||||||
elf_file = ename;
|
|
||||||
break;
|
|
||||||
|
|
||||||
jNO_DEFAULT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !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( elf_file );
|
|
||||||
}
|
|
||||||
m_hasValidState = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// special macro which disables inlining on functions that require their own function stackframe.
|
|
||||||
// This is due to how Win32 handles structured exception handling. Linux uses signals instead
|
|
||||||
// of SEH, and so these functions can be inlined.
|
|
||||||
#ifdef _WIN32
|
|
||||||
# define __unique_stackframe __noinline
|
|
||||||
#else
|
|
||||||
# define __unique_stackframe
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// On Win32 this function invokes SEH, which requires it be in a function all by itself
|
|
||||||
// with inlining disabled.
|
|
||||||
__unique_stackframe
|
|
||||||
void SysCoreThread::CpuExecute()
|
|
||||||
{
|
|
||||||
PCSX2_MEM_PROTECT_BEGIN();
|
|
||||||
Cpu->Execute();
|
|
||||||
PCSX2_MEM_PROTECT_END();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysCoreThread::ExecuteTaskInThread()
|
|
||||||
{
|
|
||||||
Threading::EnableHiresScheduler();
|
|
||||||
|
|
||||||
tls_coreThread = this;
|
|
||||||
|
|
||||||
m_sem_event.WaitRaw();
|
|
||||||
StateCheckInThread();
|
|
||||||
CpuExecute();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysCoreThread::OnSuspendInThread()
|
|
||||||
{
|
|
||||||
if( g_plugins != NULL )
|
|
||||||
g_plugins->Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysCoreThread::OnResumeInThread( bool isSuspended )
|
|
||||||
{
|
|
||||||
if( isSuspended && g_plugins != NULL )
|
|
||||||
{
|
|
||||||
g_plugins->Open();
|
|
||||||
CpuInitializeMess();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Invoked by the pthread_exit or pthread_cancel
|
|
||||||
void SysCoreThread::OnCleanupInThread()
|
|
||||||
{
|
|
||||||
Threading::DisableHiresScheduler();
|
|
||||||
|
|
||||||
if( g_plugins != NULL )
|
|
||||||
g_plugins->Close();
|
|
||||||
|
|
||||||
_parent::OnCleanupInThread();
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,6 +19,25 @@
|
||||||
|
|
||||||
using namespace Threading;
|
using namespace Threading;
|
||||||
|
|
||||||
|
|
||||||
|
#if !PCSX2_SEH
|
||||||
|
# include <setjmp.h>
|
||||||
|
|
||||||
|
// Platforms without SEH need to use SetJmp / LongJmp to deal with exiting the recompiled
|
||||||
|
// code execution pipelines in an efficient manner, since standard C++ exceptions cannot
|
||||||
|
// unwind across dynamically recompiled code.
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SetJmp_Dispatcher = 1,
|
||||||
|
SetJmp_Exit,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// ISysThread
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
class ISysThread : public virtual IThread
|
class ISysThread : public virtual IThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -30,6 +49,9 @@ public:
|
||||||
virtual void Resume() {}
|
virtual void Resume() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// SysThreadBase
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
class SysThreadBase : public PersistentThread, public virtual ISysThread
|
class SysThreadBase : public PersistentThread, public virtual ISysThread
|
||||||
{
|
{
|
||||||
|
@ -93,7 +115,7 @@ public:
|
||||||
return m_ExecMode > ExecMode_Closed;
|
return m_ExecMode > ExecMode_Closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasPendingStateChangeRequest()
|
bool HasPendingStateChangeRequest() const
|
||||||
{
|
{
|
||||||
ExecutionMode mode = m_ExecMode;
|
ExecutionMode mode = m_ExecMode;
|
||||||
return (mode == ExecMode_Closing) || (mode == ExecMode_Pausing);
|
return (mode == ExecMode_Closing) || (mode == ExecMode_Pausing);
|
||||||
|
@ -108,8 +130,6 @@ public:
|
||||||
virtual void Resume();
|
virtual void Resume();
|
||||||
virtual bool Pause();
|
virtual bool Pause();
|
||||||
|
|
||||||
virtual void StateCheckInThread( bool isCancelable = true );
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void OnStart();
|
virtual void OnStart();
|
||||||
|
|
||||||
|
@ -118,6 +138,7 @@ protected:
|
||||||
// Resume() has a lot of checks and balances to prevent re-entrance and race conditions.
|
// Resume() has a lot of checks and balances to prevent re-entrance and race conditions.
|
||||||
virtual void OnResumeReady() {}
|
virtual void OnResumeReady() {}
|
||||||
|
|
||||||
|
virtual void StateCheckInThread();
|
||||||
virtual void OnCleanupInThread();
|
virtual void OnCleanupInThread();
|
||||||
virtual void OnStartInThread();
|
virtual void OnStartInThread();
|
||||||
|
|
||||||
|
@ -147,8 +168,10 @@ protected:
|
||||||
virtual void OnResumeInThread( bool isSuspended )=0;
|
virtual void OnResumeInThread( bool isSuspended )=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// EECoreThread class
|
// SysCoreThread class
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class SysCoreThread : public SysThreadBase
|
class SysCoreThread : public SysThreadBase
|
||||||
{
|
{
|
||||||
|
@ -160,6 +183,9 @@ protected:
|
||||||
bool m_resetVirtualMachine;
|
bool m_resetVirtualMachine;
|
||||||
bool m_hasValidState;
|
bool m_hasValidState;
|
||||||
|
|
||||||
|
// Used by SETJMP only, but ifdef'ing it out clutters up the code.
|
||||||
|
bool m_CoreCancelDamnit;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static SysCoreThread& Get();
|
static SysCoreThread& Get();
|
||||||
|
|
||||||
|
@ -177,9 +203,12 @@ public:
|
||||||
return m_hasValidState;
|
return m_hasValidState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HasPendingStateChangeRequest() const;
|
||||||
|
|
||||||
|
virtual void StateCheckInThread();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void CpuInitializeMess();
|
void CpuInitializeMess();
|
||||||
void CpuExecute();
|
|
||||||
|
|
||||||
virtual void Start();
|
virtual void Start();
|
||||||
virtual void OnSuspendInThread();
|
virtual void OnSuspendInThread();
|
||||||
|
@ -187,6 +216,8 @@ protected:
|
||||||
virtual void OnResumeInThread( bool IsSuspended );
|
virtual void OnResumeInThread( bool IsSuspended );
|
||||||
virtual void OnCleanupInThread();
|
virtual void OnCleanupInThread();
|
||||||
virtual void ExecuteTaskInThread();
|
virtual void ExecuteTaskInThread();
|
||||||
|
|
||||||
|
void _StateCheckThrows();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int sys_resume_lock;
|
extern int sys_resume_lock;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include <wx/docview.h>
|
#include <wx/docview.h>
|
||||||
#include <wx/apptrait.h>
|
#include <wx/apptrait.h>
|
||||||
|
|
||||||
#include "Utilities/Listeners.h"
|
#include "Utilities/EventSource.h"
|
||||||
#include "IniInterface.h"
|
#include "IniInterface.h"
|
||||||
|
|
||||||
//class IniInterface;
|
//class IniInterface;
|
||||||
|
@ -490,7 +490,7 @@ public:
|
||||||
|
|
||||||
virtual bool Suspend( bool isBlocking=true );
|
virtual bool Suspend( bool isBlocking=true );
|
||||||
virtual void Resume();
|
virtual void Resume();
|
||||||
virtual void StateCheckInThread( bool isCancelable=true );
|
virtual void StateCheckInThread();
|
||||||
virtual void ApplySettings( const Pcsx2Config& src );
|
virtual void ApplySettings( const Pcsx2Config& src );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -128,9 +128,9 @@ void AppCoreThread::OnCleanupInThread()
|
||||||
extern int TranslateGDKtoWXK( u32 keysym );
|
extern int TranslateGDKtoWXK( u32 keysym );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void AppCoreThread::StateCheckInThread( bool isCancelable )
|
void AppCoreThread::StateCheckInThread()
|
||||||
{
|
{
|
||||||
_parent::StateCheckInThread( isCancelable );
|
_parent::StateCheckInThread();
|
||||||
if( !pxAssert(g_plugins!=NULL) ) return;
|
if( !pxAssert(g_plugins!=NULL) ) return;
|
||||||
|
|
||||||
const keyEvent* ev = PADkeyEvent();
|
const keyEvent* ev = PADkeyEvent();
|
||||||
|
|
|
@ -244,7 +244,6 @@ bool Pcsx2App::OnInit()
|
||||||
Connect( pxEVT_SysExecute, wxCommandEventHandler( Pcsx2App::OnSysExecute ) );
|
Connect( pxEVT_SysExecute, wxCommandEventHandler( Pcsx2App::OnSysExecute ) );
|
||||||
|
|
||||||
Connect( pxEVT_LoadPluginsComplete, wxCommandEventHandler( Pcsx2App::OnLoadPluginsComplete ) );
|
Connect( pxEVT_LoadPluginsComplete, wxCommandEventHandler( Pcsx2App::OnLoadPluginsComplete ) );
|
||||||
|
|
||||||
Connect( pxEVT_CoreThreadStatus, wxCommandEventHandler( Pcsx2App::OnCoreThreadStatus ) );
|
Connect( pxEVT_CoreThreadStatus, wxCommandEventHandler( Pcsx2App::OnCoreThreadStatus ) );
|
||||||
Connect( pxEVT_FreezeThreadFinished, wxCommandEventHandler( Pcsx2App::OnFreezeThreadFinished ) );
|
Connect( pxEVT_FreezeThreadFinished, wxCommandEventHandler( Pcsx2App::OnFreezeThreadFinished ) );
|
||||||
|
|
||||||
|
|
|
@ -210,8 +210,7 @@ void Pcsx2App::OnEmuKeyDown( wxKeyEvent& evt )
|
||||||
|
|
||||||
void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent& event) const
|
void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent& event) const
|
||||||
{
|
{
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
(handler->*func)(event);
|
(handler->*func)(event);
|
||||||
}
|
}
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -247,7 +246,7 @@ void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnStateSaveFinished( void* obj, const wxCommandEvent& evt )
|
static void __fastcall OnStateSaveFinished( void* obj, wxCommandEvent& evt )
|
||||||
{
|
{
|
||||||
if( evt.GetInt() == CoreStatus_Resumed )
|
if( evt.GetInt() == CoreStatus_Resumed )
|
||||||
{
|
{
|
||||||
|
@ -290,7 +289,8 @@ bool Pcsx2App::PrepForExit( bool canCancel )
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
m_evtsrc_AppStatus.Dispatch( AppStatus_Exiting );
|
AppEventType toSend = AppStatus_Exiting;
|
||||||
|
m_evtsrc_AppStatus.Dispatch( toSend );
|
||||||
CleanupMess();
|
CleanupMess();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -354,7 +354,8 @@ void AppApplySettings( const AppConfig* oldconf, bool saveOnSuccess )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sApp.Source_SettingsApplied().Dispatch( 0 );
|
int toSend = 0;
|
||||||
|
sApp.Source_SettingsApplied().Dispatch( toSend );
|
||||||
CoreThread.ApplySettings( g_Conf->EmuOptions );
|
CoreThread.ApplySettings( g_Conf->EmuOptions );
|
||||||
|
|
||||||
if( resume )
|
if( resume )
|
||||||
|
|
|
@ -255,34 +255,33 @@ void MainEmuFrame::InitLogBoxPosition( AppConfig::ConsoleLogOptions& conf )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::OnCoreThreadStatusChanged( void* obj, const wxCommandEvent& evt )
|
void __fastcall MainEmuFrame::OnCoreThreadStatusChanged( void* obj, wxCommandEvent& evt )
|
||||||
{
|
{
|
||||||
if( obj == NULL ) return;
|
if( obj == NULL ) return;
|
||||||
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
||||||
mframe->ApplyCoreStatus();
|
mframe->ApplyCoreStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::OnCorePluginStatusChanged( void* obj, const wxCommandEvent& evt )
|
void __fastcall MainEmuFrame::OnCorePluginStatusChanged( void* obj, wxCommandEvent& evt )
|
||||||
{
|
{
|
||||||
if( obj == NULL ) return;
|
if( obj == NULL ) return;
|
||||||
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
||||||
mframe->ApplyCoreStatus();
|
mframe->ApplyCoreStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::OnSettingsApplied( void* obj, const int& evt )
|
void __fastcall MainEmuFrame::OnSettingsApplied( void* obj, int& evt )
|
||||||
{
|
{
|
||||||
if( obj == NULL ) return;
|
if( obj == NULL ) return;
|
||||||
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
||||||
mframe->ApplySettings();
|
mframe->ApplySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::OnSettingsLoadSave( void* obj, const IniInterface& evt )
|
void __fastcall MainEmuFrame::OnSettingsLoadSave( void* obj, IniInterface& evt )
|
||||||
{
|
{
|
||||||
if( obj == NULL ) return;
|
if( obj == NULL ) return;
|
||||||
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
||||||
|
|
||||||
// FIXME: Evil const cast hack!
|
mframe->LoadSaveRecentIsoList( evt );
|
||||||
mframe->LoadSaveRecentIsoList( const_cast<IniInterface&>(evt) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
|
@ -85,10 +85,10 @@ public:
|
||||||
void ReloadRecentLists();
|
void ReloadRecentLists();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void OnCoreThreadStatusChanged( void* obj, const wxCommandEvent& evt );
|
static void __fastcall OnCoreThreadStatusChanged( void* obj, wxCommandEvent& evt );
|
||||||
static void OnCorePluginStatusChanged( void* obj, const wxCommandEvent& evt );
|
static void __fastcall OnCorePluginStatusChanged( void* obj, wxCommandEvent& evt );
|
||||||
static void OnSettingsApplied( void* obj, const int& evt );
|
static void __fastcall OnSettingsApplied( void* obj, int& evt );
|
||||||
static void OnSettingsLoadSave( void* obj, const IniInterface& evt );
|
static void __fastcall OnSettingsLoadSave( void* obj, IniInterface& evt );
|
||||||
|
|
||||||
void LoadSaveRecentIsoList( IniInterface& conf );
|
void LoadSaveRecentIsoList( IniInterface& conf );
|
||||||
void ApplySettings();
|
void ApplySettings();
|
||||||
|
|
|
@ -380,16 +380,16 @@
|
||||||
RelativePath="..\..\Stats.cpp"
|
RelativePath="..\..\Stats.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\System\SysCoreThread.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\System.cpp"
|
RelativePath="..\..\System.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\System\SysThreads.cpp"
|
RelativePath="..\..\System\SysThreadBase.cpp"
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\System\SysThreads.h"
|
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<Filter
|
<Filter
|
||||||
|
@ -455,6 +455,10 @@
|
||||||
RelativePath="..\..\NakedAsm.h"
|
RelativePath="..\..\NakedAsm.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\System\PageFaultSource.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\Paths.h"
|
RelativePath="..\..\Paths.h"
|
||||||
>
|
>
|
||||||
|
@ -479,6 +483,10 @@
|
||||||
RelativePath="..\..\System.h"
|
RelativePath="..\..\System.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\System\SysThreads.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Linux"
|
Name="Linux"
|
||||||
|
|
|
@ -18,23 +18,23 @@
|
||||||
#include <winnt.h>
|
#include <winnt.h>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "System/PageFaultSource.h"
|
||||||
|
|
||||||
int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
|
int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
|
||||||
{
|
{
|
||||||
const _EXCEPTION_RECORD& ExceptionRecord = *eps->ExceptionRecord;
|
if( eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION )
|
||||||
|
|
||||||
if (ExceptionRecord.ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
|
||||||
{
|
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get bad virtual address
|
|
||||||
u32 offset = (u8*)ExceptionRecord.ExceptionInformation[1]-psM;
|
|
||||||
|
|
||||||
if (offset>=Ps2MemSize::Base)
|
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
|
||||||
mmap_ClearCpuBlock( offset );
|
PageFaultInfo info( (uptr)eps->ExceptionRecord->ExceptionInformation[1] );
|
||||||
|
|
||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
Source_PageFault.DispatchException( info );
|
||||||
|
|
||||||
|
if( info.handled ) return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
|
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstallSignalHandler()
|
||||||
|
{
|
||||||
|
// NOP on Win32 systems -- we use __try{} __except{} instead.
|
||||||
}
|
}
|
|
@ -22,11 +22,8 @@
|
||||||
#include "VU.h"
|
#include "VU.h"
|
||||||
#include "iCore.h"
|
#include "iCore.h"
|
||||||
|
|
||||||
#define PC_GETBLOCK(x) PC_GETBLOCK_(x, recLUT)
|
|
||||||
|
|
||||||
extern u32 pc;
|
extern u32 pc;
|
||||||
extern int branch;
|
extern int branch;
|
||||||
extern uptr recLUT[];
|
|
||||||
|
|
||||||
extern u32 maxrecmem;
|
extern u32 maxrecmem;
|
||||||
extern u32 pc; // recompiler pc (also used by the SuperVU! .. why? (air))
|
extern u32 pc; // recompiler pc (also used by the SuperVU! .. why? (air))
|
||||||
|
|
|
@ -19,42 +19,23 @@
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "R5900OpcodeTables.h"
|
#include "R5900OpcodeTables.h"
|
||||||
#include "iR5900.h"
|
#include "iR5900.h"
|
||||||
#include "iR5900AritImm.h"
|
|
||||||
#include "iR5900Arit.h"
|
|
||||||
#include "iR5900MultDiv.h"
|
|
||||||
#include "iR5900Shift.h"
|
|
||||||
#include "iR5900Branch.h"
|
|
||||||
#include "iR5900Jump.h"
|
|
||||||
#include "iR5900LoadStore.h"
|
|
||||||
#include "iR5900Move.h"
|
|
||||||
|
|
||||||
#include "BaseblockEx.h"
|
#include "BaseblockEx.h"
|
||||||
|
|
||||||
#include "iMMI.h"
|
|
||||||
#include "iFPU.h"
|
|
||||||
#include "iCOP0.h"
|
|
||||||
#include "sVU_Micro.h"
|
|
||||||
#include "VU.h"
|
|
||||||
#include "VUmicro.h"
|
|
||||||
|
|
||||||
#include "sVU_zerorec.h"
|
|
||||||
#include "vtlb.h"
|
#include "vtlb.h"
|
||||||
|
|
||||||
#include "SamplProf.h"
|
#include "SamplProf.h"
|
||||||
|
|
||||||
#include "NakedAsm.h"
|
|
||||||
#include "Dump.h"
|
#include "Dump.h"
|
||||||
|
|
||||||
|
#include "SysThreads.h"
|
||||||
|
#include "GS.h"
|
||||||
|
|
||||||
using namespace x86Emitter;
|
using namespace x86Emitter;
|
||||||
using namespace R5900;
|
using namespace R5900;
|
||||||
|
|
||||||
// used to disable register freezing during cpuBranchTests (registers
|
#define PC_GETBLOCK(x) PC_GETBLOCK_(x, recLUT)
|
||||||
// are safe then since they've been completely flushed)
|
|
||||||
bool g_EEFreezeRegs = false;
|
|
||||||
|
|
||||||
u32 maxrecmem = 0;
|
u32 maxrecmem = 0;
|
||||||
uptr recLUT[0x10000];
|
static uptr recLUT[0x10000];
|
||||||
uptr hwLUT[0x10000];
|
static uptr hwLUT[0x10000];
|
||||||
|
|
||||||
#define HWADDR(mem) (hwLUT[mem >> 16] + (mem))
|
#define HWADDR(mem) (hwLUT[mem >> 16] + (mem))
|
||||||
|
|
||||||
|
@ -584,13 +565,12 @@ struct ManualPageTracking
|
||||||
static __aligned16 u16 manual_page[Ps2MemSize::Base >> 12];
|
static __aligned16 u16 manual_page[Ps2MemSize::Base >> 12];
|
||||||
static __aligned16 u8 manual_counter[Ps2MemSize::Base >> 12];
|
static __aligned16 u8 manual_counter[Ps2MemSize::Base >> 12];
|
||||||
|
|
||||||
volatile bool eeRecIsReset = false;
|
static bool eeRecIsReset = false;
|
||||||
|
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
void recResetEE( void )
|
void recResetEE( void )
|
||||||
{
|
{
|
||||||
Console.Status( "Issuing EE/iR5900-32 Recompiler Reset [mem/structure cleanup]" );
|
Console.Status( "Issuing EE/iR5900-32 Recompiler Reset [mem/structure cleanup]" );
|
||||||
eeRecIsReset = true;
|
|
||||||
|
|
||||||
maxrecmem = 0;
|
maxrecmem = 0;
|
||||||
|
|
||||||
|
@ -652,6 +632,7 @@ void recResetEE( void )
|
||||||
|
|
||||||
branch = 0;
|
branch = 0;
|
||||||
SetCPUState(EmuConfig.Cpu.sseMXCSR, EmuConfig.Cpu.sseVUMXCSR);
|
SetCPUState(EmuConfig.Cpu.sseMXCSR, EmuConfig.Cpu.sseVUMXCSR);
|
||||||
|
eeRecIsReset = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recShutdown( void )
|
static void recShutdown( void )
|
||||||
|
@ -673,17 +654,60 @@ void recStep( void )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PCSX2_SEH
|
static jmp_buf m_SetJmp_StateCheck;
|
||||||
|
|
||||||
// <--- setjmp/longjmp model <---
|
static void recCheckExecutionState()
|
||||||
|
|
||||||
#include "GS.h"
|
|
||||||
#include "System/SysThreads.h"
|
|
||||||
|
|
||||||
static void StateThreadCheck_LongJmp()
|
|
||||||
{
|
{
|
||||||
setjmp( SetJmp_StateCheck );
|
#if PCSX2_SEH
|
||||||
|
SysCoreThread::Get().StateCheckInThread();
|
||||||
|
|
||||||
|
if( eeRecIsReset )
|
||||||
|
throw Exception::ForceDispatcherReg();
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Without SEH we'll need to hop to a safehouse point outside the scope of recompiled
|
||||||
|
// code. C++ exceptions can't cross the mighty chasm in the stackframe that the recompiler
|
||||||
|
// creates. However, the longjump is slow so we only want to do one when absolutely
|
||||||
|
// necessary:
|
||||||
|
|
||||||
|
pxAssert( !eeRecIsReset ); // should only be changed during suspended thread states
|
||||||
|
if( SysCoreThread::Get().HasPendingStateChangeRequest() )
|
||||||
|
{
|
||||||
|
longjmp( m_SetJmp_StateCheck, SetJmp_Dispatcher );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void recExecute()
|
||||||
|
{
|
||||||
|
// Implementation Notes:
|
||||||
|
// [TODO] fix this comment to explain various code entry/exit points, when I'm not so tired!
|
||||||
|
|
||||||
|
#if PCSX2_SEH
|
||||||
|
try {
|
||||||
|
while( true )
|
||||||
|
{
|
||||||
|
eeRecIsReset = false;
|
||||||
|
g_EEFreezeRegs = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
EnterRecompiledCode();
|
||||||
|
}
|
||||||
|
catch( Exception::ForceDispatcherReg& ) { }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch( Exception::ExitRecExecute& ) {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
switch( setjmp( m_SetJmp_StateCheck ) )
|
||||||
|
{
|
||||||
|
case 0: // first run, fall through to Dispatcher
|
||||||
|
case SetJmp_Dispatcher:
|
||||||
|
while( true )
|
||||||
|
{
|
||||||
int oldstate;
|
int oldstate;
|
||||||
|
|
||||||
// Important! Most of the console logging and such has cancel points in it. This is great
|
// Important! Most of the console logging and such has cancel points in it. This is great
|
||||||
|
@ -692,62 +716,37 @@ static void StateThreadCheck_LongJmp()
|
||||||
// of the cancelstate here!
|
// of the cancelstate here!
|
||||||
|
|
||||||
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
|
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
|
||||||
mtgsThread.RethrowException();
|
|
||||||
SysCoreThread::Get().StateCheckInThread();
|
SysCoreThread::Get().StateCheckInThread();
|
||||||
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate );
|
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate );
|
||||||
}
|
|
||||||
|
|
||||||
static void recExecute()
|
eeRecIsReset = false;
|
||||||
{
|
|
||||||
StateThreadCheck_LongJmp();
|
|
||||||
|
|
||||||
switch( setjmp( SetJmp_RecExecute ) )
|
#ifdef _WIN32
|
||||||
{
|
__try {
|
||||||
case SetJmp_Exit: break;
|
#endif
|
||||||
|
|
||||||
case 0:
|
|
||||||
case SetJmp_Dispatcher:
|
|
||||||
|
|
||||||
// Typically the Dispatcher is invoked from the EventTest code, which clears
|
|
||||||
// the FreezeRegs flag, so always be sure to reset it here:
|
|
||||||
g_EEFreezeRegs = true;
|
|
||||||
|
|
||||||
while( true )
|
|
||||||
EnterRecompiledCode();
|
EnterRecompiledCode();
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
} __finally
|
||||||
|
{
|
||||||
|
// This assertion is designed to help me troubleshoot the setjmp behavior from Win32.
|
||||||
|
// If the recompiler throws an unhandled SEH exception with SEH support disabled (which
|
||||||
|
// is typically a pthread_cancel) then this will fire and let me know.
|
||||||
|
|
||||||
|
// FIXME: Doesn't work because SEH is remarkably clever and executes the _finally block
|
||||||
|
// even when I use longjmp to restart the loop. Maybe a workaround exists? :/
|
||||||
|
|
||||||
|
//pxFailDev( "Recompiler threw an SEH exception with SEH disabled; possibly due to pthread_cancel." );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SetJmp_Exit: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_EEFreezeRegs = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
// ---> SEH Model --->
|
|
||||||
|
|
||||||
static void recExecute()
|
|
||||||
{
|
|
||||||
// Implementation Notes:
|
|
||||||
// [TODO] fix this comment to explain various code entry/exit points, when I'm not so tired!
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
while( true )
|
|
||||||
{
|
|
||||||
// Typically the Dispatcher is invoked from the EventTest code, which clears
|
|
||||||
// the FreezeRegs flag, so always be sure to reset it here:
|
|
||||||
g_EEFreezeRegs = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
EnterRecompiledCode();
|
|
||||||
}
|
|
||||||
catch( Exception::ForceDispatcherReg& ) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch( Exception::ExitRecExecute& ) { }
|
|
||||||
|
|
||||||
g_EEFreezeRegs = false;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
void R5900::Dynarec::OpcodeImpl::recSYSCALL( void )
|
void R5900::Dynarec::OpcodeImpl::recSYSCALL( void )
|
||||||
|
@ -856,17 +855,12 @@ void recClear(u32 addr, u32 size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef PCSX2_SEH
|
static void recExitExecution()
|
||||||
jmp_buf SetJmp_RecExecute;
|
|
||||||
jmp_buf SetJmp_StateCheck;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void ExitRec()
|
|
||||||
{
|
{
|
||||||
#ifdef PCSX2_SEH
|
#if PCSX2_SEH
|
||||||
throw Exception::ExitRecExecute();
|
throw Exception::ExitRecExecute();
|
||||||
#else
|
#else
|
||||||
longjmp( SetJmp_RecExecute, SetJmp_Exit );
|
longjmp( m_SetJmp_StateCheck, SetJmp_Exit );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -875,11 +869,9 @@ void CheckForBIOSEnd()
|
||||||
{
|
{
|
||||||
xMOV( eax, &cpuRegs.pc );
|
xMOV( eax, &cpuRegs.pc );
|
||||||
|
|
||||||
/*xCMP( eax, 0x00200008 );
|
if( IsDevBuild )
|
||||||
xJE(ExitRec);
|
{
|
||||||
|
// Using CALL retains stacktrace info, useful for debugging.
|
||||||
xCMP( eax, 0x00100008 );
|
|
||||||
xJE(ExitRec);*/
|
|
||||||
|
|
||||||
xCMP( eax, 0x00200008 );
|
xCMP( eax, 0x00200008 );
|
||||||
xForwardJE8 CallExitRec;
|
xForwardJE8 CallExitRec;
|
||||||
|
@ -888,9 +880,18 @@ void CheckForBIOSEnd()
|
||||||
xForwardJNE8 SkipExitRec;
|
xForwardJNE8 SkipExitRec;
|
||||||
|
|
||||||
CallExitRec.SetTarget();
|
CallExitRec.SetTarget();
|
||||||
xCALL( ExitRec );
|
xCALL( recExitExecution );
|
||||||
|
|
||||||
SkipExitRec.SetTarget();
|
SkipExitRec.SetTarget();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xCMP( eax, 0x00200008 );
|
||||||
|
xJE(recExitExecution);
|
||||||
|
|
||||||
|
xCMP( eax, 0x00100008 );
|
||||||
|
xJE(recExitExecution);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int *s_pCode;
|
static int *s_pCode;
|
||||||
|
@ -1765,11 +1766,13 @@ StartRecomp:
|
||||||
s_pCurBlockEx = NULL;
|
s_pCurBlockEx = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
R5900cpu recCpu = {
|
R5900cpu recCpu =
|
||||||
|
{
|
||||||
recAlloc,
|
recAlloc,
|
||||||
recResetEE,
|
recResetEE,
|
||||||
recStep,
|
recStep,
|
||||||
recExecute,
|
recExecute,
|
||||||
|
recCheckExecutionState,
|
||||||
recClear,
|
recClear,
|
||||||
recShutdown
|
recShutdown
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue