* Moved some files around in an attempt to improve CoreEmu and UI separation.
 * Major upgrade to the UI's handling of savestates
 * Maintenance work to the C++ exception handling
 * Some improved error handling and message popups here or there

git-svn-id: http://pcsx2.googlecode.com/svn/branches/wxgui@1714 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-08-31 03:47:05 +00:00
parent ea1b204bde
commit 980afabc30
42 changed files with 1032 additions and 1245 deletions

View File

@ -67,25 +67,30 @@ namespace Exception
// Translation Note: These exceptions are never translated, except to issue a general
// error message to the user (which is specified below).
//
class Ps2Generic : public BaseException
class Ps2Generic
{
protected:
const wxString m_message_eng; // (untranslated) a "detailed" message of what disastrous thing has occurred!
public:
virtual ~Ps2Generic() throw() {}
explicit Ps2Generic( const char* msg="Ps2/MIPS cpu caused a general exception" ) :
BaseException( msg ) { }
explicit Ps2Generic( const wxString& msg_eng, const wxString& msg_xlt=_("Ps2/MIPS cpu caused a general exception") ) :
BaseException( msg_eng, msg_xlt ) { }
explicit Ps2Generic( const char* msg ) :
m_message_eng( wxString::FromUTF8( msg ) ) { }
explicit Ps2Generic( const wxString& msg=L"Ps2/MIPS cpu caused a general exception" ) :
m_message_eng( msg ) { }
virtual u32 GetPc() const=0;
virtual bool IsDelaySlot() const=0;
virtual wxString Message() const { return m_message_eng; }
};
// ---------------------------------------------------------------------------------------
// Generalized Exceptions: RuntimeError / LogicError / AssertionFailure
// ---------------------------------------------------------------------------------------
class RuntimeError : public BaseException
class RuntimeError : public virtual BaseException
{
public:
virtual ~RuntimeError() throw() {}
@ -99,7 +104,7 @@ namespace Exception
BaseException( msg_eng, msg_xlt ) { }
};
class LogicError : public BaseException
class LogicError : public virtual BaseException
{
public:
virtual ~LogicError() throw() {}
@ -112,15 +117,17 @@ namespace Exception
explicit LogicError( const wxString& msg_eng, const wxString& msg_xlt ) :
BaseException( msg_eng, msg_xlt ) { }
};
class AssertionFailure : public LogicError
class AssertionFailure : public virtual LogicError
{
public:
explicit AssertionFailure( const char* msg=wxLt("Assertion Failure") ) :
LogicError( msg ) {}
LogicError( msg )
, BaseException( msg ) {}
explicit AssertionFailure( const wxString& msg_eng, const wxString& msg_xlt ) :
LogicError( msg_eng, msg_xlt ) { }
LogicError( msg_eng, msg_xlt )
, BaseException( msg_eng, msg_xlt ) {}
virtual ~AssertionFailure() throw() {}
};
@ -129,40 +136,45 @@ namespace Exception
// OutOfMemory / InvalidOperation / InvalidArgument / IndexBoundsFault / ParseError
// ---------------------------------------------------------------------------------------
class OutOfMemory : public RuntimeError
class OutOfMemory : public virtual RuntimeError
{
public:
virtual ~OutOfMemory() throw() {}
explicit OutOfMemory( const char* msg=wxLt("Out of memory") ) :
RuntimeError( msg ) {}
RuntimeError( msg )
, BaseException( msg ) {}
explicit OutOfMemory( const wxString& msg_eng, const wxString& msg_xlt=_("Out of memory") ) :
RuntimeError( msg_eng, msg_xlt ) { }
RuntimeError( msg_eng, msg_xlt )
, BaseException( msg_eng, msg_xlt ) {}
};
// This exception thrown any time an operation is attempted when an object
// is in an uninitialized state.
//
class InvalidOperation : public LogicError
class InvalidOperation : public virtual LogicError
{
public:
virtual ~InvalidOperation() throw() {}
explicit InvalidOperation( const char* msg="Attempted method call is invalid for the current object or program state." ) :
LogicError( msg ) {}
LogicError( msg )
, BaseException( msg ) {}
explicit InvalidOperation( const wxString& msg_eng, const wxString& msg_xlt ) :
LogicError( msg_eng, msg_xlt ) { }
LogicError( msg_eng, msg_xlt )
, BaseException( msg_eng, msg_xlt ) {}
};
// This exception thrown any time an operation is attempted when an object
// is in an uninitialized state.
//
class InvalidArgument : public LogicError
class InvalidArgument : public virtual LogicError
{
public:
virtual ~InvalidArgument() throw() {}
explicit InvalidArgument( const char* msg="Invalid argument passed to a function." ) :
LogicError( msg )
, BaseException( msg )
{
// assertions make debugging easier sometimes. :)
wxASSERT_MSG_A( false, msg );
@ -172,7 +184,7 @@ namespace Exception
// Keep those array indexers in bounds when using the SafeArray type, or you'll be
// seeing these.
//
class IndexBoundsFault : public LogicError
class IndexBoundsFault : public virtual AssertionFailure
{
public:
const wxString ArrayName;
@ -182,14 +194,11 @@ namespace Exception
public:
virtual ~IndexBoundsFault() throw() {}
explicit IndexBoundsFault( const wxString& objname, int index, int arrsize ) :
LogicError( "Index is outside the bounds of an array." ),
AssertionFailure( "Index is outside the bounds of an array." ),
ArrayName( objname ),
ArrayLength( arrsize ),
BadIndex( index )
{
// assertions make debugging easier sometimes. :)
wxASSERT_MSG( false, L"Index is outside the bounds of an array" );
}
, BaseException( "Index is outside the bounds of an array." ) {}
virtual wxString LogMessage() const;
virtual wxString DisplayMessage() const;
@ -200,7 +209,8 @@ namespace Exception
public:
virtual ~ParseError() throw() {}
explicit ParseError( const char* msg="Parse error" ) :
RuntimeError( msg ) {}
RuntimeError( msg )
, BaseException( msg ) {}
};
// ---------------------------------------------------------------------------------------
@ -208,50 +218,22 @@ namespace Exception
// HardwareDeficiency / CpuStateShutdown / PluginFailure / ThreadCreationError
// ---------------------------------------------------------------------------------------
class HardwareDeficiency : public RuntimeError
class HardwareDeficiency : public virtual RuntimeError
{
public:
explicit HardwareDeficiency( const char* msg=wxLt("Your machine's hardware is incapable of running Pcsx2. Sorry dood.") ) :
RuntimeError( msg ) {}
RuntimeError( msg )
, BaseException( msg ) {}
virtual ~HardwareDeficiency() throw() {}
};
// This exception is thrown by the PS2 emulation (R5900, etc) when bad things happen
// that force the emulation state to terminate. The GUI should handle them by returning
// the user to the GUI.
//
class CpuStateShutdown : public RuntimeError
{
public:
virtual ~CpuStateShutdown() throw() {}
explicit CpuStateShutdown( const char* msg="Unexpected emulation shutdown" ) :
RuntimeError( msg ) {}
explicit CpuStateShutdown( const wxString& msg_eng, const wxString& msg_xlt=wxString() ) :
RuntimeError( msg_eng, msg_xlt.IsEmpty() ? L"Unexpected emulation shutdown" : msg_xlt ) { }
};
class PluginFailure : public RuntimeError
{
public:
wxString plugin_name; // name of the plugin
virtual ~PluginFailure() throw() {}
explicit PluginFailure( const char* plugin, const char* msg="%s plugin encountered a critical error" ) :
RuntimeError( msg )
, plugin_name( wxString::FromAscii(plugin) ) {}
virtual wxString LogMessage() const;
virtual wxString DisplayMessage() const;
};
class ThreadCreationError : public RuntimeError
class ThreadCreationError : public virtual RuntimeError
{
public:
virtual ~ThreadCreationError() throw() {}
explicit ThreadCreationError( const char* msg="Thread could not be created." ) :
RuntimeError( msg ) {}
RuntimeError( msg )
, BaseException( msg ) {}
};
// ---------------------------------------------------------------------------------------
@ -263,7 +245,7 @@ namespace Exception
// This exception is usually thrown via derived classes, except in the (rare) case of a
// generic / unknown error.
//
class Stream : public RuntimeError
class Stream : public virtual RuntimeError
{
public:
wxString StreamName; // name of the stream (if applicable)
@ -272,19 +254,22 @@ namespace Exception
// copy construct!
Stream( const Stream& src ) :
RuntimeError( src ),
StreamName( src.StreamName ) {}
RuntimeError( src )
, BaseException( src )
, StreamName( src.StreamName ) {}
explicit Stream(
const wxString& objname=wxString(),
const char* msg="General file operation error" // general error while accessing or operating on a file or stream
) :
RuntimeError( msg ),
StreamName( objname ) {}
RuntimeError( msg )
, BaseException( msg )
, StreamName( objname ) {}
explicit Stream( const wxString& objname, const wxString& msg_eng, const wxString& msg_xlt=_("General file operation error") ) :
RuntimeError( msg_eng, msg_xlt ),
StreamName( objname ) {}
RuntimeError( msg_eng, msg_xlt )
, BaseException( msg_eng, msg_xlt )
, StreamName( objname ) {}
virtual wxString LogMessage() const;
virtual wxString DisplayMessage() const;
@ -294,7 +279,7 @@ namespace Exception
// connection, or anything else that would indicate a failure to read the data after the
// stream was successfully opened.
//
class BadStream : public Stream
class BadStream : public virtual Stream
{
public:
virtual ~BadStream() throw() {}
@ -302,12 +287,17 @@ namespace Exception
const wxString& objname=wxString(),
const char* msg=wxLt("File data is corrupted or incomplete, or the stream connection closed unexpectedly")
) :
Stream( objname, msg ) {}
Stream( objname, msg )
, BaseException( msg ) {}
explicit BadStream( const wxString& objname, const wxString& msg_eng, const wxString& msg_xlt ) :
Stream( objname, msg_eng, msg_xlt )
, BaseException( msg_eng, msg_xlt ) {}
};
// A generic exception for odd-ball stream creation errors.
//
class CreateStream : public Stream
class CreateStream : public virtual Stream
{
public:
virtual ~CreateStream() throw() {}
@ -315,55 +305,63 @@ namespace Exception
explicit CreateStream(
const char* objname,
const char* msg=wxLt("File could not be created or opened") ) :
Stream( wxString::FromAscii( objname ), msg ) {}
Stream( wxString::FromAscii( objname ), msg )
, BaseException( msg ) {}
explicit CreateStream(
const wxString& objname=wxString(),
const char* msg=wxLt("File could not be created or opened") ) :
Stream( objname, msg ) {}
Stream( objname, msg )
, BaseException( msg ) {}
explicit CreateStream(
const wxString& objname, const wxString& msg_eng, const wxString& msg_xlt ) :
Stream( objname, msg_eng, msg_xlt ) {}
Stream( objname, msg_eng, msg_xlt )
, BaseException( msg_eng, msg_xlt ) {}
};
// Exception thrown when an attempt to open a non-existent file is made.
// (this exception can also mean file permissions are invalid)
//
class FileNotFound : public CreateStream
class FileNotFound : public virtual CreateStream
{
public:
virtual ~FileNotFound() throw() {}
explicit FileNotFound(
const wxString& objname=wxString(),
const char* msg="File not found" ) :
CreateStream( objname, msg ) {}
explicit FileNotFound( const wxString& objname, const wxString& msg_eng, const wxString& msg_xlt ) :
CreateStream( objname, msg_eng, msg_xlt ) {}
const char* msg="File not found" )
:
CreateStream( objname, msg )
, BaseException( msg ) {}
explicit FileNotFound( const wxString& objname, const wxString& msg_eng, const wxString& msg_xlt ) :
CreateStream( objname, msg_eng, msg_xlt )
, BaseException( msg_eng, msg_xlt ) {}
};
class AccessDenied : public CreateStream
class AccessDenied : public virtual CreateStream
{
public:
virtual ~AccessDenied() throw() {}
explicit AccessDenied(
const wxString& objname=wxString(),
const char* msg="Permission denied to file" ) :
CreateStream( objname, msg ) {}
const char* msg="Permission denied to file" )
:
CreateStream( objname, msg )
, BaseException( msg ) {}
};
// EndOfStream can be used either as an error, or used just as a shortcut for manual
// feof checks.
//
class EndOfStream : public Stream
class EndOfStream : public virtual Stream
{
public:
virtual ~EndOfStream() throw() {}
explicit EndOfStream( const wxString& objname, const char* msg=wxLt("Unexpected end of file") ) :
Stream( objname, msg ) {}
Stream( objname, msg )
, BaseException( msg ) {}
};
// ---------------------------------------------------------------------------------------
@ -374,19 +372,20 @@ namespace Exception
// Exception thrown when a corrupted or truncated savestate is encountered.
//
class BadSavedState : public BadStream
class BadSavedState : public virtual BadStream
{
public:
virtual ~BadSavedState() throw() {}
explicit BadSavedState(
const wxString& objname=wxString(),
const char* msg="Savestate data is corrupted" ) : // or incomplete
BadStream( objname, msg ) {}
BadStream( objname, msg )
, BaseException( msg ) {}
};
// Exception thrown by SaveState class when a critical plugin or gzread
//
class FreezePluginFailure : public RuntimeError
class FreezePluginFailure : public virtual RuntimeError
{
public:
wxString plugin_name; // name of the plugin
@ -396,39 +395,28 @@ namespace Exception
explicit FreezePluginFailure( const char* plugin, const char* action,
const wxString& msg_xlt=_("Plugin error occurred while loading/saving state") )
:
RuntimeError( wxString(), msg_xlt ) // LogMessage / DisplayMessage build their own messages
RuntimeError( wxEmptyString, msg_xlt ) // LogMessage / DisplayMessage build their own messages
, BaseException( wxEmptyString, msg_xlt )
, plugin_name( wxString::FromAscii(plugin) )
, freeze_action( wxString::FromAscii(action) ){}
, freeze_action( wxString::FromAscii(action) ) {}
virtual wxString LogMessage() const;
virtual wxString DisplayMessage() const;
};
// A recoverable error thrown when a savestate load fails prior to actually modifying
// the current emulation state. Recoverable errors are always thrown from the SaveState
// object construction (and never from Freeze methods).
//
class StateLoadError : public RuntimeError
{
public:
virtual ~StateLoadError() throw() {}
explicit StateLoadError( const char* msg="Recoverable savestate load error" ) :
RuntimeError( msg ) {}
};
// A recoverable exception thrown when the savestate being loaded isn't supported.
//
class UnsupportedStateVersion : public StateLoadError
class UnsupportedStateVersion : public virtual BadSavedState
{
public:
u32 Version; // version number of the unsupported state.
public:
virtual ~UnsupportedStateVersion() throw() {}
explicit UnsupportedStateVersion( int version ) :
StateLoadError(),
Version( version )
{}
explicit UnsupportedStateVersion( int version, const wxString& objname=wxEmptyString ) :
BadSavedState( objname )
, BaseException( wxEmptyString, wxEmptyString )
, Version( version ) {}
virtual wxString LogMessage() const;
virtual wxString DisplayMessage() const;
@ -438,7 +426,7 @@ namespace Exception
// CRC returned by the Cdvd driver.
// [feature not implemented yet]
//
class StateCrcMismatch : public StateLoadError
class StateCrcMismatch : public virtual BadSavedState
{
public:
u32 Crc_Savestate;
@ -446,8 +434,9 @@ namespace Exception
public:
virtual ~StateCrcMismatch() throw() {}
explicit StateCrcMismatch( u32 crc_save, u32 crc_cdvd )
: StateLoadError()
explicit StateCrcMismatch( u32 crc_save, u32 crc_cdvd, const wxString& objname=wxEmptyString ) :
BadSavedState( objname )
, BaseException( wxEmptyString, wxEmptyString )
, Crc_Savestate( crc_save )
, Crc_Cdvd( crc_cdvd )
{}

View File

@ -146,6 +146,8 @@ namespace Threading
virtual bool IsRunning() const;
virtual sptr Block();
bool IsSelf() const;
protected:
// Used to dispatch the thread callback function.

View File

@ -83,20 +83,6 @@ namespace Exception
return m_message + L"\n\n" + StreamName;
}
// ------------------------------------------------------------------------
wxString PluginFailure::LogMessage() const
{
return wxsFormat(
L"%s plugin has encountered an error.\n\n",
plugin_name.c_str()
) + m_stacktrace;
}
wxString PluginFailure::DisplayMessage() const
{
return wxsFormat( m_message, plugin_name.c_str() );
}
// ------------------------------------------------------------------------
wxString FreezePluginFailure::LogMessage() const
{
@ -124,7 +110,7 @@ namespace Exception
// m_message contains a recoverable savestate error which is helpful to the user.
return wxsFormat(
m_message + L"\n\n" +
wxsFormat( L"Unknown savestate version: 0x%x", Version )
wxsFormat( _("Cannot load savestate. It is of an unknown or unsupported version."), Version )
);
}

View File

@ -45,6 +45,8 @@ namespace Threading
void PersistentThread::Start()
{
if( m_running ) return;
if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 )
throw Exception::ThreadCreationError();
@ -89,8 +91,13 @@ namespace Threading
pthread_join( m_thread, (void**)&m_returncode );
return m_returncode;
}
bool PersistentThread::IsSelf() const
{
return pthread_self() == m_thread;
}
bool Exists( pthread_t pid )
bool PersistentThread::Exists( pthread_t pid )
{
// passing 0 to pthread_kill is a NOP, and returns the status of the thread only.
return ( ESRCH != pthread_kill( pid, 0 ) );

View File

@ -33,8 +33,7 @@ int IsoFS_getDirectories(TocEntry tocEntry[], int req_entries);
#define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */
#if defined(_MSC_VER)
#pragma pack(1)
#pragma warning(disable:4996) //ignore the stricmp deprecated warning
# pragma pack(1)
#endif
struct rootDirTocHeader

View File

@ -16,8 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __COMMON_H__
#define __COMMON_H__
#pragma once
#include "Pcsx2Defs.h"
@ -42,4 +41,5 @@
#include "Elfheader.h"
#include "Patch.h"
#endif /* __COMMON_H__ */
extern bool EmulationInProgress();

View File

@ -442,16 +442,22 @@ __forceinline void rcntUpdate_vSync()
s32 diff = (cpuRegs.cycle - vsyncCounter.sCycle);
if( diff < vsyncCounter.CycleT ) return;
//iopBranchAction = 1;
if (vsyncCounter.Mode == MODE_VSYNC)
{
eeRecIsReset = false;
CoreEmuThread::Get().StateCheck();
if( eeRecIsReset )
{
eeRecIsReset = false;
cpuSetBranch();
throw Exception::RecompilerReset();
}
VSyncEnd(vsyncCounter.sCycle);
vsyncCounter.sCycle += vSyncInfo.Blank;
vsyncCounter.CycleT = vSyncInfo.Render;
vsyncCounter.Mode = MODE_VRENDER;
CoreEmuThread::Get().StateCheck();
}
else // VSYNC end / VRENDER begin
{

View File

@ -23,10 +23,6 @@
using namespace std;
#ifdef _MSC_VER
#pragma warning(disable:4996) //ignore the stricmp deprecated warning
#endif
u32 ElfCRC;
struct ELF_HEADER {

View File

@ -68,8 +68,6 @@ extern void States_Load( int num );
extern void States_Save( int num );
extern bool States_isSlotUsed(int num);
extern bool g_EmulationInProgress; // Set TRUE if a game is actively running (set to false on reset)
//////////////////////////////////////////////////////////////////////////////////////////
// External Gui APIs (platform specific)
//
@ -87,14 +85,6 @@ extern bool g_EmulationInProgress; // Set TRUE if a game is actively running (se
// as keyboard events, menu/status updates, and cpu execution invocation.
namespace HostGui
{
// Signal for informing the GUI that the saveslot status has been altered.
// The guis hould re-enumerate the slot information displayed in the menu, or wherever.
extern void ResetMenuSlots();
// Signals to the GUI that execution of the emulator should begin. This can be either
// a blocking or non-blocking (threaded) action.
extern void BeginExecution();
// Signals the gui with a keystroke. Handle or discard or dispatch, or enjoy its
// pleasant flavor.
extern void __fastcall KeyEvent( keyEvent* ev );

View File

@ -1088,7 +1088,6 @@ void mtgsWaitGS()
void mtgsOpen()
{
// better not be a thread already running, yo!
assert( mtgsThread == NULL );
if( mtgsThread != NULL ) return;
mtgsThread = new mtgsThreadObject();

View File

@ -73,7 +73,7 @@ void MemoryCard::Load( uint mcd )
if( !fname.FileExists() )
Create( str );
#ifdef WIN32
#ifdef _WIN32
NTFS_CompressFile( str, g_Conf->McdEnableNTFS );
#endif

View File

@ -41,21 +41,13 @@
#include "COP0.h"
#include "Cache.h"
#include "Dump.h"
#include "AppConfig.h"
using namespace std;
using namespace R5900;
static int g_Pcsx2Recording = 0; // true 1 if recording video and sound
// renderswitch - tells GSdx to go into dx9 sw if "renderswitch" is set.
bool renderswitch = false;
struct KeyModifiers keymodifiers = {false, false, false, false};
#define NUM_STATES 10
int StatesC = 0;
extern wxString strgametitle;
@ -245,166 +237,6 @@ char* mystrlwr( char* string )
return string;
}
static wxString GetGSStateFilename()
{
return Path::Combine( g_Conf->Folders.Savestates, wxsFormat( L"/%8.8X.%d.gs", ElfCRC, StatesC ) );
}
void ProcessFKeys(int fkey, struct KeyModifiers *keymod)
{
assert(fkey >= 1 && fkey <= 12 );
switch(fkey)
{
case 1:
try
{
gzSavingState( SaveState::GetFilename( StatesC ) ).FreezeAll();
HostGui::ResetMenuSlots();
}
catch( Exception::BaseException& ex )
{
// 99% of the time this is a file permission error and the
// cpu state is intact so just display a passive msg to console without
// raising an exception.
Console::Error( "Error! Could not save state to slot %d", params StatesC );
Console::Error( ex.LogMessage() );
}
break;
case 2:
if( keymod->shift )
StatesC = (StatesC+NUM_STATES-1) % NUM_STATES;
else
StatesC = (StatesC+1) % NUM_STATES;
Console::Notice( " > Selected savestate slot %d", params StatesC);
if( GSchangeSaveState != NULL )
GSchangeSaveState(StatesC, SaveState::GetFilename(StatesC).mb_str());
break;
case 3:
try
{
gzLoadingState joe( SaveState::GetFilename( StatesC ) ); // throws exception on version mismatch
cpuReset();
SysClearExecutionCache();
joe.FreezeAll();
}
catch( Exception::StateLoadError& )
{
// At this point the cpu hasn't been reset, so we can return
// control to the user safely... (and silently)
}
catch( Exception::FileNotFound& )
{
Console::Notice( "Saveslot %d cannot be loaded; slot does not exist (file not found)", params StatesC );
}
catch( Exception::RuntimeError& ex )
{
// This is the bad one. Chances are the cpu has been reset, so emulation has
// to be aborted. Sorry user! We'll give you some info for your trouble:
ClosePlugins( true );
throw Exception::CpuStateShutdown(
// english log message:
wxsFormat( L"Error! Could not load from saveslot %d\n", StatesC ) + ex.LogMessage(),
// translated message:
wxsFormat( _("Error loading saveslot %d. Emulator reset."), StatesC )
);
}
break;
case 4:
// FIXME : Reimplement framelimiting using new oolean system
//CycleFrameLimit(keymod->shift ? -1 : 1);
break;
// note: VK_F5-VK_F7 are reserved for GS
case 8:
GSmakeSnapshot( g_Conf->Folders.Snapshots.ToAscii().data() );
break;
case 9: //gsdx "on the fly" renderer switching
StateRecovery::MakeGsOnly();
g_EmulationInProgress = false;
// close GS and PAD together, because the PAD depends on the GS window.
g_plugins->Close( PluginId_PAD );
safe_delete( mtgsThread );
renderswitch = !renderswitch;
StateRecovery::Recover();
HostGui::BeginExecution(); // also sets g_EmulationInProgress to true later
break;
#ifdef PCSX2_DEVBUILD
case 10:
// There's likely a better way to implement this, but this seemed useful.
// I might add turning EE, VU0, and VU1 recs on and off by hotkey at some point, too.
// --arcum42
enableLogging = !enableLogging;
if (enableLogging)
GSprintf(10, "Logging Enabled.");
else
GSprintf(10,"Logging Disabled.");
break;
case 11:
Console::Notice( "Cannot make gsstates in MTGS mode" );
// fixme : fix up gsstate mess and make it mtgs compatible -- air
#ifdef _STGS_GSSTATE_CODE
wxString Text;
if( strgametitle[0] != 0 )
{
// only take the first two words
wxString gsText;
wxStringTokenizer parts( strgametitle, L" " );
wxString name( parts.GetNextToken() ); // first part
wxString part2( parts.GetNextToken() );
if( !!part2 )
name += L"_" + part2;
gsText.Printf( L"%s.%d.gs", name.c_str(), StatesC );
Text = Path::Combine( g_Conf->Folders.Savestates, gsText );
}
else
{
Text = GetGSStateFilename();
}
break;
#endif
#endif
case 12:
if( keymod->shift )
{
#ifdef PCSX2_DEVBUILD
iDumpRegisters(cpuRegs.pc, 0);
Console::Notice("hardware registers dumped EE:%x, IOP:%x\n", params cpuRegs.pc, psxRegs.pc);
#endif
}
else
{
g_Pcsx2Recording ^= 1;
mtgsThread->SendSimplePacket(GS_RINGTYPE_RECORD, g_Pcsx2Recording, 0, 0);
if( SPU2setupRecording != NULL ) SPU2setupRecording(g_Pcsx2Recording, NULL);
}
break;
}
}
void _memset16_unaligned( void* dest, u16 data, size_t size )
{
jASSUME( (size & 0x1) == 0 );

View File

@ -37,9 +37,6 @@ extern int GetPS2ElfName( wxString& dest ); // Used in Misc, System, Linux, CDVD
void SetCPUState(u32 sseMXCSR, u32 sseVUMXCSR);
extern u32 g_sseVUMXCSR, g_sseMXCSR;
// Used in Misc,and Windows/Linux files.
extern void ProcessFKeys(int fkey, struct KeyModifiers *keymod); // processes fkey related commands value 1-12
void SaveGSState(const wxString& file);
void LoadGSState(const wxString& file);

View File

@ -27,10 +27,6 @@
#include "Patch.h"
#include "VU.h"
#ifdef _MSC_VER
#pragma warning(disable:4996) //ignore the stricmp deprecated warning
#endif
IniPatch patch[ MAX_PATCH ];
u32 SkipCount=0, IterationCount=0;

View File

@ -17,7 +17,6 @@
*/
#include "PrecompiledHeader.h"
#include "Utilities/RedtapeWindows.h"
#include "Utilities/ScopedPtr.h"
#include <wx/dir.h>
@ -27,7 +26,6 @@
#include "GS.h"
#include "HostGui.h"
#include "CDVD/CDVDisoReader.h"
#include "AppConfig.h"
// ----------------------------------------------------------------------------
// Yay, order of this array shouldn't be important. :)
@ -49,24 +47,6 @@ const PluginInfo tbl_PluginInfo[] =
};
int EnumeratePluginsInFolder( const wxDirName& searchpath, wxArrayString* dest )
{
wxScopedPtr<wxArrayString> placebo;
wxArrayString* realdest = dest;
if( realdest == NULL )
placebo.reset( realdest = new wxArrayString() );
#ifdef _WIN32
return searchpath.Exists() ?
wxDir::GetAllFiles( searchpath.ToString(), realdest, wxsFormat( L"*%s", wxDynamicLibrary::GetDllExt()), wxDIR_FILES ) : 0;
#else
return searchpath.Exists() ?
wxDir::GetAllFiles( searchpath.ToString(), realdest, wxsFormat( L"*%s*", wxDynamicLibrary::GetDllExt()), wxDIR_FILES ) : 0;
#endif
}
typedef void CALLBACK VoidMethod();
typedef void CALLBACK vMeth(); // shorthand for VoidMethod
@ -166,21 +146,7 @@ _PADkeyEvent PADkeyEvent;
_PADsetSlot PADsetSlot;
_PADqueryMtap PADqueryMtap;
void PAD_update( u32 padslot ) { }
// SIO[2]
/*
_SIOinit SIOinit[2][9];
_SIOopen SIOopen[2][9];
_SIOclose SIOclose[2][9];
_SIOshutdown SIOshutdown[2][9];
_SIOstartPoll SIOstartPoll[2][9];
_SIOpoll SIOpoll[2][9];
_SIOquery SIOquery[2][9];
_SIOconfigure SIOconfigure[2][9];
_SIOtest SIOtest[2][9];
_SIOabout SIOabout[2][9];*/
static void PAD_update( u32 padslot ) { }
// SPU2
_SPU2open SPU2open;
@ -559,12 +525,35 @@ static const LegacyApi_OptMethod* const s_MethMessOpt[] =
PluginManager *g_plugins = NULL;
Exception::NotPcsxPlugin::NotPcsxPlugin( const wxString& objname ) :
Stream( objname, wxLt("File is not a PCSX2 plugin") ) {}
//////////////////////////////////////////////////////////////////////////////////////////
Exception::NotPcsxPlugin::NotPcsxPlugin( const PluginsEnum_t& pid ) :
Stream( wxString::FromUTF8( tbl_PluginInfo[pid].shortname ), wxLt("File is not a PCSX2 plugin") ) {}
Exception::InvalidPluginConfigured::InvalidPluginConfigured( const PluginsEnum_t& pid, const wxString& objname, const char* eng ) :
BadStream( objname, eng )
, PluginError( pid )
, BaseException( eng )
{}
Exception::InvalidPluginConfigured::InvalidPluginConfigured( const PluginsEnum_t& pid, const wxString& objname,
const wxString& eng_msg, const wxString& xlt_msg ) :
BadStream( objname, eng_msg, xlt_msg )
, PluginError( pid )
, BaseException( eng_msg, xlt_msg )
{}
wxString Exception::PluginFailure::LogMessage() const
{
return wxsFormat(
L"%s plugin has encountered an error.\n\n",
plugin_name.c_str()
) + m_stacktrace;
}
wxString Exception::PluginFailure::DisplayMessage() const
{
return wxsFormat( m_message, plugin_name.c_str() );
}
//////////////////////////////////////////////////////////////////////////////////////////
PluginManager::PluginManager( const wxString (&folders)[PluginId_Count] )
{
@ -574,15 +563,20 @@ PluginManager::PluginManager( const wxString (&folders)[PluginId_Count] )
const PluginsEnum_t pid = pi->id;
if( folders[pid].IsEmpty() )
throw Exception::InvalidArgument( "Invalid argument in PluginManager::ctor: Empty plugin filename." );
throw Exception::InvalidArgument( "Empty plugin filename." );
m_info[pid].Filename = folders[pid];
if( !wxFile::Exists( folders[pid] ) )
throw Exception::FileNotFound( folders[pid] );
throw Exception::InvalidPluginConfigured( pid, folders[pid],
L"Plugin file not found",
_("The configured plugin file was not found")
);
if( !m_info[pid].Lib.Load( folders[pid] ) )
throw Exception::NotPcsxPlugin( folders[pid] );
throw Exception::InvalidPluginConfigured( pid, folders[pid],
wxLt("Configured plugin file is not a valid dynamic library")
);
// Try to enumerate the new v2.0 plugin interface first.
// If that fails, fall back on the old style interface.
@ -599,7 +593,7 @@ PluginManager::PluginManager( const wxString (&folders)[PluginId_Count] )
// Bind Optional Functions
// (leave pointer null and do not generate error)
}
// Hack for PAD's stupid parameter passed on Init
PADinit = (_PADinit)m_info[PluginId_PAD].CommonBindings.Init;
m_info[PluginId_PAD].CommonBindings.Init = _hack_PADinit;
@ -609,7 +603,7 @@ PluginManager::~PluginManager()
{
Close();
Shutdown();
// All library unloading done automatically.
}
@ -623,13 +617,16 @@ void PluginManager::BindCommon( PluginsEnum_t pid )
while( current->MethodName != NULL )
{
*target = (VoidMethod*)m_info[pid].Lib.GetSymbol( current->GetMethodName( pid ) );
if( *target == NULL )
*target = current->Fallback;
if( *target == NULL )
throw Exception::NotPcsxPlugin( pid );
{
throw Exception::InvalidPluginConfigured( pid, m_info[pid].Filename,
wxLt( "Configured plugin is not a valid PCSX2 plugin, or is for an older unsupported version of PCSX2." ) );
}
target++;
current++;
}
@ -650,7 +647,10 @@ void PluginManager::BindRequired( PluginsEnum_t pid )
*(current->Dest) = current->Fallback;
if( *(current->Dest) == NULL )
throw Exception::NotPcsxPlugin( pid );
{
throw Exception::InvalidPluginConfigured( pid, m_info[pid].Filename,
wxLt( "Configured plugin is not a valid PCSX2 plugin, or is for an older unsupported version of PCSX2." ) );
}
current++;
}
@ -688,8 +688,18 @@ static bool OpenPlugin_CDVD()
static bool OpenPlugin_GS()
{
// Abusing the isMultiThread parameter for that so we don't need a new callback
return !GSopen( (void*)&pDsp, "PCSX2", renderswitch ? 2 : 1 );
if( !mtgsThread->IsSelf() )
{
if( mtgsThread == NULL )
mtgsOpen(); // mtgsOpen raises its own exception on error
return true;
}
else
return !GSopen( (void*)&pDsp, "PCSX2", renderswitch ? 2 : 1 );
// Note: rederswitch is us abusing the isMultiThread parameter for that so
// we don't need a new callback
}
static bool OpenPlugin_PAD()
@ -739,7 +749,7 @@ static bool OpenPlugin_FW()
void PluginManager::Open( PluginsEnum_t pid )
{
if( m_info[pid].IsOpened ) return;
// Each Open needs to be called explicitly. >_<
bool result = true;
@ -759,19 +769,44 @@ void PluginManager::Open( PluginsEnum_t pid )
m_info[pid].IsOpened = true;
}
void PluginManager::Open()
{
const PluginInfo* pi = tbl_PluginInfo-1;
while( ++pi, pi->shortname != NULL )
g_plugins->Open( pi->id );
}
void PluginManager::Close( PluginsEnum_t pid )
{
if( !m_info[pid].IsOpened ) return;
if( pid == PluginId_GS )
{
if( mtgsThread == NULL ) return;
if( !mtgsThread->IsSelf() )
{
// force-close PAD before GS, because the PAD depends on the GS window.
Close( PluginId_PAD );
safe_delete( mtgsThread );
return;
}
}
m_info[pid].IsOpened = false;
m_info[pid].CommonBindings.Close();
}
void PluginManager::Close()
void PluginManager::Close( bool closegs )
{
const PluginInfo* pi = tbl_PluginInfo-1;
while( ++pi, pi->shortname != NULL )
Close( pi->id );
// Close plugins in reverse order of the initialization procedure.
for( int i=PluginId_Count-1; i>=0; --i )
{
if( closegs || (tbl_PluginInfo[i].id != PluginId_GS) )
Close( tbl_PluginInfo[i].id );
}
}
// Initializes all plugins. Plugin initialization should be done once for every new emulation
@ -806,10 +841,12 @@ void PluginManager::Shutdown()
{
Close();
const PluginInfo* pi = tbl_PluginInfo-1;
while( ++pi, pi->shortname != NULL )
// Shutdown plugins in reverse order (probably doesn't matter...
// ... but what the heck, right?)
for( int i=PluginId_Count-1; i>=0; --i )
{
const PluginsEnum_t pid = pi->id;
const PluginsEnum_t pid = tbl_PluginInfo[i].id;
if( !m_info[pid].IsInitialized ) continue;
m_info[pid].IsInitialized = false;
m_info[pid].CommonBindings.Shutdown();
@ -869,7 +906,7 @@ PluginManager* PluginManager_Create( const wxString (&folders)[PluginId_Count] )
PluginManager* PluginManager_Create( const wxChar* (&folders)[PluginId_Count] )
{
wxString passins[PluginId_Count];
const PluginInfo* pi = tbl_PluginInfo-1;
while( ++pi, pi->shortname != NULL )
passins[pi->id] = folders[pi->id];
@ -877,305 +914,12 @@ PluginManager* PluginManager_Create( const wxChar* (&folders)[PluginId_Count] )
return PluginManager_Create( passins );
}
void LoadPlugins()
static PluginManagerBase s_pluginman_placebo;
// retrieves a handle to the current plugin manager. Plugin manager is assumed to be valid,
// and debug-level assertions are performed on the validity of the handle.
PluginManagerBase& GetPluginManager()
{
wxString passins[PluginId_Count];
const PluginInfo* pi = tbl_PluginInfo-1;
while( ++pi, pi->shortname != NULL )
passins[pi->id] = g_Conf->FullpathTo( pi->id );
g_plugins = PluginManager_Create( passins );
if( g_plugins == NULL ) return s_pluginman_placebo;
return *g_plugins;
}
void InitPlugins()
{
if( g_plugins == NULL )
LoadPlugins();
g_plugins->Init();
}
// All plugins except the CDVD are opened here. The CDVD must be opened manually by
// the GUI, depending on the user's menu/config in use.
//
// Exceptions:
// PluginFailure - if any plugin fails to initialize or open.
// ThreadCreationError - If the MTGS thread fails to be created.
//
void OpenPlugins()
{
if( g_plugins == NULL )
InitPlugins();
mtgsOpen();
const PluginInfo* pi = tbl_PluginInfo-1;
while( ++pi, pi->shortname != NULL )
g_plugins->Open( pi->id );
}
void ClosePlugins( bool closegs )
{
if( g_plugins == NULL ) return;
safe_delete( mtgsThread );
const PluginInfo* pi = tbl_PluginInfo-1;
while( ++pi, pi->shortname != NULL )
g_plugins->Close( pi->id );
}
void ShutdownPlugins()
{
if( g_plugins == NULL ) return;
ClosePlugins( true );
g_plugins->Shutdown();
}
void ReleasePlugins()
{
safe_delete( g_plugins );
}
#ifdef _not_wxWidgets_Land_
bool OpenGS()
{
GSdriverInfo info;
if (!OpenStatus.GS)
{
if (ReportError2(gsOpen(), "GS"))
{
ClosePlugins(true);
return false;
}
//Get the user input.
if (GSgetDriverInfo)
{
GSgetDriverInfo(&info);
if (PAD1gsDriverInfo) PAD1gsDriverInfo(&info);
if (PAD2gsDriverInfo) PAD2gsDriverInfo(&info);
}
OpenStatus.GS = true;
}
return true;
}
bool OpenCDVD( const char* pTitleFilename )
{
// if this assertion fails it means you didn't call CDVDsys_ChangeSource. You should.
// You really should. Really.
jASSUME( CDVD != NULL );
// Don't repetitively open the CDVD plugin if directly loading an elf file and open failed once already.
if (!OpenStatus.CDVD)
{
CDVD->newDiskCB( cdvdNewDiskCB );
if( (pTitleFilename == NULL) && !cdvd_FileNameParam.IsEmpty() )
pTitleFilename = cdvd_FileNameParam.c_str();
if (DoCDVDopen(pTitleFilename) != 0)
{
Msgbox::Alert("Error Opening CDVD Plugin");
ClosePlugins(true);
return false;
}
if( cdvd_FileNameParam.IsEmpty() && (pTitleFilename != NULL) )
cdvd_FileNameParam = pTitleFilename;
OpenStatus.CDVD = true;
}
return true;
}
bool OpenPAD1()
{
if (!OpenStatus.PAD1)
{
if (ReportError2(PAD1open((void *)&pDsp), "PAD1"))
{
ClosePlugins(true);
return false;
}
OpenStatus.PAD1 = true;
}
return true;
}
bool OpenPAD2()
{
if (!OpenStatus.PAD2)
{
if (ReportError2(PAD2open((void *)&pDsp), "PAD2"))
{
ClosePlugins(true);
return false;
}
OpenStatus.PAD2 = true;
}
return true;
}
bool OpenSPU2()
{
if (!OpenStatus.SPU2)
{
SPU2irqCallback(spu2Irq,spu2DMA4Irq,spu2DMA7Irq);
if (SPU2setDMABaseAddr != NULL) SPU2setDMABaseAddr((uptr)psxM);
if (SPU2setClockPtr != NULL) SPU2setClockPtr(&psxRegs.cycle);
if (ReportError2(SPU2open((void*)&pDsp), "SPU2"))
{
ClosePlugins(true);
return false;
}
OpenStatus.SPU2 = true;
}
return true;
}
bool OpenDEV9()
{
if (!OpenStatus.DEV9)
{
DEV9irqCallback(dev9Irq);
dev9Handler = DEV9irqHandler();
if (ReportError2(DEV9open(&psxRegs.pc)/*((void *)&pDsp)*/, "DEV9"))
{
ClosePlugins(true);
return false;
}
OpenStatus.DEV9 = true;
}
return true;
}
bool OpenUSB()
{
if (!OpenStatus.USB)
{
USBirqCallback(usbIrq);
usbHandler = USBirqHandler();
USBsetRAM(psxM);
if (ReportError2(USBopen((void *)&pDsp), "USB"))
{
ClosePlugins(true);
return false;
}
OpenStatus.USB = true;
}
return true;
}
bool OpenFW()
{
if (!OpenStatus.FW)
{
FWirqCallback(fwIrq);
if (ReportError2(FWopen((void *)&pDsp), "FW"))
{
ClosePlugins(true);
return false;
}
OpenStatus.FW = true;
}
return true;
}
// Note: If the CDVD has not already been manually opened, then it will be opened here
// using NULL as the source file (defaults to whatever's been previously configured into
// the CDVD plugin, which is typically a drive letter)
int OpenPlugins()
{
if( InitPlugins() == -1 ) return -1;
if( !OpenGS() || !OpenPAD1() || !OpenPAD2() || !OpenCDVD(NULL) ||
!OpenSPU2() || !OpenDEV9() || !OpenUSB() || !OpenFW()
)
return -1;
cdvdDetectDisk();
return 0;
}
#define CLOSE_PLUGIN( name ) \
if( OpenStatus.name ) { \
name##close(); \
OpenStatus.name = false; \
}
#define CLOSE_PLUGIN2( name ) \
if( OpenStatus.name ) { \
name.close(); \
OpenStatus.name = false; \
}
void ClosePlugins( bool closegs )
{
// Close pads first since they attach to the GS's window.
CLOSE_PLUGIN( PAD1 );
CLOSE_PLUGIN( PAD2 );
// GS plugin is special and is not always closed during emulation pauses.
// (that's because the GS is the most complicated plugin and to close it would
// require we save the GS state)
if( OpenStatus.GS )
{
if( closegs )
{
gsClose();
OpenStatus.GS = false;
}
else
{
mtgsWaitGS();
}
}
CloseCDVD();
if( OpenStatus.CDVD )
{
DoCDVDclose();
OpenStatus.CDVD = false;
}
CLOSE_PLUGIN( DEV9 );
CLOSE_PLUGIN( USB );
CLOSE_PLUGIN( FW );
CLOSE_PLUGIN( SPU2 );
}
void PluginsResetGS()
{
// PADs are tied to the GS window, so shut them down together with the GS.
CLOSE_PLUGIN( PAD1 );
CLOSE_PLUGIN( PAD2 );
if( OpenStatus.GS )
{
gsClose();
OpenStatus.GS = false;
}
GSshutdown();
int ret = GSinit();
if (ret != 0) { Msgbox::Alert("GSinit error: %d", params ret); }
}
#endif

View File

@ -39,12 +39,45 @@ struct PluginInfo
namespace Exception
{
class NotPcsxPlugin : public Stream
class PluginError : public virtual RuntimeError
{
public:
virtual ~NotPcsxPlugin() throw() {}
explicit NotPcsxPlugin( const wxString& objname );
explicit NotPcsxPlugin( const PluginsEnum_t& pid );
const PluginsEnum_t PluginId;
public:
PluginError( PluginsEnum_t pid ) :
RuntimeError( "Generic plugin error" )
, BaseException( "Generic plugin error" )
, PluginId( pid )
{
}
};
class PluginFailure : public virtual RuntimeError
{
public:
wxString plugin_name; // name of the plugin
virtual ~PluginFailure() throw() {}
explicit PluginFailure( const char* plugin, const char* msg="%s plugin encountered a critical error" ) :
RuntimeError( msg )
, BaseException( msg )
, plugin_name( wxString::FromAscii(plugin) ) {}
virtual wxString LogMessage() const;
virtual wxString DisplayMessage() const;
};
class InvalidPluginConfigured : public virtual PluginError, public virtual BadStream
{
public:
virtual ~InvalidPluginConfigured() throw() {}
explicit InvalidPluginConfigured( const PluginsEnum_t& pid, const wxString& objname,
const char* eng );
explicit InvalidPluginConfigured( const PluginsEnum_t& pid, const wxString& objname,
const wxString& eng_msg, const wxString& xlt_msg );
};
};
@ -80,8 +113,40 @@ struct LegacyPluginAPI_Common
class SaveState;
//////////////////////////////////////////////////////////////////////////////////////////
// IPluginManager
// Provides a basic placebo "do-nothing" interface for plugin management. This is used
// to avoid NULL pointer exceptions/segfaults when referencing the plugin manager global
// handle.
//
class PluginManager
// Note: The Init and Freeze methods of this class will cause debug assertions, but Close
// methods fail silently, on the premise that Close and Shutdown are typically run from
// exception handlers or cleanup code, and null pointers should be silently ignored in
// favor of continuing cleanup.
//
class PluginManagerBase
{
DeclareNoncopyableObject( PluginManagerBase )
public:
PluginManagerBase() {}
virtual ~PluginManagerBase() {}
virtual void Init() { wxASSERT_MSG( false, L"Null PluginManager!" ); }
virtual void Shutdown() {}
virtual void Open() { }
virtual void Open( PluginsEnum_t pid ) { wxASSERT_MSG( false, L"Null PluginManager!" ); }
virtual void Close( PluginsEnum_t pid ) {}
virtual void Close( bool closegs=true ) {}
virtual void Freeze( PluginsEnum_t pid, int mode, freezeData* data ) { wxASSERT_MSG( false, L"Null PluginManager!" ); }
virtual void Freeze( PluginsEnum_t pid, SaveState& state ) { wxASSERT_MSG( false, L"Null PluginManager!" ); }
virtual void Freeze( SaveState& state ) { wxASSERT_MSG( false, L"Null PluginManager!" ); }
};
//////////////////////////////////////////////////////////////////////////////////////////
//
class PluginManager : public PluginManagerBase
{
DeclareNoncopyableObject( PluginManager )
@ -110,13 +175,14 @@ protected:
PluginStatus_t m_info[PluginId_Count];
public:
~PluginManager();
virtual ~PluginManager();
void Init();
void Shutdown();
void Open();
void Open( PluginsEnum_t pid );
void Close( PluginsEnum_t pid );
void Close();
void Close( bool closegs=true );
void Freeze( PluginsEnum_t pid, int mode, freezeData* data );
void Freeze( PluginsEnum_t pid, SaveState& state );
@ -137,15 +203,8 @@ protected:
extern const PluginInfo tbl_PluginInfo[];
extern PluginManager* g_plugins;
extern int EnumeratePluginsInFolder( const wxDirName& searchPath, wxArrayString* dest );
extern PluginManager* PluginManager_Create( const wxString (&folders)[PluginId_Count] );
extern PluginManager* PluginManager_Create( const wxChar* (&folders)[PluginId_Count] );
extern void LoadPlugins();
extern void ReleasePlugins();
extern void InitPlugins();
extern void ShutdownPlugins();
extern void OpenPlugins();
extern void ClosePlugins( bool closegs );
extern PluginManagerBase& GetPluginManager();

View File

@ -3,6 +3,12 @@
//#pragma once // no dice, causes problems in GCC PCH (which doesn't really work very well
// Disable some pointless warnings...
#ifdef _MSC_VER
# pragma warning(disable:4250) //'class' inherits 'method' via dominance
# pragma warning(disable:4996) //ignore the stricmp deprecated warning
#endif
//////////////////////////////////////////////////////////////////////////////////////////
// Define PCSX2's own i18n helpers. These override the wxWidgets helpers and provide
// additional functionality.

View File

@ -69,7 +69,6 @@ void psxReset()
void psxShutdown() {
psxBiosShutdown();
psxSIOShutdown();
//psxCpu->Shutdown();
}

View File

@ -89,16 +89,6 @@ void cpuReset()
psxReset();
}
void cpuShutdown()
{
mtgsWaitGS();
hwShutdown();
// biosShutdown();
psxShutdown();
disR5900FreeSyms();
}
__releaseinline void cpuException(u32 code, u32 bd)
{
cpuRegs.branch = 0; // Tells the interpreter that an exception occurred during a branch.
@ -367,14 +357,10 @@ __forceinline void _cpuBranchTest_Shared()
eeEventTestIsActive = true;
g_nextBranchCycle = cpuRegs.cycle + eeWaitCycles;
EEsCycle += cpuRegs.cycle - EEoCycle;
EEoCycle = cpuRegs.cycle;
if( EEsCycle > 0 )
iopBranchAction = true;
// ---- Counters -------------
rcntUpdate_hScanline();
// Important: the vsync counter must be the first to be checked. It includes emulation
// escape/suspend hooks, and it's really a good idea to suspend/resume emulation before
// doing any actual meaninful branchtest logic.
if( cpuTestCycle( nextsCounter, nextCounter ) )
{
@ -382,6 +368,8 @@ __forceinline void _cpuBranchTest_Shared()
_cpuTestPERF();
}
rcntUpdate_hScanline();
_cpuTestTIMR();
// ---- Interrupts -------------
@ -399,6 +387,12 @@ __forceinline void _cpuBranchTest_Shared()
// * The IOP cannot always be run. If we run IOP code every time through the
// cpuBranchTest, the IOP generally starts to run way ahead of the EE.
EEsCycle += cpuRegs.cycle - EEoCycle;
EEoCycle = cpuRegs.cycle;
if( EEsCycle > 0 )
iopBranchAction = true;
psxBranchTest();
if( iopBranchAction )

View File

@ -16,11 +16,33 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __R5900_H__
#define __R5900_H__
#pragma once
//////////////////////////////////////////////////////////////////////////////////////////
#pragma region Recompiler Stuffs
// This code section contains recompiler vars that are used in "shared" code. Placing
// them in iR5900.h would mean having to include that into more files than I care to
// right now, so we're sticking them here for now until a better solution comes along.
extern bool g_EEFreezeRegs;
extern bool g_ExecBiosHack;
extern volatile bool eeRecIsReset;
namespace Exception
{
// Implementation Note: this exception has no meaningful type information and we don't
// care to have it be caught by any BaseException handlers lying about, so let's not
// derive from BaseException :D
class RecompilerReset
{
public:
explicit RecompilerReset() { }
};
}
#pragma endregion
//////////////////////////////////////////////////////////////////////////////////////////
// EE Bios function name tables.
namespace R5900 {
extern const char* const bios[256];
@ -28,7 +50,6 @@ extern const char* const bios[256];
extern s32 EEsCycle;
extern u32 EEoCycle;
extern bool g_ExecBiosHack;
union GPR_reg { // Declare union type GPR register
u64 UD[2]; //128 bits
@ -254,7 +275,6 @@ extern R5900cpu recCpu;
extern void cpuInit();
extern void cpuReset(); // can throw Exception::FileNotFound.
extern void cpuShutdown();
extern void cpuExecuteBios();
extern void cpuException(u32 code, u32 bd);
extern void cpuTlbMissR(u32 addr, u32 bd);
@ -295,5 +315,3 @@ extern void cpuTestTIMRInts();
#define EXC_CODE_WATCH EXC_CODE(23)
#define EXC_CODE__MASK 0x0000007c
#define EXC_CODE__SHIFT 2
#endif /* __R5900_H__ */

View File

@ -30,7 +30,7 @@ namespace R5900Exception
// Translation note: EE Emulation exceptions are untranslated only. There's really no
// point in providing translations for this hardcore mess. :)
//
class BaseExcept : public Ps2Generic
class BaseExcept : public virtual Ps2Generic
{
public:
const cpuRegisters cpuState;
@ -39,8 +39,8 @@ namespace R5900Exception
virtual ~BaseExcept() throw()=0;
explicit BaseExcept( const wxString& msg ) :
Exception::Ps2Generic( L"(EE) " + msg ),
cpuState( cpuRegs )
Ps2Generic( L"(EE) " + msg )
, cpuState( cpuRegs )
{
}
@ -103,18 +103,6 @@ namespace R5900Exception
{}
};
//////////////////////////////////////////////////////////////////////////////////
//
class SystemCall : public BaseExcept
{
public:
virtual ~SystemCall() throw() {}
explicit SystemCall() :
BaseExcept( L"SystemCall [SYSCALL]" )
{}
};
//////////////////////////////////////////////////////////////////////////////////
//
class Trap : public BaseExcept
@ -139,30 +127,6 @@ namespace R5900Exception
{}
};
//////////////////////////////////////////////////////////////////////////////////
//
class Break : public BaseExcept
{
public:
virtual ~Break() throw() {}
explicit Break() :
BaseExcept( L"Break Instruction" )
{}
};
//////////////////////////////////////////////////////////////////////////////////
//
class Overflow : public BaseExcept
{
public:
virtual ~Overflow() throw() {}
explicit Overflow() :
BaseExcept( L"Overflow" )
{}
};
//////////////////////////////////////////////////////////////////////////////////
//
class DebugBreakpoint : public BaseExcept

View File

@ -34,12 +34,12 @@ static __forceinline s64 _add64_Overflow( s64 x, s64 y )
// other method below is like 5-10 times slower).
if( ((~(x^y))&(x^result)) < 0 )
throw R5900Exception::Overflow();
cpuException(0x30, cpuRegs.branch); // fixme: is 0x30 right for overflow??
// the not-as-fast style!
//if( ((x >= 0) && (y >= 0) && (result < 0)) ||
// ((x < 0) && (y < 0) && (result >= 0)) )
// throw R5900Exception::Overflow();
// cpuException(0x30, cpuRegs.branch);
return result;
}
@ -54,7 +54,7 @@ static __forceinline s64 _add32_Overflow( s32 x, s32 y )
// If bit32 != bit31 then we have an overflow.
if( (result.UL[0]>>31) != (result.UL[1] & 1) )
throw R5900Exception::Overflow();
cpuException(0x30, cpuRegs.branch);
return result.SD[0];
}

View File

@ -19,6 +19,7 @@
#include "PrecompiledHeader.h"
#include "Common.h"
#include "ps2/CoreEmuThread.h"
#include "HostGui.h"
@ -79,8 +80,8 @@ namespace StateRecovery {
void Recover()
{
// Just in case they weren't initialized earlier (no harm in calling this multiple times)
OpenPlugins();
wxASSERT( g_EmuThread != NULL );
wxASSERT( g_EmuThread->IsSelf() );
if( g_RecoveryState != NULL )
{
@ -99,9 +100,7 @@ namespace StateRecovery {
}
StateRecovery::Clear();
// this needs to be called for every new game!
// (note: sometimes launching games through bios will give a crc of 0)
SysClearExecutionCache();
if( GSsetGameCRC != NULL )
GSsetGameCRC(ElfCRC, g_ZeroGSOptions);
@ -111,37 +110,35 @@ namespace StateRecovery {
// (if one exists) and no recovery data was found. This is needed because when a recovery
// state is made, the emulation state is usually reset so the only persisting state is
// the one in the memory save. :)
//
// Threading Notes:
// This function can be invoked by any thread. However, if it is run outside the context
// of a CoreEmuThred then it
void SaveToFile( const wxString& file )
{
SysSuspend();
if( g_RecoveryState == NULL )
{
RecoveryMemSavingState().FreezeAll();
}
SysResume();
if( g_RecoveryState != NULL )
{
// State is already saved into memory, and the emulator (and in-progress flag)
// have likely been cleared out. So save from the Recovery buffer instead of
// doing a "standard" save:
gzFile fileptr = gzopen( file.ToAscii().data(), "wb" );
if( fileptr == NULL )
{
Msgbox::Alert( wxsFormat( _("Error while trying to save to file: %s"), file.c_str() ) );
return;
}
throw Exception::CreateStream( file, "General savestate file creation error." );
gzwrite( fileptr, &g_SaveVersion, sizeof( u32 ) );
gzwrite( fileptr, g_RecoveryState->GetPtr(), g_RecoveryState->GetSizeInBytes() );
gzclose( fileptr );
}
else if( g_gsRecoveryState != NULL )
{
RecoveryZipSavingState( file ).FreezeAll();
}
else
{
if( !g_EmulationInProgress )
{
Msgbox::Alert( _("No emulation state to save") ); // translate: You need to start a game first before you can save it's state
return;
}
States_Save( file );
if( !EmulationInProgress() ) return;
RecoveryZipSavingState( file ).FreezeAll();
}
}
@ -161,8 +158,7 @@ namespace StateRecovery {
void MakeGsOnly()
{
StateRecovery::Clear();
if( !g_EmulationInProgress ) return;
if( !EmulationInProgress() ) return;
g_gsRecoveryState = new SafeArray<u8>();
JustGsSavingState eddie;
@ -172,23 +168,28 @@ namespace StateRecovery {
// Creates a full recovery of the entire emulation state (CPU and all plugins).
// If a current recovery state is already present, then nothing is done (the
// existing recovery state takes precedence).
// existing recovery state takes precedence since if it were out-of-date it'd be
// deleted!).
void MakeFull()
{
if( g_RecoveryState != NULL ) return;
if( !EmulationInProgress() ) return;
SysSuspend();
try
{
g_RecoveryState = new SafeArray<u8>( L"Memory Savestate Recovery" );
RecoveryMemSavingState().FreezeAll();
safe_delete( g_gsRecoveryState );
g_EmulationInProgress = false;
}
catch( Exception::RuntimeError& ex )
{
Msgbox::Alert( wxsFormat( // fixme: this error needs proper translation stuffs.
L"Pcsx2 gamestate recovery failed. Some options may have been reverted to protect your game's state.\n"
L"Error: %s", ex.DisplayMessage().c_str() )
Msgbox::Alert( wxsFormat( // fixme: needs proper translation
L"PCSX2 encountered an error while trying to backup/suspend the PS2 VirtualMachine state. "
L"You may resume emulation without losing any data, however the machine state will not be "
L"able to recover if you make changes to your PCSX2 configuration.\n\n"
L"Details: %s", ex.DisplayMessage().c_str() )
);
safe_delete( g_RecoveryState );
}

View File

@ -80,16 +80,11 @@ void sioInit()
// Transfer(?) Ready and the Buffer is Empty
sio.StatReg = TX_RDY | TX_EMPTY;
sio.packetsize = 0;
sio.terminator =0x55; // Command terminator 'U'
sio.terminator = 0x55; // Command terminator 'U'
MemoryCard::Init();
}
void psxSIOShutdown()
{
MemoryCard::Shutdown();
}
u8 sioRead8() {
u8 ret = 0xFF;
@ -597,7 +592,7 @@ void InitializeSIO(u8 value)
if( sio.activeMemcardSlot[mcidx] != 0 )
{
// Might want to more agressively declare a card's non-existence here.
// Might want to more aggressively declare a card's non-existence here.
// As non-zero slots always report a failure, and have to read
// the FAT before writing, think this should be fine.
sio2.packet.recvVal1 = 0x1D100;
@ -607,7 +602,7 @@ void InitializeSIO(u8 value)
{
m_PostSavestateCards[mcidx]--;
sio2.packet.recvVal1 = 0x1D100;
PAD_LOG( "START MEMCARD[%d] - post-savestate ejection - reported as missing!", sio.GetMemcardIndex() );
PAD_LOG( "START MEMCARD[%d] - post-savestate ejection - reporting as missing!", sio.GetMemcardIndex() );
}
else
{

View File

@ -60,8 +60,6 @@ struct _sio {
extern _sio sio;
extern void sioInit();
extern void sioShutdown();
extern void psxSIOShutdown();
extern u8 sioRead8();
extern void sioWrite8(u8 value);
extern void sioWriteCtrl16(u16 value);

View File

@ -18,9 +18,9 @@
#include "PrecompiledHeader.h"
#include "Common.h"
#include "HostGui.h"
#include "Common.h"
#include "VUmicro.h"
#include "iR5900.h"
#include "R3000A.h"
@ -30,13 +30,15 @@
#include "R5900Exceptions.h"
#include "CDVD/CDVD.h"
#include "ps2/CoreEmuThread.h"
using namespace std;
Pcsx2Config EmuConfig;
// disable all session overrides by default...
SessionOverrideFlags g_Session = {false};
SessionOverrideFlags g_Session = {false};
CoreEmuThread* g_EmuThread;
bool sysInitialized = false;
@ -230,10 +232,9 @@ void SysAllocateDynarecs()
//////////////////////////////////////////////////////////////////////////////////////////
// This should be called last thing before Pcsx2 exits.
//
void SysShutdownMem()
{
cpuShutdown();
vuMicroMemShutdown();
psxMemShutdown();
memShutdown();
@ -254,9 +255,6 @@ void SysShutdownDynarecs()
}
bool g_ReturnToGui = false; // set to exit the execution of the emulator and return control to the GUI
bool g_EmulationInProgress = false; // Set TRUE if a game is actively running (set to false on reset)
//////////////////////////////////////////////////////////////////////////////////////////
// Resets all PS2 cpu execution caches, which does not affect that actual PS2 state/condition.
// This can be called at any time outside the context of a Cpu->Execute() block without
@ -265,16 +263,8 @@ bool g_EmulationInProgress = false; // Set TRUE if a game is actively running (s
// Use this method to reset the recs when important global pointers like the MTGS are re-assigned.
void SysClearExecutionCache()
{
if( CHECK_EEREC )
{
Cpu = &recCpu;
psxCpu = &psxRec;
}
else
{
Cpu = &intCpu;
psxCpu = &psxInt;
}
Cpu = CHECK_EEREC ? &recCpu : &intCpu;
psxCpu = CHECK_IOPREC ? &psxRec : &psxInt;
Cpu->Reset();
psxCpu->Reset();
@ -287,83 +277,118 @@ __forceinline void SysUpdate()
HostGui::KeyEvent( PADkeyEvent() );
}
void SysExecute()
bool EmulationInProgress()
{
g_EmulationInProgress = true;
g_ReturnToGui = false;
// Optimization: We hardcode two versions of the EE here -- one for recs and one for ints.
// This is because recs are performance critical, and being able to inline them into the
// function here helps a small bit (not much but every small bit counts!).
try
{
if( CHECK_EEREC )
{
while( !g_ReturnToGui )
{
recExecute();
SysUpdate();
}
}
else
{
while( !g_ReturnToGui )
{
Cpu->Execute();
SysUpdate();
}
}
}
catch( R5900Exception::BaseExcept& ex )
{
Console::Error( ex.LogMessage() );
Console::Error( fmt_string( "(EE) PC: 0x%8.8x \tCycle: 0x%8.8x", ex.cpuState.pc, ex.cpuState.cycle ).c_str() );
}
return (g_EmuThread != NULL) && g_EmuThread->IsRunning();
}
// Function provided to escape the emulation state, by shutting down plugins and saving
// the GS state. The execution state is effectively preserved, and can be resumed with a
// call to SysExecute.
// Executes the specified cdvd source and optional elf file. This command performs a
// full closure of any existing VM state and starts a fresh VM with the requested
// sources.
void SysExecute( CoreEmuThread* newThread, CDVD_SourceType cdvdsrc )
{
wxASSERT( newThread != NULL );
safe_delete( g_EmuThread );
CDVDsys_ChangeSource( cdvdsrc );
g_EmuThread = newThread;
g_EmuThread->Resume();
}
// Executes the emulator using a saved/existing virtual machine state and currently
// configured CDVD source device.
// Debug assertions:
void SysExecute( CoreEmuThread* newThread )
{
wxASSERT( newThread != NULL );
safe_delete( g_EmuThread );
g_EmuThread = newThread;
g_EmuThread->Resume();
}
// Once execution has been ended no action can be taken on the Virtual Machine (such as
// saving states). No assertions or exceptions.
void SysEndExecution()
{
if( EmuConfig.closeGSonEsc )
StateRecovery::MakeGsOnly();
ClosePlugins( EmuConfig.closeGSonEsc );
g_ReturnToGui = true;
safe_delete( g_EmuThread );
}
void SysSuspend()
{
if( g_EmuThread != NULL )
g_EmuThread->Suspend();
}
void SysResume()
{
if( g_EmuThread != NULL )
g_EmuThread->Resume();
}
// Function provided to escape the emulation state, by shutting down plugins and saving
// the GS state. The execution state is effectively preserved, and can be resumed with a
// call to SysExecute.
/*void SysEndExecution()
{
if( EmuConfig.closeGSonEsc )
StateRecovery::MakeGsOnly();
ClosePlugins( EmuConfig.closeGSonEsc );
}*/
void SysRestorableReset()
{
if( !g_EmulationInProgress ) return;
if( !EmulationInProgress() ) return;
StateRecovery::MakeFull();
}
// The calling function should trap and handle exceptions as needed.
// Exceptions:
// Exception::StateLoadError - thrown when a fully recoverable exception ocurred. The
// virtual machine memory state is fully intact.
//
// Any other exception means the Virtual Memory state is indeterminate and probably
// invalid.
void SysLoadState( const wxString& file )
{
// we perform a full backup to memory first so that we can restore later if the
// load fails. fixme: should this be made optional? It could have significant
// speed impact on state loads on slower machines with low ram. >_<
StateRecovery::MakeFull();
gzLoadingState joe( file ); // this'll throw an StateLoadError.
GetPluginManager().Open();
cpuReset();
SysClearExecutionCache();
joe.FreezeAll();
if( GSsetGameCRC != NULL )
GSsetGameCRC(ElfCRC, g_ZeroGSOptions);
}
void SysReset()
{
// fixme - this code sets the statusbar but never returns control to the window message pump
// so the status bar won't receive the WM_PAINT messages needed to update itself anyway.
// Oops! (air)
HostGui::Notice( _("Resetting...") );
Console::SetTitle( _("Resetting...") );
g_EmulationInProgress = false;
StateRecovery::Clear();
cpuShutdown();
ShutdownPlugins();
Console::Status( _("Resetting...") );
safe_delete( g_EmuThread );
GetPluginManager().Shutdown();
ElfCRC = 0;
// Note : No need to call cpuReset() here. It gets called automatically before the
// emulator resumes execution.
HostGui::Notice( _("Ready") );
Console::SetTitle( _("Emulation state is reset.") );
}
// Maps a block of memory for use as a recompiled code buffer, and ensures that the
// allocation is below a certain memory address (specified in "bounds" parameter).
// The allocated block has code execution privileges.
// Returns NULL on allocation failure.
u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller)
{
u8 *Mem = (u8*)HostSys::Mmap( base, size );

View File

@ -23,34 +23,38 @@
#include "Utilities/Threading.h" // to use threading stuff, include the Threading namespace in your file.
#include "Misc.h"
class CoreEmuThread;
enum CDVD_SourceType;
extern bool SysInit();
extern void SysDetect(); // Detects cpu type and fills cpuInfo structs.
extern void SysReset(); // Resets the various PS2 cpus, sub-systems, and recompilers.
extern void SysUpdate(); // Called on VBlank (to update i.e. pads)
extern void SysExecute( CoreEmuThread* newThread );
extern void SysExecute( CoreEmuThread* newThread, CDVD_SourceType cdvdsrc );
extern void SysEndExecution();
extern void SysSuspend();
extern void SysResume();
extern bool SysAllocateMem(); // allocates memory for all PS2 systems; returns FALSe on critical error.
extern void SysAllocateDynarecs(); // allocates memory for all dynarecs, and force-disables any failures.
extern void SysShutdownDynarecs();
extern void SysShutdownMem();
extern void SysLoadState( const wxString& file );
extern void SysRestorableReset(); // Saves the current emulation state prior to spu reset.
extern void SysClearExecutionCache(); // clears recompiled execution caches!
extern void SysEndExecution(); // terminates plugins, saves GS state (if enabled), and signals emulation loop to end.
// initiates high-speed execution of the emulation state. This function is currently
// designed to be run from an event loop, but will eventually be re-tooled with threading
// in mindunder the new GUI (assuming Linux approves!), which will make life easier *and*
// improve overall performance too!
extern void SysExecute();
// Maps a block of memory for use as a recompiled code buffer, and ensures that the
// allocation is below a certain memory address (specified in "bounds" parameter).
// The allocated block has code execution privileges.
// Returns NULL on allocation failure.
extern u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed");
extern void vSyncDebugStuff( uint frame );
extern CoreEmuThread* g_EmuThread;
//////////////////////////////////////////////////////////////////////////////////////////
//
#ifdef __LINUX__
# include <signal.h>
@ -91,7 +95,7 @@ namespace Msgbox
extern bool OkCancel( const wxString& text, const wxString& caption=L"PCSX2 Message", int icon=0 );
extern bool YesNo( const wxString& text, const wxString& caption=L"PCSX2 Message", int icon=wxICON_QUESTION );
extern int Assertion( const wxString& text, const wxString& stacktrace );
extern int Assertion( const wxString& text, const wxString& stacktrace );
extern void Except( const Exception::BaseException& src );
}
@ -99,4 +103,3 @@ BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE( pxEVT_MSGBOX, -1 );
DECLARE_EVENT_TYPE( pxEVT_CallStackBox, -1 );
END_DECLARE_EVENT_TYPES()

View File

@ -28,14 +28,10 @@
#include "AppConfig.h"
#include "System.h"
#include "ConsoleLogger.h"
#include "ps2/CoreEmuThread.h"
class IniInterface;
extern wxFileHistory* g_RecentIsoList;
extern wxRect wxGetDisplayArea();
extern bool pxIsValidWindowPosition( const wxWindow& window, const wxPoint& windowPos );
//////////////////////////////////////////////////////////////////////////////////////////
//
struct AppImageIds
@ -183,8 +179,32 @@ protected:
bool TryOpenConfigCwd();
void OnMessageBox( pxMessageBoxEvent& evt );
void CleanupMess();
};
//////////////////////////////////////////////////////////////////////////////////////////
//
class AppEmuThread : public CoreEmuThread
{
public:
AppEmuThread( const wxString& elf_file=wxEmptyString );
virtual ~AppEmuThread() { }
virtual void Resume();
protected:
sptr ExecuteTask();
};
DECLARE_APP(Pcsx2App)
extern int EnumeratePluginsInFolder( const wxDirName& searchPath, wxArrayString* dest );
extern void LoadPlugins();
extern void InitPlugins();
extern void OpenPlugins();
extern wxRect wxGetDisplayArea();
extern bool pxIsValidWindowPosition( const wxWindow& window, const wxPoint& windowPos );
extern wxFileHistory* g_RecentIsoList;

View File

@ -17,13 +17,28 @@
*/
#include "PrecompiledHeader.h"
#include "HostGui.h"
#include "MainFrame.h"
#include "Dump.h"
#include "Elfheader.h"
#include "SaveState.h"
#include "GS.h"
// This API is likely obsolete for the most part, so I've just included a few dummies
// to keep things compiling until I can get to the point of tying up loose ends.
// renderswitch - tells GSdx to go into dx9 sw if "renderswitch" is set.
bool renderswitch = false;
namespace HostGui
{
static const int NUM_STATES = 10;
static int StatesC = 0;
static int g_Pcsx2Recording = 0; // true 1 if recording video and sound
// Sets the status bar message without mirroring the output to the console.
void SetStatusMsg( const wxString& text )
{
@ -37,15 +52,120 @@ namespace HostGui
SetStatusMsg( text );
}
void ResetMenuSlots()
static wxString GetGSStateFilename()
{
// Probably obsolete if we do a savestate dialog.
return Path::Combine( g_Conf->Folders.Savestates, wxsFormat( L"/%8.8X.%d.gs", ElfCRC, StatesC ) );
}
void BeginExecution()
static void ProcessFKeys(int fkey, struct KeyModifiers *keymod)
{
wxASSERT( g_EmuThread != NULL );
g_EmuThread->Resume();
assert(fkey >= 1 && fkey <= 12 );
switch(fkey)
{
case 1:
States_Save( StatesC );
break;
case 2:
if( keymod->shift )
StatesC = (StatesC+NUM_STATES-1) % NUM_STATES;
else
StatesC = (StatesC+1) % NUM_STATES;
Console::Notice( " > Selected savestate slot %d", params StatesC);
if( GSchangeSaveState != NULL )
GSchangeSaveState(StatesC, SaveState::GetFilename(StatesC).mb_str());
break;
case 3:
States_Load( StatesC );
break;
case 4:
// FIXME : Reimplement framelimiting using new oolean system
//CycleFrameLimit(keymod->shift ? -1 : 1);
break;
// note: VK_F5-VK_F7 are reserved for GS
case 8:
GSmakeSnapshot( g_Conf->Folders.Snapshots.ToAscii().data() );
break;
case 9: //gsdx "on the fly" renderer switching
SysSuspend();
StateRecovery::MakeGsOnly();
g_plugins->Close( PluginId_GS );
renderswitch = !renderswitch;
StateRecovery::Recover();
SysResume();
break;
#ifdef PCSX2_DEVBUILD
case 10:
// There's likely a better way to implement this, but this seemed useful.
// I might add turning EE, VU0, and VU1 recs on and off by hotkey at some point, too.
// --arcum42
enableLogging = !enableLogging;
if (enableLogging)
GSprintf(10, "Logging Enabled.");
else
GSprintf(10,"Logging Disabled.");
break;
case 11:
Console::Notice( "Cannot make gsstates in MTGS mode" );
// fixme : fix up gsstate mess and make it mtgs compatible -- air
#ifdef _STGS_GSSTATE_CODE
wxString Text;
if( strgametitle[0] != 0 )
{
// only take the first two words
wxString gsText;
wxStringTokenizer parts( strgametitle, L" " );
wxString name( parts.GetNextToken() ); // first part
wxString part2( parts.GetNextToken() );
if( !!part2 )
name += L"_" + part2;
gsText.Printf( L"%s.%d.gs", name.c_str(), StatesC );
Text = Path::Combine( g_Conf->Folders.Savestates, gsText );
}
else
{
Text = GetGSStateFilename();
}
break;
#endif
#endif
case 12:
if( keymod->shift )
{
#ifdef PCSX2_DEVBUILD
iDumpRegisters(cpuRegs.pc, 0);
Console::Notice("hardware registers dumped EE:%x, IOP:%x\n", params cpuRegs.pc, psxRegs.pc);
#endif
}
else
{
g_Pcsx2Recording ^= 1;
mtgsThread->SendSimplePacket(GS_RINGTYPE_RECORD, g_Pcsx2Recording, 0, 0);
if( SPU2setupRecording != NULL ) SPU2setupRecording(g_Pcsx2Recording, NULL);
}
break;
}
}
void __fastcall KeyEvent( keyEvent* ev )

View File

@ -23,9 +23,6 @@
#include <wx/docview.h>
#include "App.h"
#include "ps2/CoreEmuThread.h"
extern CoreEmuThread* g_EmuThread;
//////////////////////////////////////////////////////////////////////////////////////////
//

View File

@ -49,23 +49,29 @@ static const wxChar* isoFilterTypes =
void MainEmuFrame::Menu_RunIso_Click(wxCommandEvent &event)
{
g_EmuThread->Suspend();
SysSuspend();
Console::Status( L"Default Folder: " + g_Conf->Folders.RunIso.ToString() );
wxFileDialog ctrl( this, _("Run PS2 Iso..."), g_Conf->Folders.RunIso.ToString(), wxEmptyString,
isoFilterTypes, wxFD_OPEN | wxFD_FILE_MUST_EXIST );
if( ctrl.ShowModal() == wxID_CANCEL ) return;
g_Conf->Folders.RunIso = ctrl.GetPath();
//g_Conf->Save();
if( ctrl.ShowModal() == wxID_CANCEL )
{
SysResume();
return;
}
SysEndExecution();
g_Conf->Folders.RunIso = ctrl.GetPath();
g_Conf->Save();
wxString elf_file;
if( EmuConfig.SkipBiosSplash )
{
// Fetch the ELF filename and CD type from the CDVD provider.
wxString ename( ctrl.GetFilename() );
int result = GetPS2ElfName( ename );
g_EmuThread->SetElfFile( wxEmptyString );
switch( result )
{
case 0:
@ -78,34 +84,32 @@ void MainEmuFrame::Menu_RunIso_Click(wxCommandEvent &event)
case 2:
// PS2 game. Valid!
g_EmuThread->SetElfFile( ename );
elf_file = ename;
break;
}
}
SysExecute( new AppEmuThread( elf_file ), CDVDsrc_Iso );
}
void MainEmuFrame::Menu_RunWithoutDisc_Click(wxCommandEvent &event)
{
if( g_EmuThread->IsRunning() )
if( EmulationInProgress() )
{
g_EmuThread->Suspend();
SysSuspend();
// [TODO] : Add one of 'dems checkboxes that read like "[x] don't show this stupid shit again, kthx."
bool result = Msgbox::OkCancel( pxE( ".Popup:ConfirmEmuReset", L"This will reset the emulator and your current emulation session will be lost. Are you sure?") );
if( !result )
{
if( !IsPaused() )
g_EmuThread->Resume();
SysResume();
return;
}
}
g_EmuThread->Reset();
CDVDsys_ChangeSource( CDVDsrc_NoDisc );
g_EmuThread->Resume();
//HostGui::BeginExecution();
SysEndExecution();
SysExecute( new AppEmuThread(), CDVDsrc_NoDisc );
}
void MainEmuFrame::Menu_IsoRecent_Click(wxCommandEvent &event)

View File

@ -1,21 +0,0 @@
AUTOMAKE_OPTIONS = foreign
INCLUDES = $(shell pkg-config --cflags gtk+-2.0) -I@srcdir@/../ -I@srcdir@/../Linux/ -I@srcdir@/../../common/include -I@srcdir@/../../3rdparty $(shell wx-config --cppflags)
bin_PROGRAMS = pcsx2
# the application source, library search path, and link libraries
pcsx2_SOURCES = \
CheckedStaticBox.cpp ConsoleLogger.cpp MainFrame.cpp wxHelpers.cpp AppConfig.cpp main.cpp \
App.h CheckedStaticBox.h MainFrame.h wxHelpers.h \
IniInterface.cpp AboutBoxDialog.cpp GameFixesDialog.cpp LogOptionsDialog.cpp \
AboutBoxDialog.h GameFixesDialog.h LogOptionsDialog.h
pcsx2_LDFLAGS =
pcsx2_DEPENDENCIES = ../libpcsx2.a ../IPU/libIPU.a ../IPU/mpeg2lib/libmpeg2IPU.a ../RDebug/libRDebug.a ../tinyxml/libtinyxml.a
pcsx2_DEPENDENCIES += ../x86/libx86recomp.a ../x86/ix86/libix86.a
pcsx2_DEPENDENCIES += ../DebugTools/libDebugTools.a
pcsx2_LDADD = ../libpcsx2.a ../IPU/libIPU.a ../IPU/mpeg2lib/libmpeg2IPU.a ../RDebug/libRDebug.a ../tinyxml/libtinyxml.a
pcsx2_LDADD += ../x86/libx86recomp.a ../x86/ix86/libix86.a
pcsx2_LDADD += ../DebugTools/libDebugTools.a

View File

@ -17,7 +17,7 @@
*/
#include "PrecompiledHeader.h"
#include "System.h"
#include "App.h"
#include "Plugins.h"
#include "Utilities/ScopedPtr.h"
#include "ConfigurationPanels.h"
@ -39,6 +39,21 @@ DEFINE_EVENT_TYPE(wxEVT_EnumerationFinished);
typedef s32 (CALLBACK* PluginTestFnptr)();
typedef void (CALLBACK* PluginConfigureFnptr)();
//////////////////////////////////////////////////////////////////////////////////////////
//
namespace Exception
{
class NotEnumerablePlugin : public BadStream
{
public:
virtual ~NotEnumerablePlugin() throw() {}
explicit NotEnumerablePlugin( const wxString& objname=wxEmptyString ) :
BadStream( objname, "" )
, BaseException( wxLt("File is not a PCSX2 plugin") )
{}
};
}
//////////////////////////////////////////////////////////////////////////////////////////
//
class PluginEnumerator
@ -75,7 +90,7 @@ public:
if( m_GetLibType == NULL || m_GetLibName == NULL || m_GetLibVersion2 == NULL )
{
throw Exception::NotPcsxPlugin( m_plugpath );
throw Exception::NotEnumerablePlugin( m_plugpath );
}
m_type = m_GetLibType();
}
@ -447,10 +462,6 @@ sptr Panels::PluginSelectorPanel::EnumThread::ExecuteTask()
{
Console::Status( ex.LogMessage() );
}
catch( Exception::NotPcsxPlugin& ex )
{
Console::Status( ex.LogMessage() );
}
pthread_testcancel();

83
pcsx2/gui/Plugins.cpp Normal file
View File

@ -0,0 +1,83 @@
/* Pcsx2 - Pc Ps2 Emulator
* Copyright (C) 2002-2009 Pcsx2 Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "PrecompiledHeader.h"
#include "Utilities/ScopedPtr.h"
#include <wx/dir.h>
#include <wx/file.h>
#include "Plugins.h"
#include "GS.h"
#include "HostGui.h"
#include "AppConfig.h"
int EnumeratePluginsInFolder( const wxDirName& searchpath, wxArrayString* dest )
{
wxScopedPtr<wxArrayString> placebo;
wxArrayString* realdest = dest;
if( realdest == NULL )
placebo.reset( realdest = new wxArrayString() );
#ifdef __WXMSW__
// Windows pretty well has a strict "must end in .dll" rule.
wxString pattern( L"*%s" );
#else
// Other platforms seem to like to version their libs after the .so extension:
// blah.so.3.1.fail?
wxString pattern( L"*%s*" );
#endif
return searchpath.Exists() ?
wxDir::GetAllFiles( searchpath.ToString(), realdest, wxsFormat( pattern, wxDynamicLibrary::GetDllExt()), wxDIR_FILES ) : 0;
}
void LoadPlugins()
{
if( g_plugins != NULL ) return;
wxString passins[PluginId_Count];
const PluginInfo* pi = tbl_PluginInfo-1;
while( ++pi, pi->shortname != NULL )
passins[pi->id] = g_Conf->FullpathTo( pi->id );
g_plugins = PluginManager_Create( passins );
}
void InitPlugins()
{
if( g_plugins == NULL )
LoadPlugins();
GetPluginManager().Init();
}
// All plugins except the CDVD are opened here. The CDVD must be opened manually by
// the GUI, depending on the user's menu/config in use.
//
// Exceptions:
// PluginFailure - if any plugin fails to initialize or open.
// ThreadCreationError - If the MTGS thread fails to be created.
//
void OpenPlugins()
{
if( g_plugins == NULL )
InitPlugins();
GetPluginManager().Open();
}

View File

@ -17,6 +17,8 @@
*/
#include "PrecompiledHeader.h"
#include "App.h"
#include "Common.h"
#include "HostGui.h"
@ -40,52 +42,30 @@ bool States_isSlotUsed(int num)
//////////////////////////////////////////////////////////////////////////////////////////
// Save state load-from-file (or slot) helpers.
// Internal use state loading function which does not trap exceptions.
// The calling function should trap and handle exceptions as needed.
static void _loadStateOrExcept( const wxString& file )
{
gzLoadingState joe( file ); // this'll throw an StateLoadError.
// Make sure the cpu and plugins are ready to be state-ified!
cpuReset();
OpenPlugins();
joe.FreezeAll();
if( GSsetGameCRC != NULL )
GSsetGameCRC(ElfCRC, g_ZeroGSOptions);
}
// returns true if the new state was loaded, or false if nothing happened.
void States_Load( const wxString& file )
{
try
{
_loadStateOrExcept( file );
HostGui::Notice( wxsFormat( _("Loaded State %s"), file.c_str() ) );
SysLoadState( file );
HostGui::Notice( wxsFormat( _("Loaded State %s"),
wxFileName( file ).GetFullName().c_str() ) );
}
catch( Exception::StateLoadError& ex)
catch( Exception::BadSavedState& ex)
{
// At this point we can return control back to the user, no questions asked.
// StateLoadErrors are only thorwn if the load failed prior to any virtual machine
// memory contents being changed. (usually missing file errors)
Console::Notice( ex.LogMessage() );
// At this point the cpu hasn't been reset, so we can return
// control to the user safely... (that's why we use a console notice instead of a popup)
return;
}
catch( Exception::BaseException& ex )
{
// The emulation state is ruined. Might as well give them a popup and start the gui.
// Translation Tip: Since the savestate load was incomplete, the emulator has been reset.
Msgbox::Alert(
wxsFormat( _("Error loading savestate from file: %s"), file.c_str() ) +
L"\n\n" + _("Error details:") + ex.DisplayMessage()
);
SysReset();
return;
// VM state is probably ruined. We'll need to recover from the in-memory backup.
StateRecovery::Recover();
}
HostGui::BeginExecution();
SysExecute( new AppEmuThread() );
}
void States_Load(int num)
@ -94,39 +74,13 @@ void States_Load(int num)
if( !Path::IsFile( file ) )
{
Console::Notice( "Saveslot %d is empty.", params num );
Console::Notice( "Savestate slot %d is empty.", params num );
return;
}
try
{
_loadStateOrExcept( file );
HostGui::Notice( wxsFormat( _("Loaded State %d"), num ) );
}
catch( Exception::StateLoadError& ex)
{
Console::Notice( wxsFormat( L"Could not load savestate slot %d.\n\n%s", num, ex.LogMessage().c_str() ) );
// At this point the cpu hasn't been reset, so we can return
// control to the user safely... (that's why we use a console notice instead of a popup)
return;
}
catch( Exception::BaseException& ex )
{
// The emulation state is ruined. Might as well give them a popup and start the gui.
// Translation Tip: Since the savestate load was incomplete, the emulator has been reset.
Msgbox::Alert(
wxsFormat( _("Error loading savestate from slot %d"), file.c_str() ) +
L"\n\n" + _("Error details:") + ex.DisplayMessage()
);
SysEndExecution();
return;
}
HostGui::BeginExecution();
Console::Status( "Loading savestate from slot %d...", params num );
States_Load( file );
HostGui::Notice( wxsFormat( _("Loaded State (slot %d)"), num ) );
}
//////////////////////////////////////////////////////////////////////////////////////////
@ -134,10 +88,17 @@ void States_Load(int num)
void States_Save( const wxString& file )
{
if( !EmulationInProgress() )
{
Msgbox::Alert( _("You need to start emulation first before you can save it's state.") );
return;
}
try
{
Console::Status( wxsFormat( L"Saving savestate to file: %s", file.c_str() ) );
StateRecovery::SaveToFile( file );
HostGui::Notice( wxsFormat( _("State saved to file: %s"), file.c_str() ) );
HostGui::Notice( wxsFormat( _("State saved to file: %s"), wxFileName( file ).GetFullName().c_str() ) );
}
catch( Exception::BaseException& ex )
{
@ -153,32 +114,16 @@ void States_Save( const wxString& file )
Console::Error( wxsFormat(
L"An error occurred while trying to save to file %s\n", file.c_str() ) +
L"Your emulation state has not been saved!\n\nError: " + ex.LogMessage()
L"Your emulation state has not been saved!\n"
L"\nError: " + ex.LogMessage()
);
}
// Filename could be a valid slot, so still need to update
HostGui::ResetMenuSlots();
}
void States_Save(int num)
{
try
{
StateRecovery::SaveToSlot( num );
HostGui::Notice( wxsFormat( _("State saved to slot %d"), num ) );
}
catch( Exception::BaseException& ex )
{
// TODO: Implement a "pause the action and issue a popup" thing here.
// *OR* some kind of GS overlay... [for now we use the console]
Console::Error( wxsFormat(
L"An error occurred while trying to save to slot %d\n", num ) +
L"Your emulation state has not been saved!\n\nError: " + ex.LogMessage()
);
}
HostGui::ResetMenuSlots();
Console::Status( "Saving savestate to slot %d...", params num );
States_Save( SaveState::GetFilename( num ) );
}
//////////////////////////////////////////////////////////////////////////////////////////
@ -196,7 +141,7 @@ void vSyncDebugStuff( uint frame )
g_TestRun.frame += 20;
if( g_TestRun.curimage >= g_TestRun.numimages ) {
// exit
SysEndExecution();
g_EmuThread->Cancel();
}
}
else {
@ -206,7 +151,7 @@ void vSyncDebugStuff( uint frame )
}
else {
// exit
SysEndExecution();
g_EmuThread->Cancel();
}
}
}

View File

@ -19,6 +19,9 @@
#include "PrecompiledHeader.h"
#include "IniInterface.h"
#include "MainFrame.h"
#include "MemoryCard.h"
#include "Plugins.h"
#include "Dialogs/ModalPopups.h"
#include "Utilities/ScopedPtr.h"
@ -34,7 +37,6 @@ IMPLEMENT_APP(Pcsx2App)
bool UseAdminMode = false;
AppConfig* g_Conf = NULL;
wxFileHistory* g_RecentIsoList = NULL;
CoreEmuThread* g_EmuThread = NULL;
namespace Exception
{
@ -53,6 +55,70 @@ namespace Exception
};
}
AppEmuThread::AppEmuThread( const wxString& elf_file ) :
CoreEmuThread( elf_file )
{
MemoryCard::Init();
}
void AppEmuThread::Resume()
{
if( wxGetApp().GetMainFrame().IsPaused() ) return;
CoreEmuThread::Resume();
}
sptr AppEmuThread::ExecuteTask()
{
try
{
CoreEmuThread::ExecuteTask();
}
// ----------------------------------------------------------------------------
catch( Exception::FileNotFound& ex )
{
if( ex.StreamName == g_Conf->FullpathToBios() )
{
Msgbox::OkCancel( ex.DisplayMessage() +
_("\n\nPress Ok to go to the BIOS Configuration Panel.") );
}
else
{
// Probably a plugin. Find out which one!
const PluginInfo* pi = tbl_PluginInfo-1;
while( ++pi, pi->shortname != NULL )
{
const PluginsEnum_t pid = pi->id;
if( g_Conf->FullpathTo( pid ) == ex.StreamName ) break;
}
if( pi->shortname == NULL )
{
// Some other crap file failure >_<
}
int result = Msgbox::OkCancel( ex.DisplayMessage() +
_("\n\nPress Ok to go to the Plugin Configuration Panel.") );
if( result == wxID_OK )
{
}
}
}
// ----------------------------------------------------------------------------
// [TODO] : Add exception handling here for debuggable PS2 exceptions that allows
// invocation of the PCSX2 debugger and such.
catch( Exception::BaseException& ex )
{
// Sent the exception back to the main gui thread?
GetPluginManager().Close();
Msgbox::Alert( ex.DisplayMessage() );
}
return 0;
}
wxFrame* Pcsx2App::GetMainWindow() const { return m_MainFrame; }
#include "HashMap.h"
@ -165,7 +231,6 @@ bool Pcsx2App::OnInit()
wxApp::OnInit();
g_Conf = new AppConfig();
g_EmuThread = new CoreEmuThread();
wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
@ -236,6 +301,8 @@ bool Pcsx2App::PrepForExit()
int Pcsx2App::OnExit()
{
MemoryCard::Shutdown();
if( g_Conf != NULL )
g_Conf->Save();

View File

@ -38,43 +38,58 @@ CoreEmuThread& CoreEmuThread::Get()
void CoreEmuThread::CpuInitializeMess()
{
try
{
OpenPlugins();
cpuReset();
SysClearExecutionCache();
GetPluginManager().Open();
cpuReset();
SysClearExecutionCache();
if( GSsetGameCRC != NULL )
GSsetGameCRC( ElfCRC, 0 );
if( StateRecovery::HasState() )
{
// no need to boot bios or detect CDs when loading savestates.
// [TODO] : It might be useful to detect game SLUS/CRC and compare it against
// the savestate info, and issue a warning to the user since, chances are, they
// don't really want to run a game with the wrong ISO loaded into the emu.
StateRecovery::Recover();
}
else
{
ScopedLock lock( m_lock_elf_file );
if( !m_elf_file.IsEmpty() )
{
// Skip Bios Hack -- Runs the PS2 BIOS stub, and then manually loads the ELF
// executable data, and injects the cpuRegs.pc with the address of the
// execution start point.
//
// This hack is necessary for non-CD ELF files, and is optional for game CDs
// (though not recommended for games because of rare ill side effects).
cpuExecuteBios();
loadElfFile( m_elf_file );
}
}
}
catch( Exception::BaseException& ex )
if( StateRecovery::HasState() )
{
Msgbox::Alert( ex.DisplayMessage() );
// no need to boot bios or detect CDs when loading savestates.
// [TODO] : It might be useful to detect game SLUS/CRC and compare it against
// the savestate info, and issue a warning to the user since, chances are, they
// don't really want to run a game with the wrong ISO loaded into the emu.
StateRecovery::Recover();
}
else
{
if( !m_elf_file.IsEmpty() )
{
// Skip Bios Hack -- Runs the PS2 BIOS stub, and then manually loads the ELF
// executable data, and injects the cpuRegs.pc with the address of the
// execution start point.
//
// This hack is necessary for non-CD ELF files, and is optional for game CDs
// (though not recommended for games because of rare ill side effects).
cpuExecuteBios();
loadElfFile( m_elf_file );
}
}
}
// 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
#endif
// On Win32 this function invokes SEH, which requires it be in a function all by itself
// with inlining disabled.
__unique_stackframe
void CoreEmuThread::CpuExecute()
{
PCSX2_MEM_PROTECT_BEGIN();
Cpu->Execute();
PCSX2_MEM_PROTECT_END();
}
static void _cet_callback_cleanup( void* handle )
{
((CoreEmuThread*)handle)->DoThreadCleanup();
}
sptr CoreEmuThread::ExecuteTask()
@ -86,13 +101,11 @@ sptr CoreEmuThread::ExecuteTask()
m_ResumeEvent.Wait();
}
pthread_cleanup_push( _cet_callback_cleanup, this );
CpuInitializeMess();
StateCheck();
PCSX2_MEM_PROTECT_BEGIN();
Cpu->Execute();
PCSX2_MEM_PROTECT_END();
CpuExecute();
pthread_cleanup_pop( true );
return 0;
}
@ -127,28 +140,32 @@ void CoreEmuThread::StateCheck()
}
}
void CoreEmuThread::Start()
CoreEmuThread::CoreEmuThread( const wxString& elf_file ) :
m_ExecMode( ExecMode_Idle )
, m_Done( false )
, m_ResumeEvent()
, m_SuspendEvent()
, m_resetRecompilers( false )
, m_resetProfilers( false )
, m_elf_file( elf_file )
, m_lock_ExecMode()
{
if( IsRunning() ) return;
m_running = false;
m_ExecMode = ExecMode_Idle;
m_Done = false;
m_resetProfilers = false;
m_resetRecompilers = false;
m_elf_file = wxEmptyString;
m_ResumeEvent.Reset();
m_SuspendEvent.Reset();
PersistentThread::Start();
pthread_detach( m_thread );
}
void CoreEmuThread::Reset()
// Invoked by the pthread_exit or pthread_cancel
void CoreEmuThread::DoThreadCleanup()
{
wxASSERT( IsSelf() ); // only allowed from our own thread, thanks.
m_running = false;
GetPluginManager().Close();
}
CoreEmuThread::~CoreEmuThread()
{
Cancel();
StateRecovery::Clear();
}
// Resumes the core execution state, or does nothing is the core is already running. If
@ -156,7 +173,7 @@ void CoreEmuThread::Reset()
// memory savestates.
void CoreEmuThread::Resume()
{
Start();
if( IsSelf() || !IsRunning() ) return;
{
ScopedLock locker( m_lock_ExecMode );
@ -208,6 +225,8 @@ void CoreEmuThread::Resume()
//
void CoreEmuThread::Suspend( bool isBlocking )
{
if( IsSelf() || !IsRunning() ) return;
{
ScopedLock locker( m_lock_ExecMode );
@ -232,3 +251,4 @@ void CoreEmuThread::ApplySettings( const Pcsx2Config& src )
m_resetProfilers = (src.Profiler != EmuConfig.Profiler );
EmuConfig = src;
}

View File

@ -46,46 +46,27 @@ protected:
bool m_resetRecompilers;
bool m_resetProfilers;
wxString m_elf_file;
MutexLock m_lock_elf_file;
const wxString m_elf_file;
MutexLock m_lock_ExecMode;
public:
static CoreEmuThread& Get();
public:
CoreEmuThread() :
m_ExecMode( ExecMode_Idle )
, m_Done( false )
, m_ResumeEvent()
, m_SuspendEvent()
, m_resetRecompilers( false )
, m_resetProfilers( false )
, m_elf_file()
, m_lock_elf_file()
, m_lock_ExecMode()
{
}
void SetElfFile( const wxString& text )
{
ScopedLock lock( m_lock_elf_file );
m_elf_file = text;
}
void Start();
void Reset();
explicit CoreEmuThread( const wxString& elf_file=wxEmptyString );
virtual ~CoreEmuThread();
bool IsSuspended() const { return (m_ExecMode == ExecMode_Suspended); }
void Suspend( bool isBlocking = true );
void Resume();
void ApplySettings( const Pcsx2Config& src );
virtual void Suspend( bool isBlocking = true );
virtual void Resume();
virtual void ApplySettings( const Pcsx2Config& src );
virtual void StateCheck();
void StateCheck();
virtual void DoThreadCleanup();
protected:
void CpuInitializeMess();
sptr ExecuteTask();
void CpuExecute();
virtual sptr ExecuteTask();
};

View File

@ -1950,6 +1950,10 @@
RelativePath="..\..\gui\MainMenuClicks.cpp"
>
</File>
<File
RelativePath="..\..\gui\Saveslots.cpp"
>
</File>
<File
RelativePath="..\..\gui\wxHelpers.cpp"
>
@ -2134,16 +2138,32 @@
>
</File>
</Filter>
<Filter
Name="System"
>
<File
RelativePath="..\..\gui\Plugins.cpp"
>
</File>
<File
RelativePath="..\WinCompressNTFS.cpp"
>
</File>
<File
RelativePath="..\WinSysExec.cpp"
>
</File>
</Filter>
</Filter>
<Filter
Name="HostSystem"
Name="SysCore"
>
<File
RelativePath="..\..\PathUtils.cpp"
>
</File>
<File
RelativePath="..\..\Plugins.cpp"
RelativePath="..\..\PluginManager.cpp"
>
</File>
<File
@ -2154,10 +2174,6 @@
RelativePath="..\SamplProf.cpp"
>
</File>
<File
RelativePath="..\..\Saveslots.cpp"
>
</File>
<File
RelativePath="..\..\SaveState.cpp"
>
@ -2166,14 +2182,6 @@
RelativePath="..\..\System.cpp"
>
</File>
<File
RelativePath="..\WinCompressNTFS.cpp"
>
</File>
<File
RelativePath="..\WinSysExec.cpp"
>
</File>
<Filter
Name="ISO"
>

View File

@ -37,6 +37,9 @@ extern int branch; // set for branch (also used by the SuperVU! .. why
extern u32 target; // branch target
extern u32 s_nBlockCycles; // cycles of current block recompiling
//////////////////////////////////////////////////////////////////////////////////////////
//
#define REC_FUNC( f ) \
void rec##f( void ) \
{ \
@ -94,8 +97,6 @@ void iFlushCall(int flushtype);
void recBranchCall( void (*func)() );
void recCall( void (*func)(), int delreg );
extern void recExecute(); // same as recCpu.Execute(), but faster (can be inline'd)
namespace R5900{
namespace Dynarec {
extern void recDoBranchImm( u32* jmpSkip, bool isLikely = false );

View File

@ -112,69 +112,6 @@ static void iBranchTest(u32 newpc = 0xffffffff);
static void ClearRecLUT(BASEBLOCK* base, int count);
static u32 eeScaleBlockCycles();
#ifdef PCSX2_VM_COISSUE
static u8 _eeLoadWritesRs(u32 tempcode)
{
switch(tempcode>>26) {
case 26: // ldl
case 27: // ldr
case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39:
case 55: // LD
case 30: // lq
return ((tempcode>>21)&0x1f)==((tempcode>>16)&0x1f); // rs==rt
}
return 0;
}
static u8 _eeIsLoadStoreCoIssue(u32 firstcode, u32 secondcode)
{
switch(firstcode>>26) {
case 34: // lwl
return (secondcode>>26)==38;
case 38: // lwr
return (secondcode>>26)==34;
case 42: // swl
return (secondcode>>26)==46;
case 46: // swr
return (secondcode>>26)==42;
case 26: // ldl
return (secondcode>>26)==27;
case 27: // ldr
return (secondcode>>26)==26;
case 44: // sdl
return (secondcode>>26)==45;
case 45: // sdr
return (secondcode>>26)==44;
case 32: case 33: case 35: case 36: case 37: case 39:
case 55: // LD
// stores
case 40: case 41: case 43:
case 63: // sd
return (secondcode>>26)==(firstcode>>26);
case 30: // lq
case 31: // sq
case 49: // lwc1
case 57: // swc1
case 54: // lqc2
case 62: // sqc2
return (secondcode>>26)==(firstcode>>26);
}
return 0;
}
static u8 _eeIsLoadStoreCoX(u32 tempcode)
{
switch( tempcode>>26 ) {
case 30: case 31: case 49: case 57: case 55: case 63:
return 1;
}
return 0;
}
#endif
void _eeFlushAllUnused()
{
int i;
@ -446,13 +383,22 @@ static void recAlloc()
x86FpuState = FPU_STATE;
}
struct ManualPageTracking
{
u16 page;
u8 counter;
};
PCSX2_ALIGNED16( static u16 manual_page[Ps2MemSize::Base >> 12] );
PCSX2_ALIGNED16( static u8 manual_counter[Ps2MemSize::Base >> 12] );
volatile bool eeRecIsReset = false;
////////////////////////////////////////////////////
void recResetEE( void )
{
Console::Status( "Issuing EE/iR5900-32 Recompiler Reset [mem/structure cleanup]" );
eeRecIsReset = true;
maxrecmem = 0;
@ -616,67 +562,71 @@ static void __naked DispatcherEvent()
jmp DispatcherReg;
}
}
#endif
void recExecute()
static void recExecute()
{
g_EEFreezeRegs = true;
// Enter an endless loop, which is only escapable via C++ exception handling.
// Implementation Notes:
// This function enter an endless loop, which is only escapable via C++ exception handling.
// The loop is needed because some things in the rec use "ret" as a shortcut to
// invoking DispatcherReg. These things are code bits which are called infrequently,
// such as dyna_block_discard and dyna_page_reset.
// Optimization note:
// Compared pushad against manually pushing the regs one-by-one.
// Manually pushing is faster, especially on Core2's and such. :)
g_EEFreezeRegs = true;
while( true )
{
// Optimization note : Compared pushad against manually pushing the regs one-by-one.
// Manually pushing is faster, especially on Core2's and such. :)
__asm
try
{
push ebx
push esi
push edi
push ebp
#ifdef _MSC_VER
call DispatcherReg
__asm
{
push ebx
push esi
push edi
push ebp
pop ebp
pop edi
pop esi
pop ebx
}
}
g_EEFreezeRegs = false;
}
call DispatcherReg
pop ebp
pop edi
pop esi
pop ebx
}
#else // _MSC_VER
__forceinline void recExecute()
{
// Optimization note : Compared pushad against manually pushing the regs one-by-one.
// Manually pushing is faster, especially on Core2's and such. :)
g_EEFreezeRegs = true;
__asm__
(
".intel_syntax noprefix\n"
"push ebx\n"
"push esi\n"
"push edi\n"
"push ebp\n"
__asm__
(
".intel_syntax noprefix\n"
"push ebx\n"
"push esi\n"
"push edi\n"
"push ebp\n"
"call DispatcherReg\n"
"call DispatcherReg\n"
"pop ebp\n"
"pop edi\n"
"pop esi\n"
"pop ebx\n"
".att_syntax\n"
);
#endif
}
catch( Exception::RecompilerReset& )
{
}
}
"pop ebp\n"
"pop edi\n"
"pop esi\n"
"pop ebx\n"
".att_syntax\n"
);
g_EEFreezeRegs = false;
}
#endif
namespace R5900 {
namespace Dynarec {
namespace OpcodeImpl {

View File

@ -24,10 +24,6 @@ using namespace std;
#include "Patch.h"
#include "System.h"
#ifdef _MSC_VER
#pragma warning(disable:4996) //ignore the stricmp deprecated warning
#endif
#if !defined(_WIN32)
#ifndef strnicmp
#define strnicmp strncasecmp