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="../../include/Utilities/Console.h" />
|
||||
<Unit filename="../../include/Utilities/Dependencies.h" />
|
||||
<Unit filename="../../include/Utilities/EventSource.h" />
|
||||
<Unit filename="../../include/Utilities/Exceptions.h" />
|
||||
<Unit filename="../../include/Utilities/General.h" />
|
||||
<Unit filename="../../include/Utilities/HashMap.h" />
|
||||
<Unit filename="../../include/Utilities/Listeners.h" />
|
||||
<Unit filename="../../include/Utilities/MemcpyFast.h" />
|
||||
<Unit filename="../../include/Utilities/Path.h" />
|
||||
<Unit filename="../../include/Utilities/RedtapeWindows.h" />
|
||||
|
|
|
@ -425,6 +425,10 @@
|
|||
RelativePath="..\..\include\Utilities\Dependencies.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\Utilities\EventSource.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\Utilities\Exceptions.h"
|
||||
>
|
||||
|
@ -441,10 +445,6 @@
|
|||
RelativePath="..\..\include\intrin_x86.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\Utilities\Listeners.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\Utilities\lnx_memzero.h"
|
||||
>
|
||||
|
|
|
@ -16,12 +16,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <wx/event.h>
|
||||
|
||||
class wxCommandEvent;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EventListener< typename EvtType >
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
template< typename EvtType >
|
||||
struct EventListener
|
||||
{
|
||||
typedef void FuncType( void* object, const EvtType& evt );
|
||||
typedef void __fastcall FuncType( void* object, EvtType& evt );
|
||||
|
||||
void* object;
|
||||
FuncType* OnEvent;
|
||||
|
@ -49,6 +54,10 @@ struct EventListener
|
|||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EventSource< template EvtType >
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
template< typename EvtType >
|
||||
class EventSource
|
||||
{
|
||||
|
@ -58,23 +67,38 @@ public:
|
|||
typedef typename ListenerList::iterator Handle;
|
||||
|
||||
protected:
|
||||
typedef typename ListenerList::const_iterator ConstIterator;
|
||||
|
||||
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:
|
||||
EventSource() : m_cache_valid( false )
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~EventSource() throw() {}
|
||||
|
||||
virtual void Remove( const ListenerType& listener )
|
||||
{
|
||||
m_cache_valid = false;
|
||||
m_listeners.remove( listener );
|
||||
}
|
||||
|
||||
virtual void Remove( const Handle& listenerHandle )
|
||||
{
|
||||
m_cache_valid = false;
|
||||
m_listeners.erase( listenerHandle );
|
||||
}
|
||||
|
||||
virtual Handle AddFast( const ListenerType& listener )
|
||||
{
|
||||
m_cache_valid = false;
|
||||
m_listeners.push_front( listener );
|
||||
return m_listeners.begin();
|
||||
}
|
||||
|
@ -93,14 +117,21 @@ public:
|
|||
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();
|
||||
while( iter != list.end() )
|
||||
protected:
|
||||
__forceinline void _DispatchRaw( ConstIterator& iter, const ConstIterator& iend, EvtType& evt )
|
||||
{
|
||||
while( iter != iend )
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -118,14 +149,15 @@ public:
|
|||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EventListenerBinding
|
||||
// EventListenerBinding< typename EvtType ?
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Encapsulated event listener binding, provides the "benefits" of object unwinding.
|
||||
//
|
||||
template< typename EvtType = wxCommandEvent >
|
||||
template< typename EvtType >
|
||||
class EventListenerBinding
|
||||
{
|
||||
public:
|
||||
|
@ -211,9 +243,7 @@ public:
|
|||
template< typename EvtType >
|
||||
void EventSource<EvtType>::RemoveObject( const void* object )
|
||||
{
|
||||
// Iso C++ rules regarding temporaries, specifically that non-const temporaries are disallowed,
|
||||
// also removes any actual convenience factor that unary predicates may have actually offered. >_<
|
||||
|
||||
m_cache_valid = false;
|
||||
m_listeners.remove_if( PredicatesAreTheThingsOfNightmares<EvtType>( object ) );
|
||||
}
|
||||
|
|
@ -280,6 +280,7 @@ namespace Threading
|
|||
bool IsRunning() const;
|
||||
bool IsSelf() const;
|
||||
wxString GetName() const;
|
||||
bool HasPendingException() const { return !!m_except; }
|
||||
|
||||
protected:
|
||||
// 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.
|
||||
OnStart();
|
||||
|
||||
m_except = NULL;
|
||||
|
||||
if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 )
|
||||
throw Exception::ThreadCreationError();
|
||||
}
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
// 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
|
||||
//
|
||||
|
|
|
@ -440,8 +440,6 @@ __forceinline void rcntUpdate_hScanline()
|
|||
}
|
||||
}
|
||||
|
||||
bool CoreCancelDamnit = false;
|
||||
|
||||
__forceinline void rcntUpdate_vSync()
|
||||
{
|
||||
s32 diff = (cpuRegs.cycle - vsyncCounter.sCycle);
|
||||
|
@ -449,28 +447,7 @@ __forceinline void rcntUpdate_vSync()
|
|||
|
||||
if (vsyncCounter.Mode == MODE_VSYNC)
|
||||
{
|
||||
eeRecIsReset = false;
|
||||
|
||||
#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
|
||||
}
|
||||
Cpu->CheckExecutionState();
|
||||
|
||||
VSyncEnd(vsyncCounter.sCycle);
|
||||
|
||||
|
|
|
@ -123,6 +123,8 @@ public:
|
|||
mtgsThreadObject();
|
||||
virtual ~mtgsThreadObject() throw();
|
||||
|
||||
static mtgsThreadObject& Get();
|
||||
|
||||
// Waits for the GS to empty out the entire ring buffer contents.
|
||||
// Used primarily for plugin startup/shutdown.
|
||||
void WaitGS();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "Common.h"
|
||||
#include "R5900.h"
|
||||
#include "R5900OpcodeTables.h"
|
||||
#include "System/SysThreads.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 std::string disOut;
|
||||
|
||||
static void intEventTest();
|
||||
|
||||
// These macros are used to assemble the repassembler functions
|
||||
|
||||
static void debugI()
|
||||
|
@ -356,24 +359,24 @@ void JALR()
|
|||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
void intAlloc()
|
||||
static void intAlloc()
|
||||
{
|
||||
// fixme : detect cpu for use the optimize asm code
|
||||
}
|
||||
|
||||
void intReset()
|
||||
static void intReset()
|
||||
{
|
||||
cpuRegs.branch = 0;
|
||||
branch2 = 0;
|
||||
}
|
||||
|
||||
void intEventTest()
|
||||
static void intEventTest()
|
||||
{
|
||||
// Perform counters, ints, and IOP updates:
|
||||
_cpuBranchTest_Shared();
|
||||
}
|
||||
|
||||
void intExecute()
|
||||
static void intExecute()
|
||||
{
|
||||
g_EEFreezeRegs = false;
|
||||
|
||||
|
@ -386,6 +389,11 @@ void intExecute()
|
|||
}
|
||||
}
|
||||
|
||||
static void intCheckExecutionState()
|
||||
{
|
||||
SysCoreThread::Get().StateCheckInThread();
|
||||
}
|
||||
|
||||
static void intStep()
|
||||
{
|
||||
g_EEFreezeRegs = false;
|
||||
|
@ -404,6 +412,7 @@ R5900cpu intCpu = {
|
|||
intReset,
|
||||
intStep,
|
||||
intExecute,
|
||||
intCheckExecutionState,
|
||||
intClear,
|
||||
intShutdown
|
||||
};
|
||||
|
|
|
@ -23,36 +23,34 @@ extern void SignalExit(int sig);
|
|||
|
||||
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;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = &SysPageFaultExceptionFilter;
|
||||
sa.sa_sigaction = SysPageFaultSignalFilter;
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
}
|
||||
|
||||
void ReleaseLinuxExceptionHandler()
|
||||
{
|
||||
// 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 );
|
||||
}
|
||||
void NTFS_CompressFile( const wxString& file, bool compressStatus=true ) {}
|
||||
|
|
|
@ -236,7 +236,9 @@
|
|||
<Unit filename="../StringUtils.h" />
|
||||
<Unit filename="../System.cpp" />
|
||||
<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="../Tags.h" />
|
||||
<Unit filename="../Utilities/AsciiFile.h" />
|
||||
|
|
|
@ -86,6 +86,14 @@ extern bool renderswitch;
|
|||
std::list<uint> ringposStack;
|
||||
#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() :
|
||||
SysThreadBase()
|
||||
, m_RingPos( 0 )
|
||||
|
@ -162,8 +170,8 @@ void mtgsThreadObject::PostVsyncEnd( bool updategs )
|
|||
if( m_WritePos == volatize( m_RingPos ) )
|
||||
{
|
||||
// MTGS ringbuffer is empty, but we still have queued frames in the counter? Ouch!
|
||||
Console.Error( "MTGS > Queued framecount mismatch = %d", m_QueuedFrames );
|
||||
m_QueuedFrames = 0;
|
||||
int count = AtomicExchange( m_QueuedFrames, 0 );
|
||||
Console.Error( "MTGS > Queued framecount mismatch = %d", count );
|
||||
break;
|
||||
}
|
||||
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()
|
||||
{
|
||||
tls_mtgsThread = this;
|
||||
|
||||
#ifdef RINGBUF_DEBUG_STACK
|
||||
PacketTagType prevCmd;
|
||||
#endif
|
||||
|
||||
while( true )
|
||||
{
|
||||
m_sem_event.WaitRaw(); // ... because this does a cancel test itself..
|
||||
StateCheckInThread( false ); // false disables cancel test here!
|
||||
// Performance note: Both of these perform cancellation tests, but pthread_testcancel
|
||||
// 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;
|
||||
|
||||
|
@ -268,8 +282,7 @@ void mtgsThreadObject::ExecuteTaskInThread()
|
|||
|
||||
// stall for a bit to let the MainThread have time to update the g_pGSWritePos.
|
||||
m_lock_RingRestart.Wait();
|
||||
|
||||
StateCheckInThread( false ); // disable cancel since the above locks are cancelable already
|
||||
StateCheckInThread();
|
||||
continue;
|
||||
|
||||
case GS_RINGTYPE_P1:
|
||||
|
@ -427,6 +440,7 @@ void mtgsThreadObject::OnResumeInThread( bool isSuspended )
|
|||
void mtgsThreadObject::OnCleanupInThread()
|
||||
{
|
||||
ClosePlugin();
|
||||
tls_mtgsThread = NULL;
|
||||
_parent::OnCleanupInThread();
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ BIOS
|
|||
#include "VUmicro.h"
|
||||
#include "GS.h"
|
||||
#include "IPU/IPU.h"
|
||||
#include "AppConfig.h"
|
||||
#include "System/PageFaultSource.h"
|
||||
|
||||
|
||||
#ifdef ENABLECACHE
|
||||
|
@ -574,6 +574,8 @@ void memClearPageAddr(u32 vaddr)
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// PS2 Memory Init / Reset / Shutdown
|
||||
|
||||
static void __fastcall mmap_OnPageFault( void* basemem, PageFaultInfo& info );
|
||||
|
||||
static const uint m_allMemSize =
|
||||
Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2 + Ps2MemSize::ERom +
|
||||
Ps2MemSize::Base + Ps2MemSize::Hardware + Ps2MemSize::Scratch;
|
||||
|
@ -596,10 +598,14 @@ void memAlloc()
|
|||
psER = curpos; curpos += Ps2MemSize::ERom;
|
||||
psH = curpos; curpos += Ps2MemSize::Hardware;
|
||||
psS = curpos; //curpos += Ps2MemSize::Scratch;
|
||||
|
||||
Source_PageFault.Add( EventListener<PageFaultInfo>((void*)psM, mmap_OnPageFault) );
|
||||
}
|
||||
|
||||
void memShutdown()
|
||||
{
|
||||
Source_PageFault.Remove( EventListener<PageFaultInfo>((void*)psM, mmap_OnPageFault) );
|
||||
|
||||
vtlb_free( m_psAllMem, m_allMemSize );
|
||||
m_psAllMem = NULL;
|
||||
psM = psR = psR1 = psR2 = psER = psS = psH = NULL;
|
||||
|
@ -623,8 +629,7 @@ void memBindConditionalHandlers()
|
|||
void memReset()
|
||||
{
|
||||
// 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
|
||||
// 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 );
|
||||
}
|
||||
|
||||
// offset - offset of address relative to psM. The exception handler for the platform/host
|
||||
// OS should ensure that only addresses within psM address space are passed. Anything else
|
||||
// will produce undefined results (ie, crashes).
|
||||
void mmap_ClearCpuBlock( uint offset )
|
||||
// offset - offset of address relative to psM.
|
||||
static __forceinline void mmap_ClearCpuBlock( uint offset )
|
||||
{
|
||||
int rampage = offset >> 12;
|
||||
|
||||
// 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.
|
||||
jASSUME( m_PageProtectInfo[rampage].Mode != ProtMode_Manual );
|
||||
|
||||
//#ifndef __LINUX__ // this function is called from the signal handler
|
||||
//DbgCon.WriteLn( "Manual page @ 0x%05x", m_PageProtectInfo[rampage].ReverseRamMap>>12 );
|
||||
//#endif
|
||||
pxAssertMsg( m_PageProtectInfo[rampage].Mode != ProtMode_Manual,
|
||||
"Attempted to clear a block that is already under manual protection." );
|
||||
|
||||
HostSys::MemProtect( &psM[rampage<<12], 1, Protect_ReadWrite );
|
||||
m_PageProtectInfo[rampage].Mode = ProtMode_Manual;
|
||||
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.
|
||||
// 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.
|
||||
void mmap_ResetBlockTracking()
|
||||
{
|
||||
|
|
|
@ -134,7 +134,6 @@ extern void memMapVUmicro();
|
|||
extern int mmap_GetRamPageInfo( u32 paddr );
|
||||
extern void mmap_MarkCountedRamPage( u32 paddr );
|
||||
extern void mmap_ResetBlockTracking();
|
||||
extern void mmap_ClearCpuBlock( uint offset );
|
||||
|
||||
#define memRead8 vtlb_memRead8
|
||||
#define memRead16 vtlb_memRead16
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "SPR.h"
|
||||
#include "Sif.h"
|
||||
|
||||
#include "System/SysThreads.h"
|
||||
|
||||
#include "R5900Exceptions.h"
|
||||
|
||||
using namespace R5900; // for R5900 disasm tools
|
||||
|
@ -61,6 +63,8 @@ void cpuReset()
|
|||
if( mtgsThread.IsOpen() )
|
||||
mtgsThread.WaitGS(); // GS better be done processing before we reset the EE, just in case.
|
||||
|
||||
SysClearExecutionCache();
|
||||
|
||||
cpuIsInitialized = true;
|
||||
|
||||
memReset();
|
||||
|
@ -560,7 +564,6 @@ void cpuExecuteBios()
|
|||
|
||||
Console.Status( "Executing Bios Stub..." );
|
||||
|
||||
PCSX2_MEM_PROTECT_BEGIN();
|
||||
g_ExecBiosHack = true;
|
||||
while( cpuRegs.pc != 0x00200008 &&
|
||||
cpuRegs.pc != 0x00100008 )
|
||||
|
@ -568,7 +571,6 @@ void cpuExecuteBios()
|
|||
Cpu->Execute();
|
||||
}
|
||||
g_ExecBiosHack = false;
|
||||
PCSX2_MEM_PROTECT_END();
|
||||
|
||||
// {
|
||||
// FILE* f = fopen("eebios.bin", "wb");
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
|
||||
extern bool g_EEFreezeRegs;
|
||||
extern bool g_ExecBiosHack;
|
||||
extern volatile bool eeRecIsReset;
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
|
@ -256,7 +255,6 @@ extern bool eeEventTestIsActive;
|
|||
extern u32 s_iLastCOP0Cycle;
|
||||
extern u32 s_iLastPERFCycle[2];
|
||||
|
||||
void intEventTest();
|
||||
void intSetBranch();
|
||||
|
||||
// This is a special form of the interpreter's doBranch that is run from various
|
||||
|
@ -272,6 +270,7 @@ struct R5900cpu
|
|||
void (*Reset)();
|
||||
void (*Step)();
|
||||
void (*Execute)();
|
||||
void (*CheckExecutionState)();
|
||||
void (*Clear)(u32 Addr, u32 Size);
|
||||
void (*Shutdown)(); // deallocates memory reserved by Allocate
|
||||
};
|
||||
|
|
|
@ -34,7 +34,7 @@ int sys_resume_lock = 0;
|
|||
|
||||
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;
|
||||
((PersistentThread*)thr)->Cancel();
|
||||
|
|
|
@ -25,8 +25,10 @@
|
|||
#include "sVU_zerorec.h" // for SuperVUReset
|
||||
|
||||
#include "R5900Exceptions.h"
|
||||
|
||||
#include "CDVD/CDVD.h"
|
||||
#include "System/PageFaultSource.h"
|
||||
|
||||
SrcType_PageFault Source_PageFault;
|
||||
|
||||
#if _MSC_VER
|
||||
# include "svnrev.h"
|
||||
|
@ -106,6 +108,8 @@ static wxString GetMemoryErrorVM()
|
|||
|
||||
SysCoreAllocations::SysCoreAllocations()
|
||||
{
|
||||
InstallSignalHandler();
|
||||
|
||||
Console.Status( "Initializing PS2 virtual machine..." );
|
||||
|
||||
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 void vSyncDebugStuff( uint frame );
|
||||
extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true );
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Memory Protection (Used by VTLB, Recompilers, and Texture caches)
|
||||
// --------------------------------------------------------------------------------------
|
||||
#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.
|
||||
// PCSX2_SEH - Defines existence of "built in" Structured Exception Handling support.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// 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
|
||||
// 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
|
||||
// code execution pipelines in an efficient manner, since standard C++ exceptions cannot
|
||||
// unwind across dynamically recompiled code.
|
||||
|
||||
enum
|
||||
{
|
||||
SetJmp_Dispatcher = 1,
|
||||
SetJmp_Exit,
|
||||
};
|
||||
|
||||
extern jmp_buf SetJmp_RecExecute;
|
||||
extern jmp_buf SetJmp_StateCheck;
|
||||
#ifndef PCSX2_SEH
|
||||
# if defined(_WIN32) && !defined(__GNUC__)
|
||||
# define PCSX2_SEH 1
|
||||
# else
|
||||
# define PCSX2_SEH 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// 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
|
||||
|
||||
class pxMessageBoxEvent;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
// responded to the prompt.
|
||||
//
|
||||
|
||||
class pxMessageBoxEvent;
|
||||
|
||||
namespace Msgbox
|
||||
{
|
||||
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 "Common.h"
|
||||
|
||||
#include "System.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
|
||||
|
@ -267,7 +258,7 @@ void SysThreadBase::OnCleanupInThread()
|
|||
void SysThreadBase::OnSuspendInThread() {}
|
||||
void SysThreadBase::OnResumeInThread( bool isSuspended ) {}
|
||||
|
||||
void SysThreadBase::StateCheckInThread( bool isCancelable )
|
||||
void SysThreadBase::StateCheckInThread()
|
||||
{
|
||||
switch( m_ExecMode )
|
||||
{
|
||||
|
@ -283,7 +274,6 @@ void SysThreadBase::StateCheckInThread( bool isCancelable )
|
|||
case ExecMode_Opened:
|
||||
// Yup, need this a second time. Variable state could have changed while we
|
||||
// were trying to acquire the lock above.
|
||||
if( isCancelable )
|
||||
TestCancel();
|
||||
break;
|
||||
|
||||
|
@ -324,197 +314,3 @@ void SysThreadBase::StateCheckInThread( bool isCancelable )
|
|||
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;
|
||||
|
||||
|
||||
#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
|
||||
{
|
||||
public:
|
||||
|
@ -30,6 +49,9 @@ public:
|
|||
virtual void Resume() {}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysThreadBase
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
class SysThreadBase : public PersistentThread, public virtual ISysThread
|
||||
{
|
||||
|
@ -93,7 +115,7 @@ public:
|
|||
return m_ExecMode > ExecMode_Closed;
|
||||
}
|
||||
|
||||
bool HasPendingStateChangeRequest()
|
||||
bool HasPendingStateChangeRequest() const
|
||||
{
|
||||
ExecutionMode mode = m_ExecMode;
|
||||
return (mode == ExecMode_Closing) || (mode == ExecMode_Pausing);
|
||||
|
@ -108,8 +130,6 @@ public:
|
|||
virtual void Resume();
|
||||
virtual bool Pause();
|
||||
|
||||
virtual void StateCheckInThread( bool isCancelable = true );
|
||||
|
||||
protected:
|
||||
virtual void OnStart();
|
||||
|
||||
|
@ -118,6 +138,7 @@ protected:
|
|||
// Resume() has a lot of checks and balances to prevent re-entrance and race conditions.
|
||||
virtual void OnResumeReady() {}
|
||||
|
||||
virtual void StateCheckInThread();
|
||||
virtual void OnCleanupInThread();
|
||||
virtual void OnStartInThread();
|
||||
|
||||
|
@ -147,8 +168,10 @@ protected:
|
|||
virtual void OnResumeInThread( bool isSuspended )=0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EECoreThread class
|
||||
// SysCoreThread class
|
||||
// --------------------------------------------------------------------------------------
|
||||
class SysCoreThread : public SysThreadBase
|
||||
{
|
||||
|
@ -160,6 +183,9 @@ protected:
|
|||
bool m_resetVirtualMachine;
|
||||
bool m_hasValidState;
|
||||
|
||||
// Used by SETJMP only, but ifdef'ing it out clutters up the code.
|
||||
bool m_CoreCancelDamnit;
|
||||
|
||||
public:
|
||||
static SysCoreThread& Get();
|
||||
|
||||
|
@ -177,9 +203,12 @@ public:
|
|||
return m_hasValidState;
|
||||
}
|
||||
|
||||
bool HasPendingStateChangeRequest() const;
|
||||
|
||||
virtual void StateCheckInThread();
|
||||
|
||||
protected:
|
||||
void CpuInitializeMess();
|
||||
void CpuExecute();
|
||||
|
||||
virtual void Start();
|
||||
virtual void OnSuspendInThread();
|
||||
|
@ -187,6 +216,8 @@ protected:
|
|||
virtual void OnResumeInThread( bool IsSuspended );
|
||||
virtual void OnCleanupInThread();
|
||||
virtual void ExecuteTaskInThread();
|
||||
|
||||
void _StateCheckThrows();
|
||||
};
|
||||
|
||||
extern int sys_resume_lock;
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <wx/docview.h>
|
||||
#include <wx/apptrait.h>
|
||||
|
||||
#include "Utilities/Listeners.h"
|
||||
#include "Utilities/EventSource.h"
|
||||
#include "IniInterface.h"
|
||||
|
||||
//class IniInterface;
|
||||
|
@ -490,7 +490,7 @@ public:
|
|||
|
||||
virtual bool Suspend( bool isBlocking=true );
|
||||
virtual void Resume();
|
||||
virtual void StateCheckInThread( bool isCancelable=true );
|
||||
virtual void StateCheckInThread();
|
||||
virtual void ApplySettings( const Pcsx2Config& src );
|
||||
|
||||
protected:
|
||||
|
|
|
@ -128,9 +128,9 @@ void AppCoreThread::OnCleanupInThread()
|
|||
extern int TranslateGDKtoWXK( u32 keysym );
|
||||
#endif
|
||||
|
||||
void AppCoreThread::StateCheckInThread( bool isCancelable )
|
||||
void AppCoreThread::StateCheckInThread()
|
||||
{
|
||||
_parent::StateCheckInThread( isCancelable );
|
||||
_parent::StateCheckInThread();
|
||||
if( !pxAssert(g_plugins!=NULL) ) return;
|
||||
|
||||
const keyEvent* ev = PADkeyEvent();
|
||||
|
|
|
@ -244,7 +244,6 @@ bool Pcsx2App::OnInit()
|
|||
Connect( pxEVT_SysExecute, wxCommandEventHandler( Pcsx2App::OnSysExecute ) );
|
||||
|
||||
Connect( pxEVT_LoadPluginsComplete, wxCommandEventHandler( Pcsx2App::OnLoadPluginsComplete ) );
|
||||
|
||||
Connect( pxEVT_CoreThreadStatus, wxCommandEventHandler( Pcsx2App::OnCoreThreadStatus ) );
|
||||
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
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
(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 )
|
||||
{
|
||||
|
@ -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();
|
||||
|
||||
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 );
|
||||
|
||||
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;
|
||||
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
||||
mframe->ApplyCoreStatus();
|
||||
}
|
||||
|
||||
void MainEmuFrame::OnCorePluginStatusChanged( void* obj, const wxCommandEvent& evt )
|
||||
void __fastcall MainEmuFrame::OnCorePluginStatusChanged( void* obj, wxCommandEvent& evt )
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
||||
mframe->ApplyCoreStatus();
|
||||
}
|
||||
|
||||
void MainEmuFrame::OnSettingsApplied( void* obj, const int& evt )
|
||||
void __fastcall MainEmuFrame::OnSettingsApplied( void* obj, int& evt )
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
||||
mframe->ApplySettings();
|
||||
}
|
||||
|
||||
void MainEmuFrame::OnSettingsLoadSave( void* obj, const IniInterface& evt )
|
||||
void __fastcall MainEmuFrame::OnSettingsLoadSave( void* obj, IniInterface& evt )
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
||||
|
||||
// FIXME: Evil const cast hack!
|
||||
mframe->LoadSaveRecentIsoList( const_cast<IniInterface&>(evt) );
|
||||
mframe->LoadSaveRecentIsoList( evt );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
@ -85,10 +85,10 @@ public:
|
|||
void ReloadRecentLists();
|
||||
|
||||
protected:
|
||||
static void OnCoreThreadStatusChanged( void* obj, const wxCommandEvent& evt );
|
||||
static void OnCorePluginStatusChanged( void* obj, const wxCommandEvent& evt );
|
||||
static void OnSettingsApplied( void* obj, const int& evt );
|
||||
static void OnSettingsLoadSave( void* obj, const IniInterface& evt );
|
||||
static void __fastcall OnCoreThreadStatusChanged( void* obj, wxCommandEvent& evt );
|
||||
static void __fastcall OnCorePluginStatusChanged( void* obj, wxCommandEvent& evt );
|
||||
static void __fastcall OnSettingsApplied( void* obj, int& evt );
|
||||
static void __fastcall OnSettingsLoadSave( void* obj, IniInterface& evt );
|
||||
|
||||
void LoadSaveRecentIsoList( IniInterface& conf );
|
||||
void ApplySettings();
|
||||
|
|
|
@ -380,16 +380,16 @@
|
|||
RelativePath="..\..\Stats.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\System\SysCoreThread.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\System.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\System\SysThreads.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\System\SysThreads.h"
|
||||
RelativePath="..\..\System\SysThreadBase.cpp"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
|
@ -455,6 +455,10 @@
|
|||
RelativePath="..\..\NakedAsm.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\System\PageFaultSource.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Paths.h"
|
||||
>
|
||||
|
@ -479,6 +483,10 @@
|
|||
RelativePath="..\..\System.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\System\SysThreads.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Linux"
|
||||
|
|
|
@ -18,23 +18,23 @@
|
|||
#include <winnt.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "System/PageFaultSource.h"
|
||||
|
||||
int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
|
||||
{
|
||||
const _EXCEPTION_RECORD& ExceptionRecord = *eps->ExceptionRecord;
|
||||
|
||||
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)
|
||||
if( eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION )
|
||||
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 "iCore.h"
|
||||
|
||||
#define PC_GETBLOCK(x) PC_GETBLOCK_(x, recLUT)
|
||||
|
||||
extern u32 pc;
|
||||
extern int branch;
|
||||
extern uptr recLUT[];
|
||||
|
||||
extern u32 maxrecmem;
|
||||
extern u32 pc; // recompiler pc (also used by the SuperVU! .. why? (air))
|
||||
|
|
|
@ -19,42 +19,23 @@
|
|||
#include "Memory.h"
|
||||
#include "R5900OpcodeTables.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 "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 "SamplProf.h"
|
||||
|
||||
#include "NakedAsm.h"
|
||||
#include "Dump.h"
|
||||
|
||||
#include "SysThreads.h"
|
||||
#include "GS.h"
|
||||
|
||||
using namespace x86Emitter;
|
||||
using namespace R5900;
|
||||
|
||||
// used to disable register freezing during cpuBranchTests (registers
|
||||
// are safe then since they've been completely flushed)
|
||||
bool g_EEFreezeRegs = false;
|
||||
#define PC_GETBLOCK(x) PC_GETBLOCK_(x, recLUT)
|
||||
|
||||
u32 maxrecmem = 0;
|
||||
uptr recLUT[0x10000];
|
||||
uptr hwLUT[0x10000];
|
||||
static uptr recLUT[0x10000];
|
||||
static uptr hwLUT[0x10000];
|
||||
|
||||
#define HWADDR(mem) (hwLUT[mem >> 16] + (mem))
|
||||
|
||||
|
@ -584,13 +565,12 @@ struct ManualPageTracking
|
|||
static __aligned16 u16 manual_page[Ps2MemSize::Base >> 12];
|
||||
static __aligned16 u8 manual_counter[Ps2MemSize::Base >> 12];
|
||||
|
||||
volatile bool eeRecIsReset = false;
|
||||
static bool eeRecIsReset = false;
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
void recResetEE( void )
|
||||
{
|
||||
Console.Status( "Issuing EE/iR5900-32 Recompiler Reset [mem/structure cleanup]" );
|
||||
eeRecIsReset = true;
|
||||
|
||||
maxrecmem = 0;
|
||||
|
||||
|
@ -652,6 +632,7 @@ void recResetEE( void )
|
|||
|
||||
branch = 0;
|
||||
SetCPUState(EmuConfig.Cpu.sseMXCSR, EmuConfig.Cpu.sseVUMXCSR);
|
||||
eeRecIsReset = true;
|
||||
}
|
||||
|
||||
static void recShutdown( void )
|
||||
|
@ -673,17 +654,60 @@ void recStep( void )
|
|||
{
|
||||
}
|
||||
|
||||
#ifndef PCSX2_SEH
|
||||
static jmp_buf m_SetJmp_StateCheck;
|
||||
|
||||
// <--- setjmp/longjmp model <---
|
||||
|
||||
#include "GS.h"
|
||||
#include "System/SysThreads.h"
|
||||
|
||||
static void StateThreadCheck_LongJmp()
|
||||
static void recCheckExecutionState()
|
||||
{
|
||||
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;
|
||||
|
||||
// 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!
|
||||
|
||||
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
|
||||
mtgsThread.RethrowException();
|
||||
SysCoreThread::Get().StateCheckInThread();
|
||||
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate );
|
||||
}
|
||||
|
||||
static void recExecute()
|
||||
{
|
||||
StateThreadCheck_LongJmp();
|
||||
eeRecIsReset = false;
|
||||
|
||||
switch( setjmp( SetJmp_RecExecute ) )
|
||||
{
|
||||
case SetJmp_Exit: break;
|
||||
#ifdef _WIN32
|
||||
__try {
|
||||
#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();
|
||||
|
||||
#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;
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
void R5900::Dynarec::OpcodeImpl::recSYSCALL( void )
|
||||
|
@ -856,17 +855,12 @@ void recClear(u32 addr, u32 size)
|
|||
}
|
||||
|
||||
|
||||
#ifndef PCSX2_SEH
|
||||
jmp_buf SetJmp_RecExecute;
|
||||
jmp_buf SetJmp_StateCheck;
|
||||
#endif
|
||||
|
||||
static void ExitRec()
|
||||
static void recExitExecution()
|
||||
{
|
||||
#ifdef PCSX2_SEH
|
||||
#if PCSX2_SEH
|
||||
throw Exception::ExitRecExecute();
|
||||
#else
|
||||
longjmp( SetJmp_RecExecute, SetJmp_Exit );
|
||||
longjmp( m_SetJmp_StateCheck, SetJmp_Exit );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -875,11 +869,9 @@ void CheckForBIOSEnd()
|
|||
{
|
||||
xMOV( eax, &cpuRegs.pc );
|
||||
|
||||
/*xCMP( eax, 0x00200008 );
|
||||
xJE(ExitRec);
|
||||
|
||||
xCMP( eax, 0x00100008 );
|
||||
xJE(ExitRec);*/
|
||||
if( IsDevBuild )
|
||||
{
|
||||
// Using CALL retains stacktrace info, useful for debugging.
|
||||
|
||||
xCMP( eax, 0x00200008 );
|
||||
xForwardJE8 CallExitRec;
|
||||
|
@ -888,9 +880,18 @@ void CheckForBIOSEnd()
|
|||
xForwardJNE8 SkipExitRec;
|
||||
|
||||
CallExitRec.SetTarget();
|
||||
xCALL( ExitRec );
|
||||
xCALL( recExitExecution );
|
||||
|
||||
SkipExitRec.SetTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
xCMP( eax, 0x00200008 );
|
||||
xJE(recExitExecution);
|
||||
|
||||
xCMP( eax, 0x00100008 );
|
||||
xJE(recExitExecution);
|
||||
}
|
||||
}
|
||||
|
||||
static int *s_pCode;
|
||||
|
@ -1765,11 +1766,13 @@ StartRecomp:
|
|||
s_pCurBlockEx = NULL;
|
||||
}
|
||||
|
||||
R5900cpu recCpu = {
|
||||
R5900cpu recCpu =
|
||||
{
|
||||
recAlloc,
|
||||
recResetEE,
|
||||
recStep,
|
||||
recExecute,
|
||||
recCheckExecutionState,
|
||||
recClear,
|
||||
recShutdown
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue