mirror of https://github.com/PCSX2/pcsx2.git
wxgui:
* 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:
parent
ea1b204bde
commit
980afabc30
|
@ -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() {}
|
||||
|
@ -113,14 +118,16 @@ namespace Exception
|
|||
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 ) {}
|
||||
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 ) {}
|
||||
|
||||
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 )
|
||||
{}
|
||||
|
|
|
@ -147,6 +147,8 @@ namespace Threading
|
|||
virtual bool IsRunning() const;
|
||||
virtual sptr Block();
|
||||
|
||||
bool IsSelf() const;
|
||||
|
||||
protected:
|
||||
// Used to dispatch the thread callback function.
|
||||
// (handles some thread cleanup on Win32, and is basically a typecast
|
||||
|
|
|
@ -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 )
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
@ -90,7 +92,12 @@ namespace Threading
|
|||
return m_returncode;
|
||||
}
|
||||
|
||||
bool Exists( pthread_t pid )
|
||||
bool PersistentThread::IsSelf() const
|
||||
{
|
||||
return pthread_self() == m_thread;
|
||||
}
|
||||
|
||||
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 ) );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
168
pcsx2/Misc.cpp
168
pcsx2/Misc.cpp
|
@ -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 );
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
@ -628,7 +622,10 @@ void PluginManager::BindCommon( PluginsEnum_t pid )
|
|||
*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()
|
||||
|
@ -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();
|
||||
|
@ -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
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -69,7 +69,6 @@ void psxReset()
|
|||
|
||||
void psxShutdown() {
|
||||
psxBiosShutdown();
|
||||
psxSIOShutdown();
|
||||
//psxCpu->Shutdown();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
if( !EmulationInProgress() ) return;
|
||||
|
||||
States_Save( file );
|
||||
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 );
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
165
pcsx2/System.cpp
165
pcsx2/System.cpp
|
@ -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 );
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -23,9 +23,6 @@
|
|||
#include <wx/docview.h>
|
||||
|
||||
#include "App.h"
|
||||
#include "ps2/CoreEmuThread.h"
|
||||
|
||||
extern CoreEmuThread* g_EmuThread;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
|
|
@ -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;
|
||||
if( ctrl.ShowModal() == wxID_CANCEL )
|
||||
{
|
||||
SysResume();
|
||||
return;
|
||||
}
|
||||
|
||||
SysEndExecution();
|
||||
|
||||
g_Conf->Folders.RunIso = ctrl.GetPath();
|
||||
g_Conf->Save();
|
||||
|
||||
//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)
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,46 +46,27 @@ protected:
|
|||
bool m_resetRecompilers;
|
||||
bool m_resetProfilers;
|
||||
|
||||
wxString m_elf_file;
|
||||
const wxString m_elf_file;
|
||||
|
||||
MutexLock m_lock_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();
|
||||
};
|
||||
|
|
|
@ -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"
|
||||
>
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue