mirror of
https://github.com/libretro/pcsx2.git
synced 2024-11-29 04:10:48 +00:00
Mostly-new host exception system (host meaning the C++ / SEH exceptions, not the VM's PS2/MIPS exceptions). Main purpose is to make specifying diagnostic and end-user messages more sane. Secondary goal was to remove the need for C++ multiple and virtual inheritance, which are buggy in MSVC still, and problematic even when they aren't buggy.
I also re-implemented R5900 runtime exception handling for TLB Miss and such (devbuilds only, for now). git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3335 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
f058e38f5b
commit
1c7fc3e176
@ -122,7 +122,7 @@ extern pxDoAssertFnType* pxDoAssert;
|
||||
# define pxAssertDev(cond, msg) pxAssertRel(cond, msg)
|
||||
|
||||
# define pxAssumeMsg(cond, msg) (__assume(cond))
|
||||
# define pxAssumeDev(cond, msg) pxAssumeMsg(cond, msg)
|
||||
# define pxAssumeDev(cond, msg) pxAssumeRel(cond, msg)
|
||||
|
||||
# define pxFail(msg) (__assume(false))
|
||||
# define pxFailDev(msg) pxAssumeDev(false, msg)
|
||||
|
@ -108,6 +108,30 @@ static const pxEnumEnd_t pxEnumEnd = {};
|
||||
classname& operator=(const classname&)
|
||||
#endif
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ScopedBool - Makes sure a boolean is set back to FALSE when current scope is left
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception-safe way of tracking entry and exit of various functions of execution zones.
|
||||
//
|
||||
class ScopedBool
|
||||
{
|
||||
protected:
|
||||
bool* m_boolme;
|
||||
|
||||
public:
|
||||
ScopedBool(bool& boolme)
|
||||
{
|
||||
boolme = true;
|
||||
m_boolme = &boolme;
|
||||
}
|
||||
|
||||
~ScopedBool() throw()
|
||||
{
|
||||
m_boolme = false;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// macro provided for tagging translation strings, without actually running them through the
|
||||
// translator (which the _() does automatically, and sometimes we don't want that). This is
|
||||
|
@ -66,7 +66,6 @@ namespace Exception
|
||||
protected:
|
||||
wxString m_message_diag; // (untranslated) a "detailed" message of what disastrous thing has occurred!
|
||||
wxString m_message_user; // (translated) a "detailed" message of what disastrous thing has occurred!
|
||||
wxString m_stacktrace; // contains the stack trace string dump (unimplemented)
|
||||
|
||||
public:
|
||||
virtual ~BaseException() throw()=0; // the =0; syntax forces this class into "abstract" mode.
|
||||
@ -77,23 +76,20 @@ namespace Exception
|
||||
wxString& DiagMsg() { return m_message_diag; }
|
||||
wxString& UserMsg() { return m_message_user; }
|
||||
|
||||
BaseException& SetBothMsgs( const char* msg_diag );
|
||||
BaseException& SetDiagMsg( const wxString& msg_diag );
|
||||
BaseException& SetUserMsg( const wxString& msg_user );
|
||||
|
||||
// Returns a message suitable for diagnostic / logging purposes.
|
||||
// This message is always in English, and includes a full stack trace.
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
|
||||
// Returns a message suitable for end-user display.
|
||||
// This message is usually meant for display in a user popup or such.
|
||||
virtual wxString FormatDisplayMessage() const { return m_message_user; }
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
|
||||
virtual void Rethrow() const=0;
|
||||
virtual BaseException* Clone() const=0;
|
||||
|
||||
protected:
|
||||
// Construction using two pre-formatted pre-translated messages
|
||||
void InitBaseEx( const wxString& msg_eng, const wxString& msg_xlt );
|
||||
|
||||
// Construction using one translation key.
|
||||
void InitBaseEx( const char* msg_eng );
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
@ -118,6 +114,9 @@ namespace Exception
|
||||
virtual u32 GetPc() const=0;
|
||||
virtual bool IsDelaySlot() const=0;
|
||||
virtual wxString Message() const { return m_message; }
|
||||
|
||||
virtual void Rethrow() const=0;
|
||||
virtual Ps2Generic* Clone() const=0;
|
||||
};
|
||||
|
||||
// Some helper macros for defining the standard constructors of internationalized constructors
|
||||
@ -129,46 +128,44 @@ namespace Exception
|
||||
// it will be optionally translated.
|
||||
//
|
||||
// BUGZ?? I'd rather use 'classname' on the Clone() prototype, but for some reason it generates
|
||||
// ambiguity errors on virtual inheritence (it really shouldn't!). So I have to force it to the
|
||||
// ambiguity errors on virtual inheritance (it really shouldn't!). So I have to force it to the
|
||||
// BaseException base class. Not sure if this is Stupid Standard Tricks or Stupid MSVC Tricks. --air
|
||||
//
|
||||
// (update: web searches indicate it's MSVC specific -- happens in 2008, not sure about 2010).
|
||||
//
|
||||
#define DEFINE_EXCEPTION_COPYTORS( classname ) \
|
||||
virtual ~classname() throw() {} \
|
||||
virtual void Rethrow() const { throw *this; } \
|
||||
virtual BaseException* Clone() const { return new classname( *this ); }
|
||||
|
||||
// This is here because MSVC's support for covariant return types on Clone() is broken, and will
|
||||
// not work with virtual class inheritance (see DEFINE_EXCEPTION_COPYTORS for details)
|
||||
#define DEFINE_EXCEPTION_COPYTORS_COVARIANT( classname ) \
|
||||
#define DEFINE_EXCEPTION_COPYTORS( classname, parent ) \
|
||||
private: \
|
||||
typedef parent _parent; \
|
||||
public: \
|
||||
virtual ~classname() throw() {} \
|
||||
virtual void Rethrow() const { throw *this; } \
|
||||
virtual classname* Clone() const { return new classname( *this ); }
|
||||
|
||||
#define DEFINE_RUNTIME_EXCEPTION( classname, defmsg ) \
|
||||
DEFINE_EXCEPTION_COPYTORS( classname ) \
|
||||
\
|
||||
explicit classname( const char* msg=defmsg ) { BaseException::InitBaseEx( msg ); } \
|
||||
explicit classname( const wxString& msg_eng, const wxString& msg_xlt ) { BaseException::InitBaseEx( msg_eng, msg_xlt); }
|
||||
|
||||
#define DEFINE_LOGIC_EXCEPTION( classname, defmsg ) \
|
||||
DEFINE_EXCEPTION_COPYTORS( classname ) \
|
||||
\
|
||||
explicit classname( const char* msg=defmsg ) { BaseException::InitBaseEx( msg ); } \
|
||||
explicit classname( const wxString& msg_eng ) { BaseException::InitBaseEx( msg_eng, wxEmptyString ); }
|
||||
#define DEFINE_EXCEPTION_MESSAGES( classname ) \
|
||||
public: \
|
||||
classname& SetBothMsgs( const char* msg_diag ) { BaseException::SetBothMsgs(msg_diag); return *this; } \
|
||||
classname& SetDiagMsg( const wxString& msg_diag ) { m_message_diag = msg_diag; return *this; } \
|
||||
classname& SetUserMsg( const wxString& msg_user ) { m_message_user = msg_user; return *this; }
|
||||
|
||||
#define DEFINE_RUNTIME_EXCEPTION( classname, parent, message ) \
|
||||
DEFINE_EXCEPTION_COPYTORS( classname, parent ) \
|
||||
classname() { SetDiagMsg(wxT(message)); } \
|
||||
DEFINE_EXCEPTION_MESSAGES( classname )
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// RuntimeError - Generalized Exceptions with Recoverable Traits!
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
class RuntimeError : public virtual BaseException
|
||||
class RuntimeError : public BaseException
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS( RuntimeError, BaseException )
|
||||
DEFINE_EXCEPTION_MESSAGES( RuntimeError )
|
||||
|
||||
public:
|
||||
bool IsSilent;
|
||||
public:
|
||||
DEFINE_RUNTIME_EXCEPTION( RuntimeError, wxLt("An unhandled runtime error has occurred, somewhere in the depths of Pcsx2's cluttered brain-matter.") )
|
||||
|
||||
RuntimeError() { IsSilent = false; }
|
||||
RuntimeError( const std::runtime_error& ex, const wxString& prefix=wxEmptyString );
|
||||
RuntimeError( const std::exception& ex, const wxString& prefix=wxEmptyString );
|
||||
};
|
||||
@ -182,18 +179,12 @@ namespace Exception
|
||||
//
|
||||
// I chose to have this exception derive from RuntimeError, since if one is thrown from outside
|
||||
// an App message loop we'll still want it to be handled in a reasonably graceful manner.
|
||||
class CancelEvent : public virtual RuntimeError
|
||||
class CancelEvent : public RuntimeError
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION( CancelEvent, RuntimeError, "No reason given." )
|
||||
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( CancelEvent )
|
||||
|
||||
explicit CancelEvent( const char* logmsg )
|
||||
{
|
||||
m_message_diag = fromUTF8( logmsg );
|
||||
// overridden message formatters only use the diagnostic version...
|
||||
}
|
||||
|
||||
explicit CancelEvent( const wxString& logmsg=L"No reason given." )
|
||||
explicit CancelEvent( const wxString& logmsg )
|
||||
{
|
||||
m_message_diag = logmsg;
|
||||
// overridden message formatters only use the diagnostic version...
|
||||
@ -203,38 +194,33 @@ namespace Exception
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
class ObjectIsNull : public virtual CancelEvent
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// OutOfMemory
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// This exception has a custom-formatted Diagnostic string. The parameter give when constructing
|
||||
// the exception is a block/alloc name, which is used as a formatting parameter in the diagnostic
|
||||
// output. The default diagnostic message is "Out of memory exception, while allocating the %s."
|
||||
// where %s is filled in with the block name.
|
||||
//
|
||||
// The user string is not custom-formatted, and should contain *NO* %s tags.
|
||||
//
|
||||
class OutOfMemory : public RuntimeError
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION( OutOfMemory, RuntimeError, wxLt("Out of memory?!") )
|
||||
|
||||
public:
|
||||
wxString ObjectName;
|
||||
wxString AllocDescription;
|
||||
|
||||
DEFINE_EXCEPTION_COPYTORS( ObjectIsNull )
|
||||
|
||||
explicit ObjectIsNull( const char* objname="unspecified" )
|
||||
{
|
||||
m_message_diag = fromUTF8( objname );
|
||||
// overridden message formatters only use the diagnostic version...
|
||||
}
|
||||
public:
|
||||
OutOfMemory( const wxString& allocdesc );
|
||||
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// OutOfMemory / InvalidOperation / InvalidArgument / ParseError
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
class OutOfMemory : public virtual RuntimeError
|
||||
{
|
||||
public:
|
||||
DEFINE_RUNTIME_EXCEPTION( OutOfMemory, wxLt("Out of Memory") )
|
||||
};
|
||||
|
||||
class ParseError : public RuntimeError
|
||||
{
|
||||
public:
|
||||
DEFINE_RUNTIME_EXCEPTION( ParseError, "Parse error" );
|
||||
DEFINE_RUNTIME_EXCEPTION( ParseError, RuntimeError, "Parse error" );
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
@ -245,16 +231,15 @@ namespace Exception
|
||||
// This exception is a specific type of OutOfMemory error that isn't "really" an out of
|
||||
// memory error. More likely it's caused by a plugin or driver reserving a range of memory
|
||||
// we'd really like to have access to.
|
||||
class VirtualMemoryMapConflict : public virtual OutOfMemory
|
||||
class VirtualMemoryMapConflict : public OutOfMemory
|
||||
{
|
||||
public:
|
||||
DEFINE_RUNTIME_EXCEPTION( VirtualMemoryMapConflict, wxLt("Virtual memory map confict: Unable to claim specific required memory regions.") )
|
||||
DEFINE_RUNTIME_EXCEPTION( VirtualMemoryMapConflict, OutOfMemory, wxLt("Virtual memory map confict: Unable to claim specific required memory regions.") )
|
||||
};
|
||||
|
||||
class HardwareDeficiency : public virtual RuntimeError
|
||||
class HardwareDeficiency : public RuntimeError
|
||||
{
|
||||
public:
|
||||
DEFINE_RUNTIME_EXCEPTION( HardwareDeficiency, wxLt("Your machine's hardware is incapable of running PCSX2. Sorry dood.") );
|
||||
DEFINE_RUNTIME_EXCEPTION( HardwareDeficiency, RuntimeError, wxLt("Your machine's hardware is incapable of running PCSX2. Sorry dood.") );
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
@ -262,51 +247,28 @@ namespace Exception
|
||||
// Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
#define DEFINE_STREAM_EXCEPTION( classname, defmsg ) \
|
||||
DEFINE_EXCEPTION_COPYTORS( classname ) \
|
||||
\
|
||||
explicit classname( const wxString& objname=wxString(), const char* msg=defmsg ) \
|
||||
{ \
|
||||
BaseException::InitBaseEx( msg ); \
|
||||
StreamName = objname; \
|
||||
} \
|
||||
explicit classname( const wxString& objname, const wxString& msg_eng, const wxString& msg_xlt ) \
|
||||
{ \
|
||||
BaseException::InitBaseEx( msg_eng, msg_xlt ); \
|
||||
StreamName = objname; \
|
||||
} \
|
||||
explicit classname( const char* objname, const char* msg=defmsg ) \
|
||||
{ \
|
||||
BaseException::InitBaseEx( msg ); \
|
||||
StreamName = fromUTF8( objname ); \
|
||||
} \
|
||||
explicit classname( const char* objname, const wxString& msg_eng, const wxString& msg_xlt ) \
|
||||
{ \
|
||||
BaseException::InitBaseEx( msg_eng, msg_xlt ); \
|
||||
StreamName = fromUTF8( objname ); \
|
||||
} \
|
||||
explicit classname( const char* objname, const wxString& msg_eng ) \
|
||||
{ \
|
||||
BaseException::InitBaseEx( msg_eng, msg_eng ); \
|
||||
StreamName = fromUTF8( objname ); \
|
||||
} \
|
||||
explicit classname( const wxString& objname, const wxString& msg_eng ) \
|
||||
{ \
|
||||
BaseException::InitBaseEx( msg_eng, msg_eng ); \
|
||||
StreamName = objname; \
|
||||
}
|
||||
#define DEFINE_STREAM_EXCEPTION_ACCESSORS( classname ) \
|
||||
virtual classname& SetStreamName( const wxString& name ) { StreamName = name; return *this; } \
|
||||
virtual classname& SetStreamName( const char* name ) { StreamName = fromUTF8(name); return *this; }
|
||||
|
||||
#define DEFINE_STREAM_EXCEPTION( classname, parent, message ) \
|
||||
DEFINE_RUNTIME_EXCEPTION( classname, parent, message ) \
|
||||
classname( const wxString& filename ) { \
|
||||
StreamName = filename; \
|
||||
SetBothMsgs(message); \
|
||||
} \
|
||||
DEFINE_STREAM_EXCEPTION_ACCESSORS( classname )
|
||||
|
||||
// Generic stream error. Contains the name of the stream and a message.
|
||||
// This exception is usually thrown via derived classes, except in the (rare) case of a
|
||||
// generic / unknown error.
|
||||
//
|
||||
class Stream : public virtual RuntimeError
|
||||
class Stream : public RuntimeError
|
||||
{
|
||||
public:
|
||||
wxString StreamName; // name of the stream (if applicable)
|
||||
DEFINE_STREAM_EXCEPTION( Stream, RuntimeError, wxLt("General file operation error.") )
|
||||
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( Stream, "General file operation error." )
|
||||
wxString StreamName; // name of the stream (if applicable)
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
@ -316,42 +278,40 @@ namespace Exception
|
||||
// connection, or anything else that would indicate a failure to read the data after the
|
||||
// stream was successfully opened.
|
||||
//
|
||||
class BadStream : public virtual Stream
|
||||
class BadStream : public Stream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( BadStream, wxLt("File data is corrupted or incomplete, or the stream connection closed unexpectedly.") )
|
||||
DEFINE_STREAM_EXCEPTION( BadStream, Stream, wxLt("File data is corrupted or incomplete, or the stream connection closed unexpectedly.") )
|
||||
};
|
||||
|
||||
// A generic exception for odd-ball stream creation errors.
|
||||
//
|
||||
class CannotCreateStream : public virtual Stream
|
||||
class CannotCreateStream : public Stream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( CannotCreateStream, wxLt("File could not be created or opened.") )
|
||||
DEFINE_STREAM_EXCEPTION( CannotCreateStream, Stream, wxLt("File could not be created or opened.") )
|
||||
};
|
||||
|
||||
// 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 virtual CannotCreateStream
|
||||
class FileNotFound : public CannotCreateStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( FileNotFound, wxLt("File not found.") )
|
||||
DEFINE_STREAM_EXCEPTION( FileNotFound, CannotCreateStream, wxLt("File not found.") )
|
||||
};
|
||||
|
||||
class AccessDenied : public virtual CannotCreateStream
|
||||
class AccessDenied : public CannotCreateStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( AccessDenied, wxLt("Permission denied to file.") )
|
||||
DEFINE_STREAM_EXCEPTION( AccessDenied, CannotCreateStream, wxLt("Permission denied to file.") )
|
||||
};
|
||||
|
||||
// EndOfStream can be used either as an error, or used just as a shortcut for manual
|
||||
// feof checks.
|
||||
//
|
||||
class EndOfStream : public virtual Stream
|
||||
class EndOfStream : public Stream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( EndOfStream, wxLt("Unexpected end of file or stream.") );
|
||||
DEFINE_STREAM_EXCEPTION( EndOfStream, Stream, wxLt("Unexpected end of file or stream.") );
|
||||
};
|
||||
|
||||
#ifdef __WXMSW__
|
||||
@ -360,13 +320,14 @@ namespace Exception
|
||||
// --------------------------------------------------------------------------------------
|
||||
class WinApiError : public RuntimeError
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS( WinApiError, RuntimeError )
|
||||
DEFINE_EXCEPTION_MESSAGES( WinApiError )
|
||||
|
||||
public:
|
||||
int ErrorId;
|
||||
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( WinApiError )
|
||||
|
||||
WinApiError( const char* msg="" );
|
||||
WinApiError();
|
||||
|
||||
wxString GetMsgFromWindows() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
|
@ -233,8 +233,8 @@ template< int Precision >
|
||||
FixedInt<Precision> FixedInt<Precision>::FromString( const wxString parseFrom )
|
||||
{
|
||||
FixedInt<Precision> dest;
|
||||
if( !TryFromString( dest, parseFrom ) ) throw Exception::ParseError(
|
||||
wxsFormat(L"Parse error on FixedInt<%d>::FromString", Precision), wxEmptyString
|
||||
);
|
||||
if( !TryFromString( dest, parseFrom ) ) throw Exception::ParseError()
|
||||
.SetDiagMsg(wxsFormat(L"Parse error on FixedInt<%d>::FromString", Precision));
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
@ -22,30 +22,6 @@
|
||||
namespace Threading
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IThread - Interface for the public access to pxThread.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Class usage: Can be used for allowing safe nullification of a thread handle. Rather
|
||||
// than being NULL'd, the handle can be mapped to an IThread implementation which acts
|
||||
// as a do-nothing placebo or an assertion generator.
|
||||
//
|
||||
class IThread
|
||||
{
|
||||
DeclareNoncopyableObject(IThread);
|
||||
|
||||
public:
|
||||
IThread() {}
|
||||
virtual ~IThread() throw() {}
|
||||
|
||||
virtual bool IsSelf() const { return false; }
|
||||
virtual bool IsRunning() { return false; }
|
||||
|
||||
virtual void Start() {}
|
||||
virtual void Cancel( bool isBlocking = true ) {}
|
||||
virtual void Block() {}
|
||||
virtual bool Detach() { return false; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ThreadDeleteEvent
|
||||
// --------------------------------------------------------------------------------------
|
||||
@ -109,7 +85,7 @@ namespace Threading
|
||||
// no dependency options for ensuring correct static var initializations). Use heap
|
||||
// allocation to create thread objects instead.
|
||||
//
|
||||
class pxThread : public virtual IThread
|
||||
class pxThread
|
||||
{
|
||||
DeclareNoncopyableObject(pxThread);
|
||||
|
||||
|
@ -93,7 +93,7 @@ protected:
|
||||
m_size = initSize;
|
||||
|
||||
if( m_ptr == NULL )
|
||||
throw Exception::OutOfMemory();
|
||||
throw Exception::OutOfMemory(name + wxsFormat(L" (SafeArray::constructor) [size=%d]", initSize));
|
||||
}
|
||||
|
||||
virtual T* _virtual_realloc( int newsize )
|
||||
@ -138,7 +138,7 @@ public:
|
||||
m_size = initialSize;
|
||||
|
||||
if( (initialSize != 0) && (m_ptr == NULL) )
|
||||
throw Exception::OutOfMemory();
|
||||
throw Exception::OutOfMemory(name + wxsFormat(L" (SafeArray::constructor) [size=%d]", initialSize));
|
||||
}
|
||||
|
||||
// Clears the contents of the array to zero, and frees all memory allocations.
|
||||
@ -163,17 +163,10 @@ public:
|
||||
|
||||
m_ptr = _virtual_realloc( newsize );
|
||||
if( m_ptr == NULL )
|
||||
{
|
||||
throw Exception::OutOfMemory(
|
||||
wxsFormat( // english (for diagnostic)
|
||||
L"Out-of-memory on SafeArray block re-allocation.\n"
|
||||
L"Old size: %d bytes, New size: %d bytes.",
|
||||
m_size, newsize
|
||||
),
|
||||
// internationalized!
|
||||
wxsFormat( _("Out of memory, trying to allocate %d bytes."), newsize )
|
||||
throw Exception::OutOfMemory(Name +
|
||||
wxsFormat(L" (SafeArray::ExactAlloc) [oldsize=%d] [newsize=%d]", m_size, newsize)
|
||||
);
|
||||
}
|
||||
|
||||
m_size = newsize;
|
||||
}
|
||||
|
||||
@ -262,24 +255,27 @@ public:
|
||||
safe_free( m_ptr );
|
||||
}
|
||||
|
||||
explicit SafeList( const wxChar* name=L"Unnamed" ) :
|
||||
Name( name )
|
||||
, ChunkSize( DefaultChunkSize )
|
||||
, m_ptr( NULL )
|
||||
, m_allocsize( 0 )
|
||||
, m_length( 0 )
|
||||
explicit SafeList( const wxChar* name=L"Unnamed" )
|
||||
: Name( name )
|
||||
{
|
||||
ChunkSize = DefaultChunkSize;
|
||||
m_ptr = NULL;
|
||||
m_allocsize = 0;
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
explicit SafeList( int initialSize, const wxChar* name=L"Unnamed" ) :
|
||||
Name( name )
|
||||
, ChunkSize( DefaultChunkSize )
|
||||
, m_ptr( (T*)malloc( initialSize * sizeof(T) ) )
|
||||
, m_allocsize( initialSize )
|
||||
, m_length( 0 )
|
||||
explicit SafeList( int initialSize, const wxChar* name=L"Unnamed" )
|
||||
: Name( name )
|
||||
{
|
||||
ChunkSize = DefaultChunkSize;
|
||||
m_allocsize = initialSize;
|
||||
m_length = 0;
|
||||
m_ptr = (T*)malloc( initialSize * sizeof(T) );
|
||||
|
||||
if( m_ptr == NULL )
|
||||
throw Exception::OutOfMemory();
|
||||
throw Exception::OutOfMemory(Name +
|
||||
wxsFormat(L" (SafeList::Constructor) [length=%d]", m_length)
|
||||
);
|
||||
|
||||
for( int i=0; i<m_allocsize; ++i )
|
||||
{
|
||||
@ -310,18 +306,9 @@ public:
|
||||
const int newalloc = blockSize + ChunkSize;
|
||||
m_ptr = _virtual_realloc( newalloc );
|
||||
if( m_ptr == NULL )
|
||||
{
|
||||
throw Exception::OutOfMemory(
|
||||
// English Diagnostic message:
|
||||
wxsFormat(
|
||||
L"Out-of-memory on SafeList block re-allocation.\n"
|
||||
L"Name: %s, Old size: %d bytes, New size: %d bytes",
|
||||
Name.c_str(), m_allocsize, newalloc
|
||||
),
|
||||
|
||||
wxsFormat( _("Out of memory, trying to allocate %d bytes."), newalloc )
|
||||
throw Exception::OutOfMemory(Name +
|
||||
wxsFormat(L" (SafeList::MakeRoomFor) [oldlen=%d] [newlen=%d]", m_length, blockSize)
|
||||
);
|
||||
}
|
||||
|
||||
for( ; m_allocsize<newalloc; ++m_allocsize )
|
||||
{
|
||||
|
@ -63,23 +63,30 @@ namespace Threading
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
class BaseThreadError : public virtual RuntimeError
|
||||
class BaseThreadError : public RuntimeError
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS( BaseThreadError, RuntimeError )
|
||||
DEFINE_EXCEPTION_MESSAGES( BaseThreadError )
|
||||
|
||||
public:
|
||||
Threading::pxThread* m_thread;
|
||||
|
||||
DEFINE_EXCEPTION_COPYTORS( BaseThreadError )
|
||||
|
||||
explicit BaseThreadError( Threading::pxThread* _thread=NULL )
|
||||
{
|
||||
m_thread = _thread;
|
||||
BaseException::InitBaseEx( "Unspecified thread error" );
|
||||
protected:
|
||||
BaseThreadError() {
|
||||
m_thread = NULL;
|
||||
}
|
||||
|
||||
BaseThreadError( Threading::pxThread& _thread )
|
||||
public:
|
||||
explicit BaseThreadError( Threading::pxThread* _thread )
|
||||
{
|
||||
m_thread = _thread;
|
||||
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
|
||||
}
|
||||
|
||||
explicit BaseThreadError( Threading::pxThread& _thread )
|
||||
{
|
||||
m_thread = &_thread;
|
||||
BaseException::InitBaseEx( "Unspecified thread error" );
|
||||
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
|
||||
}
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
@ -89,27 +96,21 @@ namespace Exception
|
||||
const Threading::pxThread& Thread() const;
|
||||
};
|
||||
|
||||
class ThreadCreationError : public virtual BaseThreadError
|
||||
class ThreadCreationError : public BaseThreadError
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( ThreadCreationError )
|
||||
DEFINE_EXCEPTION_COPYTORS( ThreadCreationError, BaseThreadError )
|
||||
|
||||
explicit ThreadCreationError( Threading::pxThread* _thread=NULL, const char* msg="Creation of thread '%s' failed." )
|
||||
public:
|
||||
explicit ThreadCreationError( Threading::pxThread* _thread )
|
||||
{
|
||||
m_thread = _thread;
|
||||
BaseException::InitBaseEx( msg );
|
||||
SetBothMsgs( "Thread creation failure. An unspecified error occurred while trying to create the %s thread." );
|
||||
}
|
||||
|
||||
ThreadCreationError( Threading::pxThread& _thread, const char* msg="Creation of thread '%s' failed." )
|
||||
explicit ThreadCreationError( Threading::pxThread& _thread )
|
||||
{
|
||||
m_thread = &_thread;
|
||||
BaseException::InitBaseEx( msg );
|
||||
}
|
||||
|
||||
ThreadCreationError( Threading::pxThread& _thread, const wxString& msg_diag, const wxString& msg_user )
|
||||
{
|
||||
m_thread = &_thread;
|
||||
BaseException::InitBaseEx( msg_diag, msg_user );
|
||||
SetBothMsgs( "Thread creation failure. An unspecified error occurred while trying to create the %s thread." );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ T* Threading::TlsVariable<T>::GetPtr() const
|
||||
{
|
||||
pthread_setspecific( m_thread_key, result = (T*)_aligned_malloc( sizeof(T), 16 ) );
|
||||
if( result == NULL )
|
||||
throw Exception::OutOfMemory( "Out of memory allocating thread local storage variable." );
|
||||
throw Exception::OutOfMemory( L"Out of memory allocating thread local storage variable." );
|
||||
*result = m_initval;
|
||||
}
|
||||
return result;
|
||||
|
@ -23,14 +23,9 @@
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
wxString GetEnglish( const char* msg )
|
||||
static wxString GetTranslation( const char* msg )
|
||||
{
|
||||
return fromUTF8(msg);
|
||||
}
|
||||
|
||||
wxString GetTranslation( const char* msg )
|
||||
{
|
||||
return wxGetTranslation( fromUTF8(msg) );
|
||||
return msg ? wxGetTranslation( fromUTF8(msg) ) : wxString();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@ -132,71 +127,91 @@ __forceinline void pxOnAssert( const DiagnosticOrigin& origin, const char* msg)
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception Namespace Implementations (Format message handlers for general exceptions)
|
||||
// BaseException (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
BaseException::~BaseException() throw() {}
|
||||
|
||||
void BaseException::InitBaseEx( const wxString& msg_eng, const wxString& msg_xlt )
|
||||
BaseException& BaseException::SetBothMsgs( const char* msg_diag )
|
||||
{
|
||||
m_message_diag = msg_eng;
|
||||
m_message_user = msg_xlt.IsEmpty() ? msg_eng : msg_xlt;
|
||||
|
||||
// Linux/GCC exception handling is still suspect (this is likely to do with GCC more
|
||||
// than linux), and fails to propagate exceptions up the stack from EErec code. This
|
||||
// could likely be because of the EErec using EBP. So to ensure the user at least
|
||||
// gets a log of the error, we output to console here in the constructor.
|
||||
|
||||
#ifdef __LINUX__
|
||||
//wxLogError( msg_eng.c_str() );
|
||||
Console.Error( msg_eng );
|
||||
#endif
|
||||
m_message_user = GetTranslation( msg_diag );
|
||||
return SetDiagMsg( fromUTF8(msg_diag) );
|
||||
}
|
||||
|
||||
// given message is assumed to be a translation key, and will be stored in translated
|
||||
// and untranslated forms.
|
||||
void BaseException::InitBaseEx( const char* msg_eng )
|
||||
BaseException& BaseException::SetDiagMsg( const wxString& msg_diag )
|
||||
{
|
||||
m_message_diag = GetEnglish( msg_eng );
|
||||
m_message_user = GetTranslation( msg_eng );
|
||||
m_message_diag = msg_diag;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef __LINUX__
|
||||
//wxLogError( m_message_diag.c_str() );
|
||||
Console.Error( msg_eng );
|
||||
#endif
|
||||
BaseException& BaseException::SetUserMsg( const wxString& msg_user )
|
||||
{
|
||||
m_message_user = msg_user;
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxString BaseException::FormatDiagnosticMessage() const
|
||||
{
|
||||
return m_message_diag + L"\n\n" + m_stacktrace;
|
||||
return m_message_diag;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
wxString BaseException::FormatDisplayMessage() const
|
||||
{
|
||||
return m_message_user.IsEmpty() ? m_message_diag : m_message_user;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::RuntimeError (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
Exception::RuntimeError::RuntimeError( const std::runtime_error& ex, const wxString& prefix )
|
||||
{
|
||||
IsSilent = false;
|
||||
|
||||
const wxString msg( wxsFormat( L"STL Runtime Error%s: %s",
|
||||
(prefix.IsEmpty() ? prefix.c_str() : wxsFormat(L" (%s)", prefix.c_str()).c_str()),
|
||||
fromUTF8( ex.what() ).c_str()
|
||||
) );
|
||||
|
||||
BaseException::InitBaseEx( msg, msg );
|
||||
SetDiagMsg( msg );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
Exception::RuntimeError::RuntimeError( const std::exception& ex, const wxString& prefix )
|
||||
{
|
||||
IsSilent = false;
|
||||
|
||||
const wxString msg( wxsFormat( L"STL Exception%s: %s",
|
||||
(prefix.IsEmpty() ? prefix.c_str() : wxsFormat(L" (%s)", prefix.c_str()).c_str()),
|
||||
fromUTF8( ex.what() ).c_str()
|
||||
) );
|
||||
|
||||
BaseException::InitBaseEx( msg, msg );
|
||||
SetDiagMsg( msg );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::OutOfMemory (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
Exception::OutOfMemory::OutOfMemory( const wxString& allocdesc )
|
||||
{
|
||||
AllocDescription = allocdesc;
|
||||
m_message_diag = L"Out of memory exception, while allocating the %s.";
|
||||
m_message_user = _("Memory allocation failure! Your system has insufficient memory or resources to meet PCSX2's lofty needs.");
|
||||
}
|
||||
|
||||
wxString Exception::OutOfMemory::FormatDiagnosticMessage() const
|
||||
{
|
||||
return wxsFormat(m_message_diag, AllocDescription.c_str());
|
||||
}
|
||||
|
||||
wxString Exception::OutOfMemory::FormatDisplayMessage() const
|
||||
{
|
||||
if (m_message_user.IsEmpty()) return FormatDisplayMessage();
|
||||
return m_message_user + wxsFormat( L"\n\nInternal allocation descriptor: %s", AllocDescription.c_str());
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
wxString Exception::CancelEvent::FormatDiagnosticMessage() const
|
||||
{
|
||||
// FIXME: This should probably just log a single line from the stacktrace.. ?
|
||||
return L"Action canceled: " + m_message_diag;
|
||||
}
|
||||
|
||||
@ -205,35 +220,20 @@ wxString Exception::CancelEvent::FormatDisplayMessage() const
|
||||
return L"Action canceled: " + m_message_diag;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
wxString Exception::ObjectIsNull::FormatDiagnosticMessage() const
|
||||
{
|
||||
return wxsFormat(
|
||||
L"reference to '%s' failed : handle is null.",
|
||||
m_message_diag.c_str()
|
||||
) + m_stacktrace;
|
||||
}
|
||||
|
||||
wxString Exception::ObjectIsNull::FormatDisplayMessage() const
|
||||
{
|
||||
return wxsFormat(
|
||||
L"reference to '%s' failed : handle is null.",
|
||||
m_message_diag.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
wxString Exception::Stream::FormatDiagnosticMessage() const
|
||||
{
|
||||
return wxsFormat(
|
||||
L"Stream exception: %s\n\tFile/Object: %s",
|
||||
L"%s\n\tFile/Object: %s",
|
||||
m_message_diag.c_str(), StreamName.c_str()
|
||||
) + m_stacktrace;
|
||||
);
|
||||
}
|
||||
|
||||
wxString Exception::Stream::FormatDisplayMessage() const
|
||||
{
|
||||
return m_message_user + L"\n\n" +
|
||||
wxsFormat( _("Name: %s"), StreamName.c_str() );
|
||||
wxString retval( m_message_user );
|
||||
if (!StreamName.IsEmpty())
|
||||
retval += L"\n\n" + wxsFormat( _("Path: %s"), StreamName.c_str() );
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ Threading::MutexRecursive::MutexRecursive() : Mutex( false )
|
||||
if( _InterlockedIncrement( &_attr_refcount ) == 1 )
|
||||
{
|
||||
if( 0 != pthread_mutexattr_init( &_attr_recursive ) )
|
||||
throw Exception::OutOfMemory( "Out of memory error initializing the Mutex attributes for recursive mutexing." );
|
||||
throw Exception::OutOfMemory(L"Recursive mutexing attributes");
|
||||
|
||||
pthread_mutexattr_settype( &_attr_recursive, PTHREAD_MUTEX_RECURSIVE );
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ void Threading::pxThread::Start()
|
||||
RethrowException();
|
||||
|
||||
// And if the thread threw nothing of its own:
|
||||
throw Exception::ThreadCreationError( this, "(%s thread) Start error: created thread never posted startup semaphore." );
|
||||
throw Exception::ThreadCreationError( this ).SetDiagMsg( L"Thread creation error: %s thread never posted startup semaphore." );
|
||||
}
|
||||
|
||||
// Event Rationale (above): Performing this semaphore wait on the created thread is "slow" in the
|
||||
|
@ -201,3 +201,35 @@ wxString GetOSVersionString()
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::WinApiError (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
Exception::WinApiError::WinApiError()
|
||||
{
|
||||
ErrorId = GetLastError();
|
||||
m_message_diag = L"Unspecified Windows API error.";
|
||||
}
|
||||
|
||||
wxString Exception::WinApiError::GetMsgFromWindows() const
|
||||
{
|
||||
if (!ErrorId) return L"No valid error number was assigned to this exception!";
|
||||
|
||||
const DWORD BUF_LEN = 2048;
|
||||
TCHAR t_Msg[BUF_LEN];
|
||||
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, ErrorId, 0, t_Msg, BUF_LEN, 0))
|
||||
return wxsFormat( L"Win32 Error #%d: %s", ErrorId, t_Msg );
|
||||
|
||||
return wxsFormat( L"Win32 Error #%d (no text msg available)", ErrorId );
|
||||
}
|
||||
|
||||
wxString Exception::WinApiError::FormatDisplayMessage() const
|
||||
{
|
||||
return m_message_user + L"\n\n" + GetMsgFromWindows();
|
||||
}
|
||||
|
||||
wxString Exception::WinApiError::FormatDiagnosticMessage() const
|
||||
{
|
||||
return m_message_diag + L"\n\t" + GetMsgFromWindows();
|
||||
}
|
||||
|
||||
|
@ -96,12 +96,7 @@ FILE *_cdvdOpenMechaVer()
|
||||
Console.Warning("MEC File Not Found , Creating Blank File");
|
||||
fd = fopen(file, "wb");
|
||||
if (fd == NULL)
|
||||
{
|
||||
Console.Error( "MEC File Creation failed!" );
|
||||
throw Exception::CannotCreateStream( file );
|
||||
//Msgbox::Alert( "_cdvdOpenMechaVer: Error creating %s", file);
|
||||
//exit(1);
|
||||
}
|
||||
throw Exception::CannotCreateStream(mecfile.GetFullPath());
|
||||
|
||||
fputc(0x03, fd);
|
||||
fputc(0x06, fd);
|
||||
@ -136,10 +131,8 @@ FILE *_cdvdOpenNVM()
|
||||
Console.Warning("NVM File Not Found , Creating Blank File");
|
||||
fd = fopen(file, "wb");
|
||||
if (fd == NULL)
|
||||
{
|
||||
Console.Error( "NVM File Creation failed!" );
|
||||
throw Exception::CannotCreateStream( file );
|
||||
}
|
||||
throw Exception::CannotCreateStream(nvmfile.GetFullPath());
|
||||
|
||||
for (int i=0; i<1024; i++) fputc(0, fd);
|
||||
}
|
||||
return fd;
|
||||
@ -809,7 +802,7 @@ __forceinline void cdvdReadInterrupt()
|
||||
|
||||
// Any other value besides 0 should be considered invalid here (wtf is that wacky
|
||||
// plugin trying to do?)
|
||||
jASSUME( cdvd.RErr == 0 );
|
||||
pxAssume( cdvd.RErr == 0 );
|
||||
}
|
||||
|
||||
if (cdvdReadSector() == -1)
|
||||
|
@ -94,7 +94,8 @@ IsoDirectory::IsoDirectory(SectorSource& r)
|
||||
}
|
||||
|
||||
if( !isValid )
|
||||
throw Exception::FileNotFound( "IsoFS", "Root directory not found on ISO image." );
|
||||
throw Exception::FileNotFound(L"IsoFS") // FIXME: Should report the name of the ISO here...
|
||||
.SetDiagMsg(L"IsoFS could not find the root directory on the ISO image.");
|
||||
|
||||
DevCon.WriteLn( L"(IsoFS) Filesystem is " + FStype_ToString() );
|
||||
Init( rootDirEntry );
|
||||
@ -153,7 +154,7 @@ int IsoDirectory::GetIndexOf(const wxString& fileName) const
|
||||
if(files[i].name == fileName) return i;
|
||||
}
|
||||
|
||||
throw Exception::FileNotFound( fileName );
|
||||
throw Exception::FileNotFound(fileName);
|
||||
}
|
||||
|
||||
const IsoFileDescriptor& IsoDirectory::GetEntry(const wxString& fileName) const
|
||||
|
@ -242,7 +242,7 @@ bool ElfObject::hasHeaders() { return (hasProgramHeaders() && hasSectionHeaders(
|
||||
void ElfObject::readIso(IsoFile file)
|
||||
{
|
||||
int rsize = file.read(data.GetPtr(), data.GetSizeInBytes());
|
||||
if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream( filename );
|
||||
if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream(filename);
|
||||
}
|
||||
|
||||
void ElfObject::readFile()
|
||||
@ -257,19 +257,19 @@ void ElfObject::readFile()
|
||||
rsize = fread(data.GetPtr(), 1, data.GetSizeInBytes(), f);
|
||||
fclose( f );
|
||||
|
||||
if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream( filename );
|
||||
if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream(filename);
|
||||
}
|
||||
|
||||
void ElfObject::checkElfSize(s64 elfsize)
|
||||
{
|
||||
if (elfsize > 0xfffffff)
|
||||
throw Exception::BadStream( filename, wxLt("Illegal ELF file size, over 2GB!") );
|
||||
throw Exception::BadStream(filename).SetBothMsgs(wxLt("Illegal ELF file size over 2GB!"));
|
||||
|
||||
if (elfsize == -1)
|
||||
throw Exception::BadStream( filename, wxLt("Elf file does not exist! ") );
|
||||
throw Exception::BadStream(filename).SetBothMsgs(wxLt("ELF file does not exist!"));
|
||||
|
||||
if (elfsize == 0)
|
||||
throw Exception::BadStream( filename, wxLt("Unexpected end of ELF file: ") );
|
||||
throw Exception::BadStream(filename).SetBothMsgs(wxLt("Unexpected end of ELF file."));
|
||||
}
|
||||
|
||||
u32 ElfObject::getCRC()
|
||||
@ -473,12 +473,14 @@ int GetPS2ElfName( wxString& name )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch (Exception::BadStream&)
|
||||
catch (Exception::BadStream& ex)
|
||||
{
|
||||
Console.Error(ex.FormatDiagnosticMessage());
|
||||
return 0; // ISO error
|
||||
}
|
||||
catch( Exception::FileNotFound& )
|
||||
catch( Exception::FileNotFound& ex )
|
||||
{
|
||||
Console.Warning(ex.FormatDiagnosticMessage());
|
||||
return 0; // no SYSTEM.CNF, not a PS1/PS2 disc.
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "Common.h"
|
||||
|
||||
#include "R5900OpcodeTables.h"
|
||||
#include "R5900Exceptions.h"
|
||||
#include "System/SysThreads.h"
|
||||
|
||||
#include "Elfheader.h"
|
||||
@ -419,6 +420,12 @@ static void intClear(u32 Addr, u32 Size)
|
||||
static void intShutdown() {
|
||||
}
|
||||
|
||||
static void intThrowException( const BaseR5900Exception& ex )
|
||||
{
|
||||
// No tricks needed; C++ stack unwnding shoud suffice for MSW and GCC alike.
|
||||
ex.Rethrow();
|
||||
}
|
||||
|
||||
R5900cpu intCpu =
|
||||
{
|
||||
intAlloc,
|
||||
@ -429,5 +436,6 @@ R5900cpu intCpu =
|
||||
intExecute,
|
||||
|
||||
intCheckExecutionState,
|
||||
intThrowException,
|
||||
intClear,
|
||||
};
|
||||
|
@ -38,7 +38,7 @@ void psxMemAlloc()
|
||||
m_psxAllMem = vtlb_malloc( m_psxMemSize, 4096 );
|
||||
|
||||
if( m_psxAllMem == NULL)
|
||||
throw Exception::OutOfMemory( "psxMemAlloc > failed allocating memory for the IOP processor." );
|
||||
throw Exception::OutOfMemory( L"IOP system ram (and roms)" );
|
||||
|
||||
u8* curpos = m_psxAllMem;
|
||||
psxM = curpos; curpos += Ps2MemSize::IopRam;
|
||||
@ -54,8 +54,8 @@ void psxMemAlloc()
|
||||
// which is performed by MemInit and PsxMemInit()
|
||||
void psxMemReset()
|
||||
{
|
||||
jASSUME( psxMemWLUT != NULL );
|
||||
jASSUME( m_psxAllMem != NULL );
|
||||
pxAssume( psxMemWLUT != NULL );
|
||||
pxAssume( m_psxAllMem != NULL );
|
||||
|
||||
DbgCon.WriteLn( "IOP Resetting physical ram..." );
|
||||
|
||||
|
@ -936,10 +936,11 @@ void SysMtgsThread::WaitForOpen()
|
||||
RethrowException();
|
||||
|
||||
// Not opened yet, and no exceptions. Weird? You decide!
|
||||
// TODO : implement a user confirmation to cancel the action and exit the
|
||||
// [TODO] : implement a user confirmation to cancel the action and exit the
|
||||
// emulator forcefully, or to continue waiting on the GS.
|
||||
|
||||
throw Exception::PluginOpenError( PluginId_GS, "The MTGS thread has become unresponsive while waiting for the GS plugin to open." );
|
||||
throw Exception::PluginOpenError( PluginId_GS )
|
||||
.SetBothMsgs(wxLt("The MTGS thread has become unresponsive while waiting for the GS plugin to open."));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -639,7 +639,7 @@ void memAlloc()
|
||||
m_psAllMem = vtlb_malloc( m_allMemSize, 4096 );
|
||||
|
||||
if( m_psAllMem == NULL)
|
||||
throw Exception::OutOfMemory( "memAlloc > failed to allocate PS2's base ram/rom/scratchpad." );
|
||||
throw Exception::OutOfMemory( L"memAlloc > failed to allocate PS2's base ram/rom/scratchpad." );
|
||||
|
||||
u8* curpos = m_psAllMem;
|
||||
psM = curpos; curpos += Ps2MemSize::Base;
|
||||
|
@ -617,18 +617,22 @@ PluginManager *g_plugins = NULL;
|
||||
// Plugin-related Exception Implementations
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid, const wxString& objname, const char* eng )
|
||||
Exception::PluginOpenError::PluginOpenError( PluginsEnum_t pid )
|
||||
{
|
||||
BaseException::InitBaseEx( eng );
|
||||
StreamName = objname;
|
||||
PluginId = pid;
|
||||
m_message_diag = L"%s plugin failed to open!";
|
||||
m_message_user = L"%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers.";
|
||||
}
|
||||
|
||||
Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid, const wxString& objname,
|
||||
const wxString& eng_msg, const wxString& xlt_msg )
|
||||
Exception::PluginInitError::PluginInitError( PluginsEnum_t pid )
|
||||
{
|
||||
PluginId = pid;
|
||||
m_message_diag = L"%s plugin initialization failed!";
|
||||
m_message_user = L"%s plugin failed to initialize. Your system may have insufficient memory or resources needed.";
|
||||
}
|
||||
|
||||
Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid )
|
||||
{
|
||||
BaseException::InitBaseEx( eng_msg, xlt_msg );
|
||||
StreamName = objname;
|
||||
PluginId = pid;
|
||||
}
|
||||
|
||||
@ -659,7 +663,7 @@ wxString Exception::FreezePluginFailure::FormatDiagnosticMessage() const
|
||||
return wxsFormat(
|
||||
L"%s plugin returned an error while saving the state.\n\n",
|
||||
tbl_PluginInfo[PluginId].shortname
|
||||
) + m_stacktrace;
|
||||
);
|
||||
}
|
||||
|
||||
wxString Exception::FreezePluginFailure::FormatDisplayMessage() const
|
||||
@ -673,7 +677,7 @@ wxString Exception::ThawPluginFailure::FormatDiagnosticMessage() const
|
||||
return wxsFormat(
|
||||
L"%s plugin returned an error while loading the state.\n\n",
|
||||
tbl_PluginInfo[PluginId].shortname
|
||||
) + m_stacktrace;
|
||||
);
|
||||
}
|
||||
|
||||
wxString Exception::ThawPluginFailure::FormatDisplayMessage() const
|
||||
@ -726,17 +730,15 @@ PluginManager::PluginStatus_t::PluginStatus_t( PluginsEnum_t _pid, const wxStrin
|
||||
IsOpened = false;
|
||||
|
||||
if( Filename.IsEmpty() )
|
||||
throw Exception::PluginInitError( pid, "Empty plugin filename." );
|
||||
throw Exception::PluginInitError( pid ).SetDiagMsg( L"Empty plugin filename" );
|
||||
|
||||
if( !wxFile::Exists( Filename ) )
|
||||
throw Exception::PluginLoadError( pid, srcfile,
|
||||
wxLt("The configured %s plugin file was not found")
|
||||
);
|
||||
throw Exception::PluginLoadError( pid ).SetStreamName(srcfile)
|
||||
.SetBothMsgs(wxLt("The configured %s plugin file was not found"));
|
||||
|
||||
if( !Lib.Load( Filename ) )
|
||||
throw Exception::PluginLoadError( pid, Filename,
|
||||
wxLt("The configured %s plugin file is not a valid dynamic library")
|
||||
);
|
||||
throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
|
||||
.SetBothMsgs(wxLt("The configured %s plugin file is not a valid dynamic library"));
|
||||
|
||||
|
||||
// Try to enumerate the new v2.0 plugin interface first.
|
||||
@ -752,10 +754,9 @@ PluginManager::PluginStatus_t::PluginStatus_t( PluginsEnum_t _pid, const wxStrin
|
||||
_PS2EsetEmuVersion SetEmuVersion = (_PS2EsetEmuVersion) Lib.GetSymbol( L"PS2EsetEmuVersion" );
|
||||
|
||||
if( GetLibName == NULL || GetLibVersion2 == NULL )
|
||||
throw Exception::PluginLoadError( pid, Filename,
|
||||
L"\nMethod binding failure on GetLibName or GetLibVersion2.\n",
|
||||
_( "Configured plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2." )
|
||||
);
|
||||
throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
|
||||
.SetDiagMsg(L"%s plugin init failed: Method binding failure on GetLibName or GetLibVersion2.")
|
||||
.SetUserMsg(_( "The configured %s plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2."));
|
||||
|
||||
if( SetEmuVersion != NULL )
|
||||
SetEmuVersion( "PCSX2", (0ul << 24) | (9ul<<16) | (7ul<<8) | 0 );
|
||||
@ -778,10 +779,9 @@ PluginManager::PluginStatus_t::PluginStatus_t( PluginsEnum_t _pid, const wxStrin
|
||||
|
||||
int testres = CommonBindings.Test();
|
||||
if( testres != 0 )
|
||||
throw Exception::PluginLoadError( pid, Filename,
|
||||
wxsFormat( L"Plugin Test failure, return code: %d", testres ),
|
||||
_( "The plugin reports that your hardware or software/drivers are not supported." )
|
||||
);
|
||||
throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
|
||||
.SetDiagMsg(wxsFormat( L"Plugin Test failure, return code: %d", testres ))
|
||||
.SetUserMsg(_("The plugin reports that your hardware or software/drivers are not supported."));
|
||||
}
|
||||
|
||||
void PluginManager::PluginStatus_t::BindCommon( PluginsEnum_t pid )
|
||||
@ -800,10 +800,9 @@ void PluginManager::PluginStatus_t::BindCommon( PluginsEnum_t pid )
|
||||
|
||||
if( *target == NULL )
|
||||
{
|
||||
throw Exception::PluginLoadError( pid, Filename,
|
||||
wxsFormat( L"\nMethod binding failure on: %s\n", current->GetMethodName( pid ).c_str() ),
|
||||
_( "Configured plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2." )
|
||||
);
|
||||
throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
|
||||
.SetDiagMsg(wxsFormat( L"\nMethod binding failure on: %s\n", current->GetMethodName( pid ).c_str() ))
|
||||
.SetUserMsg(_("Configured plugin is not a PCSX2 plugin, or is for an older unsupported version of PCSX2."));
|
||||
}
|
||||
|
||||
target++;
|
||||
@ -827,10 +826,9 @@ void PluginManager::PluginStatus_t::BindRequired( PluginsEnum_t pid )
|
||||
|
||||
if( *(current->Dest) == NULL )
|
||||
{
|
||||
throw Exception::PluginLoadError( pid, Filename,
|
||||
wxsFormat( L"\nMethod binding failure on: %s\n", current->GetMethodName().c_str() ),
|
||||
_( "Configured plugin is not a valid PCSX2 plugin, or is for an older unsupported version of PCSX2." )
|
||||
);
|
||||
throw Exception::PluginLoadError( pid ).SetStreamName(Filename)
|
||||
.SetDiagMsg(wxsFormat( L"\n%s plugin init error; Method binding failed: %s\n", current->GetMethodName().c_str() ))
|
||||
.SetUserMsg(_( "Configured %s plugin is not a valid PCSX2 plugin, or is for an older unsupported version of PCSX2."));
|
||||
}
|
||||
|
||||
current++;
|
||||
@ -929,7 +927,7 @@ void PluginManager::Load( const wxString (&folders)[PluginId_Count] )
|
||||
if( m_mcdPlugin == NULL )
|
||||
{
|
||||
// fixme: use plugin's GetLastError (not implemented yet!)
|
||||
throw Exception::PluginLoadError( PluginId_Mcd, wxEmptyString, "Internal Memorycard Plugin failed to load." );
|
||||
throw Exception::PluginLoadError( PluginId_Mcd ).SetDiagMsg(L"Internal Memorycard Plugin failed to load.");
|
||||
}
|
||||
|
||||
SendLogFolder();
|
||||
@ -1246,7 +1244,8 @@ void PluginManager::Init()
|
||||
if( SysPlugins.Mcd == NULL )
|
||||
{
|
||||
// fixme: use plugin's GetLastError (not implemented yet!)
|
||||
throw Exception::PluginInitError( PluginId_Mcd, "Internal Memorycard Plugin failed to initialize." );
|
||||
throw Exception::PluginInitError( PluginId_Mcd )
|
||||
.SetBothMsgs(wxLt("Internal Memorycard Plugin failed to initialize."));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,24 +55,21 @@ struct PluginInfo
|
||||
namespace Exception
|
||||
{
|
||||
// Exception thrown when a corrupted or truncated savestate is encountered.
|
||||
class SaveStateLoadError : public virtual BadStream
|
||||
class SaveStateLoadError : public BadStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( SaveStateLoadError, wxLt("Load failed: The savestate appears to be corrupt or incomplete.") )
|
||||
DEFINE_STREAM_EXCEPTION( SaveStateLoadError, BadStream, wxLt("The savestate appears to be corrupt or incomplete.") )
|
||||
};
|
||||
|
||||
class PluginError : public virtual RuntimeError
|
||||
class PluginError : public RuntimeError
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION( PluginError, RuntimeError, "Generic plugin error")
|
||||
|
||||
public:
|
||||
PluginsEnum_t PluginId;
|
||||
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( PluginError )
|
||||
|
||||
PluginError() {}
|
||||
PluginError( PluginsEnum_t pid, const char* msg="Generic plugin error" )
|
||||
explicit PluginError( PluginsEnum_t pid )
|
||||
{
|
||||
BaseException::InitBaseEx( msg );
|
||||
PluginId = pid;
|
||||
}
|
||||
|
||||
@ -83,15 +80,22 @@ namespace Exception
|
||||
// Plugin load errors occur when initially trying to load plugins during the
|
||||
// creation of a PluginManager object. The error may either be due to non-existence,
|
||||
// corruption, or incompatible versioning.
|
||||
class PluginLoadError : public virtual PluginError, public virtual BadStream
|
||||
class PluginLoadError : public PluginError
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS( PluginLoadError, PluginError )
|
||||
DEFINE_EXCEPTION_MESSAGES( PluginLoadError )
|
||||
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS_COVARIANT( PluginLoadError )
|
||||
wxString StreamName;
|
||||
|
||||
PluginLoadError( PluginsEnum_t pid, const wxString& objname, const char* eng );
|
||||
protected:
|
||||
PluginLoadError() {}
|
||||
|
||||
PluginLoadError( PluginsEnum_t pid, const wxString& objname,
|
||||
const wxString& eng_msg, const wxString& xlt_msg );
|
||||
public:
|
||||
PluginLoadError( PluginsEnum_t pid );
|
||||
|
||||
virtual PluginLoadError& SetStreamName( const wxString& name ) { StreamName = name; return *this; } \
|
||||
virtual PluginLoadError& SetStreamName( const char* name ) { StreamName = fromUTF8(name); return *this; }
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
@ -100,44 +104,46 @@ namespace Exception
|
||||
// Thrown when a plugin fails it's init() callback. The meaning of this error is entirely
|
||||
// dependent on the plugin and, in most cases probably never happens (most plugins do little
|
||||
// more than a couple basic memory reservations during init)
|
||||
class PluginInitError : public virtual PluginError
|
||||
class PluginInitError : public PluginError
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS_COVARIANT( PluginInitError )
|
||||
DEFINE_EXCEPTION_COPYTORS( PluginInitError, PluginError )
|
||||
DEFINE_EXCEPTION_MESSAGES( PluginInitError )
|
||||
|
||||
explicit PluginInitError( PluginsEnum_t pid,
|
||||
const char* msg=wxLt("%s plugin failed to initialize. Your system may have insufficient memory or resources needed.") )
|
||||
{
|
||||
BaseException::InitBaseEx( msg );
|
||||
PluginId = pid;
|
||||
}
|
||||
protected:
|
||||
PluginInitError() {}
|
||||
|
||||
public:
|
||||
PluginInitError( PluginsEnum_t pid );
|
||||
};
|
||||
|
||||
// Plugin failed to open. Typically this is a non-critical error that means the plugin has
|
||||
// not been configured properly by the user, but may also be indicative of a system
|
||||
class PluginOpenError : public virtual PluginError
|
||||
class PluginOpenError : public PluginError
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS_COVARIANT( PluginOpenError )
|
||||
DEFINE_EXCEPTION_COPYTORS( PluginOpenError, PluginError )
|
||||
DEFINE_EXCEPTION_MESSAGES( PluginOpenError )
|
||||
|
||||
explicit PluginOpenError( PluginsEnum_t pid,
|
||||
const char* msg=wxLt("%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers.") )
|
||||
{
|
||||
BaseException::InitBaseEx( msg );
|
||||
PluginId = pid;
|
||||
}
|
||||
protected:
|
||||
PluginOpenError() {}
|
||||
|
||||
public:
|
||||
explicit PluginOpenError( PluginsEnum_t pid );
|
||||
};
|
||||
|
||||
// This exception is thrown when a plugin returns an error while trying to save itself.
|
||||
// Typically this should be a very rare occurance since a plugin typically shoudn't
|
||||
// be doing memory allocations or file access during state saving.
|
||||
//
|
||||
class FreezePluginFailure : public virtual PluginError
|
||||
class FreezePluginFailure : public PluginError
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( FreezePluginFailure )
|
||||
DEFINE_EXCEPTION_COPYTORS( FreezePluginFailure, PluginError )
|
||||
DEFINE_EXCEPTION_MESSAGES( FreezePluginFailure )
|
||||
|
||||
explicit FreezePluginFailure( PluginsEnum_t pid)
|
||||
protected:
|
||||
FreezePluginFailure() {}
|
||||
|
||||
public:
|
||||
explicit FreezePluginFailure( PluginsEnum_t pid )
|
||||
{
|
||||
PluginId = pid;
|
||||
}
|
||||
@ -146,11 +152,18 @@ namespace Exception
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
class ThawPluginFailure : public virtual PluginError, public virtual SaveStateLoadError
|
||||
class ThawPluginFailure : public SaveStateLoadError
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( ThawPluginFailure )
|
||||
DEFINE_EXCEPTION_COPYTORS( ThawPluginFailure, SaveStateLoadError )
|
||||
DEFINE_EXCEPTION_MESSAGES( ThawPluginFailure )
|
||||
|
||||
public:
|
||||
PluginsEnum_t PluginId;
|
||||
|
||||
protected:
|
||||
ThawPluginFailure() {}
|
||||
|
||||
public:
|
||||
explicit ThawPluginFailure( PluginsEnum_t pid )
|
||||
{
|
||||
PluginId = pid;
|
||||
|
@ -50,9 +50,6 @@ static const uint eeWaitCycles = 3072;
|
||||
|
||||
bool eeEventTestIsActive = false;
|
||||
|
||||
R5900Exception::BaseExcept::~BaseExcept() throw (){}
|
||||
|
||||
|
||||
void cpuReset()
|
||||
{
|
||||
if( GetMTGS().IsOpen() )
|
||||
@ -367,7 +364,7 @@ u32 g_nextBranchCycle = 0;
|
||||
// and the recompiler. (moved here to help alleviate redundant code)
|
||||
__forceinline void _cpuBranchTest_Shared()
|
||||
{
|
||||
eeEventTestIsActive = true;
|
||||
ScopedBool etest(eeEventTestIsActive);
|
||||
g_nextBranchCycle = cpuRegs.cycle + eeWaitCycles;
|
||||
|
||||
// ---- Counters -------------
|
||||
@ -475,8 +472,6 @@ __forceinline void _cpuBranchTest_Shared()
|
||||
// Apply vsync and other counter nextCycles
|
||||
cpuSetNextBranch( nextsCounter, nextCounter );
|
||||
|
||||
eeEventTestIsActive = false;
|
||||
|
||||
// ---- INTC / DMAC Exceptions -----------------
|
||||
// Raise the INTC and DMAC interrupts here, which usually throw exceptions.
|
||||
// This should be done last since the IOP and the VU0 can raise several EE
|
||||
|
@ -15,11 +15,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef __LINUX__
|
||||
#pragma region Recompiler Stuffs
|
||||
#endif
|
||||
class BaseR5900Exception;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// 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.
|
||||
@ -39,12 +39,10 @@ namespace Exception
|
||||
explicit ExitCpuExecute() { }
|
||||
};
|
||||
}
|
||||
#ifndef __LINUX__
|
||||
#pragma endregion
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// EE Bios function name tables.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EE Bios function name tables.
|
||||
// --------------------------------------------------------------------------------------
|
||||
namespace R5900 {
|
||||
extern const char* const bios[256];
|
||||
}
|
||||
@ -349,6 +347,11 @@ struct R5900cpu
|
||||
//
|
||||
void (*CheckExecutionState)();
|
||||
|
||||
// Safely throws host exceptions from executing code (either recompiled or interpreted).
|
||||
// If this function is called outside the context of the CPU's code execution, then the
|
||||
// given exception will be re-thrown automatically.
|
||||
void (*ThrowException)( const BaseR5900Exception& ex );
|
||||
|
||||
// Manual recompiled code cache clear; typically useful to recompilers only. Size is
|
||||
// in MIPS words (32 bits). Dev note: this callback is nearly obsolete, and might be
|
||||
// better off replaced with some generic API callbacks from VTLB block protection.
|
||||
|
@ -13,60 +13,65 @@
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _R5900_EXCEPTIONS_H_
|
||||
#define _R5900_EXCEPTIONS_H_
|
||||
#pragma once
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseR5900Exception
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Abstract base class for R5900 exceptions; contains the cpuRegs instance at the
|
||||
// time the exception is raised.
|
||||
//
|
||||
// Translation note: EE Emulation exceptions are untranslated only. There's really no
|
||||
// point in providing translations for this hardcore mess. :)
|
||||
//
|
||||
class BaseR5900Exception : public Exception::Ps2Generic
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(BaseR5900Exception, Exception::Ps2Generic)
|
||||
|
||||
public:
|
||||
cpuRegisters cpuState;
|
||||
|
||||
public:
|
||||
u32 GetPc() const { return cpuState.pc; }
|
||||
bool IsDelaySlot() const { return !!cpuState.IsDelaySlot; }
|
||||
|
||||
wxString& Message() { return m_message; }
|
||||
wxString FormatMessage() const
|
||||
{
|
||||
return wxsFormat(L"(EE pc:%8.8X) ", cpuRegs.pc) + m_message;
|
||||
}
|
||||
|
||||
protected:
|
||||
void Init( const wxString& msg )
|
||||
{
|
||||
m_message = msg;;
|
||||
cpuState = cpuRegs;
|
||||
}
|
||||
|
||||
void Init( const char* msg )
|
||||
{
|
||||
m_message = fromUTF8( msg );
|
||||
cpuState = cpuRegs;
|
||||
}
|
||||
};
|
||||
|
||||
namespace R5900Exception
|
||||
{
|
||||
using Exception::Ps2Generic;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Abstract base class for R5900 exceptions; contains the cpuRegs instance at the
|
||||
// time the exception is raised.
|
||||
//
|
||||
// Translation note: EE Emulation exceptions are untranslated only. There's really no
|
||||
// point in providing translations for this hardcore mess. :)
|
||||
//
|
||||
class BaseExcept : public virtual Ps2Generic
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseAddressError
|
||||
// --------------------------------------------------------------------------------------
|
||||
class BaseAddressError : public BaseR5900Exception
|
||||
{
|
||||
public:
|
||||
cpuRegisters cpuState;
|
||||
DEFINE_EXCEPTION_COPYTORS(BaseAddressError, BaseR5900Exception)
|
||||
|
||||
public:
|
||||
virtual ~BaseExcept() throw()=0;
|
||||
|
||||
u32 GetPc() const { return cpuState.pc; }
|
||||
bool IsDelaySlot() const { return !!cpuState.IsDelaySlot; }
|
||||
|
||||
protected:
|
||||
void Init( const wxString& msg )
|
||||
{
|
||||
m_message = L"(EE) " + msg;
|
||||
cpuState = cpuRegs;
|
||||
}
|
||||
|
||||
void Init( const char*msg )
|
||||
{
|
||||
m_message = fromUTF8( msg );
|
||||
cpuState = cpuRegs;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class BaseAddressError : public BaseExcept
|
||||
{
|
||||
public:
|
||||
bool OnWrite;
|
||||
u32 Address;
|
||||
|
||||
public:
|
||||
virtual ~BaseAddressError() throw() {}
|
||||
|
||||
protected:
|
||||
void Init( u32 ps2addr, bool onWrite, const wxString& msg )
|
||||
{
|
||||
BaseExcept::Init( wxsFormat( msg+L", addr=0x%x [%s]", ps2addr, onWrite ? L"store" : L"load" ) );
|
||||
_parent::Init( wxsFormat( msg+L", addr=0x%x [%s]", ps2addr, onWrite ? L"store" : L"load" ) );
|
||||
OnWrite = onWrite;
|
||||
Address = ps2addr;
|
||||
}
|
||||
@ -76,54 +81,46 @@ namespace R5900Exception
|
||||
class AddressError : public BaseAddressError
|
||||
{
|
||||
public:
|
||||
virtual ~AddressError() throw() {}
|
||||
|
||||
AddressError( u32 ps2addr, bool onWrite )
|
||||
{
|
||||
BaseAddressError::Init( ps2addr, onWrite, L"Address error" );
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class TLBMiss : public BaseAddressError
|
||||
{
|
||||
public:
|
||||
virtual ~TLBMiss() throw() {}
|
||||
DEFINE_EXCEPTION_COPYTORS(TLBMiss, BaseAddressError)
|
||||
|
||||
public:
|
||||
TLBMiss( u32 ps2addr, bool onWrite )
|
||||
{
|
||||
BaseAddressError::Init( ps2addr, onWrite, L"TLB Miss" );
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class BusError : public BaseAddressError
|
||||
{
|
||||
public:
|
||||
virtual ~BusError() throw() {}
|
||||
DEFINE_EXCEPTION_COPYTORS(BusError, BaseAddressError)
|
||||
|
||||
public:
|
||||
BusError( u32 ps2addr, bool onWrite )
|
||||
{
|
||||
BaseAddressError::Init( ps2addr, onWrite, L"Bus Error" );
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class Trap : public BaseExcept
|
||||
class Trap : public BaseR5900Exception
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(Trap, BaseR5900Exception)
|
||||
|
||||
public:
|
||||
u16 TrapCode;
|
||||
|
||||
public:
|
||||
virtual ~Trap() throw() {}
|
||||
|
||||
// Generates a trap for immediate-style Trap opcodes
|
||||
Trap()
|
||||
{
|
||||
BaseExcept::Init( "Trap" );
|
||||
_parent::Init( "Trap" );
|
||||
TrapCode = 0;
|
||||
}
|
||||
|
||||
@ -131,24 +128,19 @@ namespace R5900Exception
|
||||
// error code in the opcode
|
||||
explicit Trap( u16 trapcode )
|
||||
{
|
||||
BaseExcept::Init( "Trap" ),
|
||||
_parent::Init( "Trap" ),
|
||||
TrapCode = trapcode;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class DebugBreakpoint : public BaseExcept
|
||||
class DebugBreakpoint : public BaseR5900Exception
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(DebugBreakpoint, BaseR5900Exception)
|
||||
|
||||
public:
|
||||
virtual ~DebugBreakpoint() throw() {}
|
||||
|
||||
explicit DebugBreakpoint()
|
||||
{
|
||||
BaseExcept::Init( "Debug Breakpoint" );
|
||||
_parent::Init( "Debug Breakpoint" );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -94,11 +94,9 @@ void SaveStateBase::FreezeTag( const char* src )
|
||||
|
||||
if( strcmp( m_tagspace, src ) != 0 )
|
||||
{
|
||||
pxFail( "Savestate data corruption detected while reading tag" );
|
||||
throw Exception::SaveStateLoadError(
|
||||
// Untranslated diagnostic msg (use default msg for translation)
|
||||
L"Savestate data corruption detected while reading tag: " + fromUTF8(src)
|
||||
);
|
||||
wxString msg( L"Savestate data corruption detected while reading tag: " + fromUTF8(src) );
|
||||
pxFail( msg );
|
||||
throw Exception::SaveStateLoadError().SetDiagMsg(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,10 +227,9 @@ void SaveStateBase::WritebackSectionLength( int seekpos, int sectlen, const wxCh
|
||||
{
|
||||
if( sectlen != realsectsize ) // if they don't match then we have a problem, jim.
|
||||
{
|
||||
throw Exception::SaveStateLoadError( wxEmptyString,
|
||||
wxsFormat( L"Invalid size encountered on section '%s'.", sectname ),
|
||||
_("The savestate data is invalid or corrupted.")
|
||||
);
|
||||
throw Exception::SaveStateLoadError()
|
||||
.SetDiagMsg(wxsFormat(L"Invalid size encountered on section '%s'.", sectname ))
|
||||
.SetUserMsg(_("The savestate data is invalid or corrupted."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -258,10 +255,9 @@ bool SaveStateBase::FreezeSection( int seek_section )
|
||||
|
||||
if( sectlen != 128 )
|
||||
{
|
||||
throw Exception::SaveStateLoadError( wxEmptyString,
|
||||
L"Invalid size encountered on BiosVersion section.",
|
||||
_("The savestate data is invalid or corrupted.")
|
||||
);
|
||||
throw Exception::SaveStateLoadError()
|
||||
.SetDiagMsg(L"Invalid size encountered on BiosVersion section.")
|
||||
.SetUserMsg(_("The savestate data is invalid or corrupted."));
|
||||
}
|
||||
|
||||
if( isSeeking )
|
||||
@ -281,10 +277,9 @@ bool SaveStateBase::FreezeSection( int seek_section )
|
||||
Freeze( sectlen );
|
||||
if( sectlen != MainMemorySizeInBytes )
|
||||
{
|
||||
throw Exception::SaveStateLoadError( wxEmptyString,
|
||||
L"Invalid size encountered on MainMemory section.",
|
||||
_("The savestate data is invalid or corrupted.")
|
||||
);
|
||||
throw Exception::SaveStateLoadError()
|
||||
.SetDiagMsg(L"Invalid size encountered on MainMemory section.")
|
||||
.SetUserMsg(_("The savestate data is invalid or corrupted."));
|
||||
}
|
||||
|
||||
if( isSeeking )
|
||||
|
@ -58,17 +58,20 @@ namespace Exception
|
||||
|
||||
// thrown when the savestate being loaded isn't supported.
|
||||
//
|
||||
class UnsupportedStateVersion : public virtual SaveStateLoadError
|
||||
class UnsupportedStateVersion : public SaveStateLoadError
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS( UnsupportedStateVersion, SaveStateLoadError )
|
||||
DEFINE_EXCEPTION_MESSAGES( UnsupportedStateVersion )
|
||||
|
||||
public:
|
||||
u32 Version; // version number of the unsupported state.
|
||||
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( UnsupportedStateVersion )
|
||||
protected:
|
||||
UnsupportedStateVersion() {}
|
||||
|
||||
explicit UnsupportedStateVersion( int version, const wxString& objname=wxEmptyString )
|
||||
public:
|
||||
explicit UnsupportedStateVersion( int version )
|
||||
{
|
||||
StreamName = objname;
|
||||
Version = version;
|
||||
}
|
||||
|
||||
@ -80,18 +83,21 @@ namespace Exception
|
||||
// CRC returned by the Cdvd driver.
|
||||
// [feature not implemented yet]
|
||||
//
|
||||
class StateCrcMismatch : public virtual SaveStateLoadError
|
||||
class StateCrcMismatch : public SaveStateLoadError
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS( StateCrcMismatch, SaveStateLoadError )
|
||||
DEFINE_EXCEPTION_MESSAGES( StateCrcMismatch )
|
||||
|
||||
public:
|
||||
u32 Crc_Savestate;
|
||||
u32 Crc_Cdvd;
|
||||
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( StateCrcMismatch )
|
||||
protected:
|
||||
StateCrcMismatch() {}
|
||||
|
||||
explicit StateCrcMismatch( u32 crc_save, u32 crc_cdvd, const wxString& objname=wxEmptyString )
|
||||
public:
|
||||
StateCrcMismatch( u32 crc_save, u32 crc_cdvd )
|
||||
{
|
||||
StreamName = objname;
|
||||
Crc_Savestate = crc_save;
|
||||
Crc_Cdvd = crc_cdvd;
|
||||
}
|
||||
|
@ -167,8 +167,9 @@ template< typename CpuType >
|
||||
class CpuInitializer
|
||||
{
|
||||
public:
|
||||
ScopedPtr<CpuType> MyCpu;
|
||||
|
||||
ScopedPtr<CpuType> MyCpu;
|
||||
ScopedPtr<BaseException> ExThrown;
|
||||
|
||||
CpuInitializer();
|
||||
virtual ~CpuInitializer() throw();
|
||||
|
||||
@ -199,14 +200,14 @@ CpuInitializer< CpuType >::CpuInitializer()
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
Console.Error( L"CPU provider error:\n\t" + ex.FormatDiagnosticMessage() );
|
||||
if( MyCpu )
|
||||
MyCpu = NULL;
|
||||
MyCpu = NULL;
|
||||
ExThrown = ex.Clone();
|
||||
}
|
||||
catch( std::runtime_error& ex )
|
||||
{
|
||||
Console.Error( L"CPU provider error (STL Exception)\n\tDetails:" + fromUTF8( ex.what() ) );
|
||||
if( MyCpu )
|
||||
MyCpu = NULL;
|
||||
MyCpu = NULL;
|
||||
ExThrown = new Exception::RuntimeError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,9 +254,6 @@ SysCoreAllocations::SysCoreAllocations()
|
||||
|
||||
Console.WriteLn( "Initializing PS2 virtual machine..." );
|
||||
|
||||
m_RecSuccessEE = false;
|
||||
m_RecSuccessIOP = false;
|
||||
|
||||
try
|
||||
{
|
||||
vtlb_Core_Alloc();
|
||||
@ -266,8 +264,7 @@ SysCoreAllocations::SysCoreAllocations()
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::OutOfMemory& ex )
|
||||
{
|
||||
wxString newmsg( ex.UserMsg() + L"\n\n" + GetMemoryErrorVM() );
|
||||
ex.UserMsg() = newmsg;
|
||||
ex.UserMsg() += L"\n\n" + GetMemoryErrorVM();
|
||||
CleanupMess();
|
||||
throw;
|
||||
}
|
||||
@ -278,12 +275,12 @@ SysCoreAllocations::SysCoreAllocations()
|
||||
// re-throw std::bad_alloc as something more friendly. This is needed since
|
||||
// much of the code uses new/delete internally, which throw std::bad_alloc on fail.
|
||||
|
||||
throw Exception::OutOfMemory(
|
||||
L"std::bad_alloc caught while trying to allocate memory for the PS2 Virtual Machine.\n"
|
||||
L"Error Details: " + fromUTF8( ex.what() ),
|
||||
|
||||
GetMemoryErrorVM() // translated
|
||||
);
|
||||
throw Exception::OutOfMemory()
|
||||
.SetDiagMsg(
|
||||
L"std::bad_alloc caught while trying to allocate memory for the PS2 Virtual Machine.\n"
|
||||
L"Error Details: " + fromUTF8( ex.what() )
|
||||
)
|
||||
.SetUserMsg(GetMemoryErrorVM()); // translated
|
||||
}
|
||||
|
||||
Console.WriteLn( "Allocating memory for recompilers..." );
|
||||
@ -292,20 +289,20 @@ SysCoreAllocations::SysCoreAllocations()
|
||||
|
||||
try {
|
||||
recCpu.Allocate();
|
||||
m_RecSuccessEE = true;
|
||||
}
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
m_RecExceptionEE = ex.Clone();
|
||||
Console.Error( L"EE Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
|
||||
recCpu.Shutdown();
|
||||
}
|
||||
|
||||
try {
|
||||
psxRec.Allocate();
|
||||
m_RecSuccessIOP = true;
|
||||
}
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
m_RecExceptionIOP = ex.Clone();
|
||||
Console.Error( L"IOP Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
|
||||
psxRec.Shutdown();
|
||||
}
|
||||
@ -320,9 +317,13 @@ SysCoreAllocations::SysCoreAllocations()
|
||||
|
||||
bool SysCoreAllocations::IsRecAvailable_MicroVU0() const { return CpuProviders->microVU0.IsAvailable(); }
|
||||
bool SysCoreAllocations::IsRecAvailable_MicroVU1() const { return CpuProviders->microVU1.IsAvailable(); }
|
||||
BaseException* SysCoreAllocations::GetException_MicroVU0() const { return CpuProviders->microVU0.ExThrown; }
|
||||
BaseException* SysCoreAllocations::GetException_MicroVU1() const { return CpuProviders->microVU1.ExThrown; }
|
||||
|
||||
bool SysCoreAllocations::IsRecAvailable_SuperVU0() const { return CpuProviders->superVU0.IsAvailable(); }
|
||||
bool SysCoreAllocations::IsRecAvailable_SuperVU1() const { return CpuProviders->superVU1.IsAvailable(); }
|
||||
BaseException* SysCoreAllocations::GetException_SuperVU0() const { return CpuProviders->superVU0.ExThrown; }
|
||||
BaseException* SysCoreAllocations::GetException_SuperVU1() const { return CpuProviders->superVU1.ExThrown; }
|
||||
|
||||
|
||||
void SysCoreAllocations::CleanupMess() throw()
|
||||
|
@ -31,8 +31,8 @@ class SysCoreAllocations
|
||||
protected:
|
||||
ScopedPtr<CpuInitializerSet> CpuProviders;
|
||||
|
||||
bool m_RecSuccessEE:1;
|
||||
bool m_RecSuccessIOP:1;
|
||||
ScopedPtr<BaseException> m_RecExceptionEE;
|
||||
ScopedPtr<BaseException> m_RecExceptionIOP;
|
||||
|
||||
public:
|
||||
SysCoreAllocations();
|
||||
@ -42,14 +42,21 @@ public:
|
||||
|
||||
bool HadSomeFailures( const Pcsx2Config::RecompilerOptions& recOpts ) const;
|
||||
|
||||
bool IsRecAvailable_EE() const { return m_RecSuccessEE; }
|
||||
bool IsRecAvailable_IOP() const { return m_RecSuccessIOP; }
|
||||
bool IsRecAvailable_EE() const { return !m_RecExceptionEE; }
|
||||
bool IsRecAvailable_IOP() const { return !m_RecExceptionIOP; }
|
||||
|
||||
BaseException* GetException_EE() const { return m_RecExceptionEE; }
|
||||
BaseException* GetException_IOP() const { return m_RecExceptionIOP; }
|
||||
|
||||
bool IsRecAvailable_MicroVU0() const;
|
||||
bool IsRecAvailable_MicroVU1() const;
|
||||
BaseException* GetException_MicroVU0() const;
|
||||
BaseException* GetException_MicroVU1() const;
|
||||
|
||||
bool IsRecAvailable_SuperVU0() const;
|
||||
bool IsRecAvailable_SuperVU1() const;
|
||||
BaseException* GetException_SuperVU0() const;
|
||||
BaseException* GetException_SuperVU1() const;
|
||||
|
||||
protected:
|
||||
void CleanupMess() throw();
|
||||
|
@ -81,7 +81,8 @@ void SysThreadBase::OnStart()
|
||||
//
|
||||
void SysThreadBase::Suspend( bool isBlocking )
|
||||
{
|
||||
if( IsSelf() || !IsRunning() ) return;
|
||||
if (!pxAssertDev(!IsSelf(),"Suspend/Resume are not allowed from this thread.")) return;
|
||||
if (!IsRunning()) return;
|
||||
|
||||
// shortcut ExecMode check to avoid deadlocking on redundant calls to Suspend issued
|
||||
// from Resume or OnResumeReady code.
|
||||
@ -98,7 +99,7 @@ void SysThreadBase::Suspend( bool isBlocking )
|
||||
case ExecMode_Pausing:
|
||||
case ExecMode_Paused:
|
||||
if( !isBlocking )
|
||||
throw Exception::CancelEvent( "Cannot suspend in non-blocking fashion: Another thread is pausing the VM state." );
|
||||
throw Exception::CancelEvent( L"Cannot suspend in non-blocking fashion: Another thread is pausing the VM state." );
|
||||
|
||||
m_ExecMode = ExecMode_Closing;
|
||||
m_sem_Resume.Post();
|
||||
@ -182,7 +183,7 @@ void SysThreadBase::Resume()
|
||||
{
|
||||
Start();
|
||||
if( !m_running || (m_ExecMode == ExecMode_NoThreadYet) )
|
||||
throw Exception::ThreadCreationError();
|
||||
throw Exception::ThreadCreationError(this);
|
||||
if( m_ExecMode == ExecMode_Opened ) return;
|
||||
}
|
||||
// fall through...
|
||||
|
@ -31,9 +31,9 @@ void vuMicroMemAlloc()
|
||||
m_vuAllMem = vtlb_malloc( m_vuMemSize, 16 );
|
||||
|
||||
if( m_vuAllMem == NULL )
|
||||
throw Exception::OutOfMemory( "vuMicroMemInit > Failed to allocate VUmicro memory." );
|
||||
throw Exception::OutOfMemory( L"VU0 and VU1 on-chip memory" );
|
||||
|
||||
jASSUME( sizeof( VURegs ) <= 0x800 );
|
||||
pxAssume( sizeof( VURegs ) <= 0x800 );
|
||||
|
||||
u8* curpos = m_vuAllMem;
|
||||
VU0.Micro = curpos; curpos += 0x1000;
|
||||
@ -55,8 +55,8 @@ void vuMicroMemShutdown()
|
||||
|
||||
void vuMicroMemReset()
|
||||
{
|
||||
jASSUME( VU0.Mem != NULL );
|
||||
jASSUME( VU1.Mem != NULL );
|
||||
pxAssume( VU0.Mem != NULL );
|
||||
pxAssume( VU1.Mem != NULL );
|
||||
|
||||
memMapVUmicro();
|
||||
|
||||
@ -107,8 +107,8 @@ void SaveStateBase::vuMicroFreeze()
|
||||
{
|
||||
FreezeTag( "vuMicro" );
|
||||
|
||||
jASSUME( VU0.Mem != NULL );
|
||||
jASSUME( VU1.Mem != NULL );
|
||||
pxAssume( VU0.Mem != NULL );
|
||||
pxAssume( VU1.Mem != NULL );
|
||||
|
||||
Freeze(VU0.ACC);
|
||||
Freeze(VU0.code);
|
||||
|
@ -58,7 +58,7 @@ CompressThread_gzip::~CompressThread_gzip() throw()
|
||||
void CompressThread_gzip::Write( const void* data, size_t size )
|
||||
{
|
||||
if( gzwrite( m_gzfp, data, size ) == 0 )
|
||||
throw Exception::BadStream( m_filename, "Write to zip file failed." );
|
||||
throw Exception::BadStream( m_filename ).SetDiagMsg(L"Write to zip file failed.");
|
||||
}
|
||||
|
||||
void CompressThread_gzip::ExecuteTaskInThread()
|
||||
@ -104,7 +104,9 @@ void CompressThread_gzip::ExecuteTaskInThread()
|
||||
m_gzfp = NULL;
|
||||
|
||||
if( !wxRenameFile( tempfile, m_filename, true ) )
|
||||
throw Exception::BadStream( m_filename, "Failed to move or copy the temporary archive to the destination filename." );
|
||||
throw Exception::BadStream( m_filename )
|
||||
.SetDiagMsg(L"Failed to move or copy the temporary archive to the destination filename.")
|
||||
.SetUserMsg(_("The savestate was not properly saved. The temporary file was created successfully but could not be moved to its final resting place."));
|
||||
|
||||
Console.WriteLn( "(gzipThread) Data saved to disk without error." );
|
||||
}
|
||||
|
@ -154,15 +154,14 @@ namespace Exception
|
||||
// Exception used to perform an "errorless" termination of the app during OnInit
|
||||
// procedures. This happens when a user cancels out of startup prompts/wizards.
|
||||
//
|
||||
class StartupAborted : public BaseException
|
||||
class StartupAborted : public CancelEvent
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( StartupAborted )
|
||||
DEFINE_RUNTIME_EXCEPTION( StartupAborted, CancelEvent, "Startup initialization was aborted by the user." )
|
||||
|
||||
StartupAborted( const wxString& msg_eng=L"Startup initialization was aborted by the user." )
|
||||
public:
|
||||
StartupAborted( const wxString& reason )
|
||||
{
|
||||
// english messages only for this exception.
|
||||
BaseException::InitBaseEx( msg_eng, msg_eng );
|
||||
m_message_diag = L"Startup aborted: " + reason;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -755,7 +755,7 @@ void AppConfig_OnChangedSettingsFolder( bool overwrite )
|
||||
if( overwrite )
|
||||
{
|
||||
if( wxFileExists( iniFilename ) && !wxRemoveFile( iniFilename ) )
|
||||
throw Exception::AccessDenied( "Failed to overwrite settings; permission to file was denied." );
|
||||
throw Exception::AccessDenied(iniFilename).SetBothMsgs(wxLt("Failed to overwrite existing settings file; permission was denied."));
|
||||
}
|
||||
|
||||
// Bind into wxConfigBase to allow wx to use our config internally, and delete whatever
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "CDVD/CDVD.h"
|
||||
#include "Elfheader.h"
|
||||
#include "Patch.h"
|
||||
#include "R5900Exceptions.h"
|
||||
|
||||
__aligned16 SysMtgsThread mtgsThread;
|
||||
__aligned16 AppCoreThread CoreThread;
|
||||
@ -108,7 +109,13 @@ static void _Suspend()
|
||||
|
||||
void AppCoreThread::Suspend( bool isBlocking )
|
||||
{
|
||||
if( !GetSysExecutorThread().ProcessMethodSelf( _Suspend ) )
|
||||
if (IsSelf())
|
||||
{
|
||||
// this should never fail...
|
||||
bool result = GetSysExecutorThread().Rpc_TryInvokeAsync( _Suspend );
|
||||
pxAssert(result);
|
||||
}
|
||||
else if (!GetSysExecutorThread().Rpc_TryInvoke( _Suspend ))
|
||||
_parent::Suspend(true);
|
||||
}
|
||||
|
||||
@ -392,12 +399,44 @@ void AppCoreThread::UploadStateCopy( const VmStateBuffer& copy )
|
||||
paused_core.AllowResume();
|
||||
}
|
||||
|
||||
static uint m_except_threshold = 0;
|
||||
|
||||
void AppCoreThread::ExecuteTaskInThread()
|
||||
{
|
||||
PostCoreStatus( CoreThread_Started );
|
||||
m_except_threshold = 0;
|
||||
_parent::ExecuteTaskInThread();
|
||||
}
|
||||
|
||||
void AppCoreThread::DoCpuExecute()
|
||||
{
|
||||
try {
|
||||
_parent::DoCpuExecute();
|
||||
}
|
||||
catch (BaseR5900Exception& ex)
|
||||
{
|
||||
Console.Error( ex.FormatMessage() );
|
||||
|
||||
// [TODO] : Debugger Hook!
|
||||
|
||||
if( ++m_except_threshold > 6 )
|
||||
{
|
||||
// If too many TLB Misses occur, we're probably going to crash and
|
||||
// the game is probably running miserably.
|
||||
|
||||
m_except_threshold = 0;
|
||||
//Suspend();
|
||||
|
||||
// [TODO] Issue error dialog to the user here...
|
||||
Console.Error( "Too many execution errors. VM execution has been suspended!" );
|
||||
|
||||
// Hack: this keeps the EE thread from running more code while the SysExecutor
|
||||
// thread catches up and signals it for suspension.
|
||||
m_ExecMode = ExecMode_Closing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseSysExecEvent_ScopedCore / SysExecEvent_CoreThreadClose / SysExecEvent_CoreThreadPause
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -142,6 +142,8 @@ public:
|
||||
virtual void UploadStateCopy( const VmStateBuffer& copy );
|
||||
|
||||
protected:
|
||||
virtual void DoCpuExecute();
|
||||
|
||||
virtual void OnResumeReady();
|
||||
virtual void OnResumeInThread( bool IsSuspended );
|
||||
virtual void OnSuspendInThread();
|
||||
|
@ -48,8 +48,7 @@ protected:
|
||||
public:
|
||||
AppGameDatabase() {}
|
||||
virtual ~AppGameDatabase() throw() {
|
||||
// deque deletes its contents automatically.
|
||||
Console.WriteLn( "(GameDB) Destroying..." );
|
||||
Console.WriteLn( "(GameDB) Unloading..." );
|
||||
}
|
||||
|
||||
AppGameDatabase& LoadFromFile(const wxString& file = L"GameIndex.dbf", const wxString& key = L"Serial" );
|
||||
|
@ -138,7 +138,7 @@ void Pcsx2App::ReadUserModeSettings()
|
||||
// first time startup, so give the user the choice of user mode:
|
||||
FirstTimeWizard wiz( NULL );
|
||||
if( !wiz.RunWizard( wiz.GetUsermodePage() ) )
|
||||
throw Exception::StartupAborted( L"Startup aborted: User canceled FirstTime Wizard." );
|
||||
throw Exception::StartupAborted( L"User canceled FirstTime Wizard." );
|
||||
|
||||
// Save user's new settings
|
||||
IniSaver saver( *conf_usermode );
|
||||
@ -166,7 +166,7 @@ void Pcsx2App::ReadUserModeSettings()
|
||||
// If we skip this check, it's very likely that actions like creating Memory Cards will fail.
|
||||
FirstTimeWizard wiz( NULL );
|
||||
if( !wiz.RunWizard( /*wiz.GetPostUsermodePage()*/ wiz.GetUsermodePage() ) )
|
||||
throw Exception::StartupAborted( L"Startup aborted: User canceled Configuration Wizard." );
|
||||
throw Exception::StartupAborted( L"User canceled Configuration Wizard." );
|
||||
|
||||
// Save user's new settings
|
||||
IniSaver saver( *conf_usermode );
|
||||
@ -193,7 +193,9 @@ void Pcsx2App::DetectCpuAndUserMode()
|
||||
{
|
||||
// Note: due to memcpy_fast, we need minimum MMX even for interpreters. This will
|
||||
// hopefully change later once we have a dynamically recompiled memcpy.
|
||||
throw Exception::HardwareDeficiency(L"MMX Extensions not available.", _("PCSX2 requires cpu with MMX instruction to run."));
|
||||
throw Exception::HardwareDeficiency()
|
||||
.SetDiagMsg(L"Critical Failure: MMX Extensions not available.")
|
||||
.SetUserMsg(_("MMX extensions are not available. PCSX2 requires cpu with MMX extension support to run."));
|
||||
}
|
||||
|
||||
ReadUserModeSettings();
|
||||
@ -260,8 +262,8 @@ void Pcsx2App::AllocateCoreStuffs()
|
||||
wxDialogWithHelpers exconf( NULL, _("PCSX2 Recompiler Error(s)") );
|
||||
|
||||
exconf += 12;
|
||||
exconf += exconf.Heading( pxE( ".Popup:RecompilerInit",
|
||||
L"Warning: Some of the configured PS2 recompilers failed to initialize and will not be available for this session:\n" )
|
||||
exconf += exconf.Heading( pxE( ".Popup:RecompilerInit:Header",
|
||||
L"Warning: Some of the configured PS2 recompilers failed to initialize and have been disabled:" )
|
||||
);
|
||||
|
||||
wxTextCtrl* scrollableTextArea = new wxTextCtrl(
|
||||
@ -269,63 +271,55 @@ void Pcsx2App::AllocateCoreStuffs()
|
||||
wxTE_READONLY | wxTE_MULTILINE | wxTE_WORDWRAP
|
||||
);
|
||||
|
||||
exconf += scrollableTextArea | pxSizerFlags::StdExpand();
|
||||
exconf += 6;
|
||||
exconf += scrollableTextArea | pxExpand.Border(wxALL, 16);
|
||||
|
||||
if( !m_CoreAllocs->IsRecAvailable_EE() )
|
||||
if( BaseException* ex = m_CoreAllocs->GetException_EE() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* R5900 (EE)\n\n" );
|
||||
|
||||
g_Conf->EmuOptions.Recompiler.EnableEE = false;
|
||||
scrollableTextArea->AppendText( L"* R5900 (EE)\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
|
||||
g_Conf->EmuOptions.Recompiler.EnableEE = false;
|
||||
}
|
||||
|
||||
if( !m_CoreAllocs->IsRecAvailable_IOP() )
|
||||
if( BaseException* ex = m_CoreAllocs->GetException_IOP() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* R3000A (IOP)\n\n" );
|
||||
g_Conf->EmuOptions.Recompiler.EnableIOP = false;
|
||||
scrollableTextArea->AppendText( L"* R3000A (IOP)\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
|
||||
g_Conf->EmuOptions.Recompiler.EnableIOP = false;
|
||||
}
|
||||
|
||||
if( !m_CoreAllocs->IsRecAvailable_MicroVU0() ) {
|
||||
scrollableTextArea->AppendText( L"* microVU0\n\n" );
|
||||
if( BaseException* ex = m_CoreAllocs->GetException_MicroVU0() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* microVU0\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
|
||||
g_Conf->EmuOptions.Recompiler.UseMicroVU0 = false;
|
||||
g_Conf->EmuOptions.Recompiler.EnableVU0 = g_Conf->EmuOptions.Recompiler.EnableVU0 && m_CoreAllocs->IsRecAvailable_SuperVU0();
|
||||
}
|
||||
|
||||
if( !m_CoreAllocs->IsRecAvailable_MicroVU1() )
|
||||
if( BaseException* ex = m_CoreAllocs->GetException_MicroVU1() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* microVU1\n\n" );
|
||||
scrollableTextArea->AppendText( L"* microVU1\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
|
||||
g_Conf->EmuOptions.Recompiler.UseMicroVU1 = false;
|
||||
g_Conf->EmuOptions.Recompiler.EnableVU1 = g_Conf->EmuOptions.Recompiler.EnableVU1 && m_CoreAllocs->IsRecAvailable_SuperVU1();
|
||||
}
|
||||
|
||||
if( !m_CoreAllocs->IsRecAvailable_SuperVU0() )
|
||||
if( BaseException* ex = m_CoreAllocs->GetException_SuperVU0() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* SuperVU0\n\n" );
|
||||
scrollableTextArea->AppendText( L"* SuperVU0\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
|
||||
g_Conf->EmuOptions.Recompiler.UseMicroVU0 = m_CoreAllocs->IsRecAvailable_MicroVU0();
|
||||
g_Conf->EmuOptions.Recompiler.EnableVU0 = g_Conf->EmuOptions.Recompiler.EnableVU0 && g_Conf->EmuOptions.Recompiler.UseMicroVU0;
|
||||
}
|
||||
|
||||
if( !m_CoreAllocs->IsRecAvailable_SuperVU1() )
|
||||
if( BaseException* ex = m_CoreAllocs->GetException_SuperVU1() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* SuperVU1\n\n" );
|
||||
scrollableTextArea->AppendText( L"* SuperVU1\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
|
||||
g_Conf->EmuOptions.Recompiler.UseMicroVU1 = m_CoreAllocs->IsRecAvailable_MicroVU1();
|
||||
g_Conf->EmuOptions.Recompiler.EnableVU1 = g_Conf->EmuOptions.Recompiler.EnableVU1 && g_Conf->EmuOptions.Recompiler.UseMicroVU1;
|
||||
}
|
||||
|
||||
exconf += new ModalButtonPanel( &exconf, MsgButtons().OK() ) | pxSizerFlags::StdCenter();
|
||||
exconf += exconf.Heading( pxE(".Popup:RecompilerInit:Footer",
|
||||
L"Note: Recompilers are not necessary for PCSX2 to run, however they typically improve emulation speed substantially. "
|
||||
L"You may have to manually re-enable the recompilers listed above, if you resolve the errors." )
|
||||
);
|
||||
|
||||
exconf.ShowModal();
|
||||
|
||||
// Failures can be SSE-related OR memory related. Should do per-cpu error reports instead...
|
||||
|
||||
/*message += pxE( ".Popup Error:EmuCore:MemoryForRecs",
|
||||
L"These errors are the result of memory allocation failures (see the program log for details). "
|
||||
L"Closing out some memory hogging background tasks may resolve this error.\n\n"
|
||||
L"These recompilers have been disabled and interpreters will be used in their place. "
|
||||
L"Interpreters can be very slow, so don't get too excited. Press OK to continue or CANCEL to close PCSX2."
|
||||
);*/
|
||||
|
||||
//if( !Msgbox::OkCancel( message, _("PCSX2 Initialization Error"), wxICON_ERROR ) )
|
||||
// return false;
|
||||
pxIssueConfirmation( exconf, MsgButtons().OK() );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,33 +37,28 @@ namespace Exception
|
||||
//
|
||||
class CannotApplySettings : public BaseException
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS( CannotApplySettings, BaseException )
|
||||
DEFINE_EXCEPTION_MESSAGES( CannotApplySettings )
|
||||
|
||||
public:
|
||||
bool IsVerbose;
|
||||
bool IsVerbose;
|
||||
|
||||
protected:
|
||||
BaseApplicableConfigPanel* m_Panel;
|
||||
BaseApplicableConfigPanel* m_Panel;
|
||||
|
||||
protected:
|
||||
CannotApplySettings() { IsVerbose = true; }
|
||||
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( CannotApplySettings )
|
||||
|
||||
explicit CannotApplySettings( BaseApplicableConfigPanel* thispanel, const char* msg=wxLt("Cannot apply new settings, one of the settings is invalid."), bool isVerbose = true )
|
||||
explicit CannotApplySettings( BaseApplicableConfigPanel* thispanel )
|
||||
{
|
||||
BaseException::InitBaseEx( msg );
|
||||
m_Panel = thispanel;
|
||||
IsVerbose = isVerbose;
|
||||
}
|
||||
|
||||
explicit CannotApplySettings( BaseApplicableConfigPanel* thispanel, const wxString& msg_eng, const wxString& msg_xlt )
|
||||
{
|
||||
BaseException::InitBaseEx( msg_eng, msg_xlt );
|
||||
SetBothMsgs(wxLt("Cannot apply new settings, one of the settings is invalid."));
|
||||
m_Panel = thispanel;
|
||||
IsVerbose = true;
|
||||
}
|
||||
|
||||
BaseApplicableConfigPanel* GetPanel()
|
||||
{
|
||||
return m_Panel;
|
||||
}
|
||||
virtual CannotApplySettings& Quiet() { IsVerbose = false; return *this; }
|
||||
BaseApplicableConfigPanel* GetPanel() { return m_Panel; }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ CpuUsageProviderMSW::CpuUsageProviderMSW()
|
||||
throw Exception::RuntimeError( "(CpuUsageProviderMSW) CoInitializeSecurity failed: No good security packages! .. whatever tht means." );
|
||||
|
||||
case E_OUTOFMEMORY:
|
||||
throw Exception::OutOfMemory( "(CpuUsageProviderMSW) Out of Memory error returned during call to CoInitializeSecurity." );
|
||||
throw Exception::OutOfMemory( L"(CpuUsageProviderMSW) Out of Memory error returned during call to CoInitializeSecurity." );
|
||||
|
||||
default:
|
||||
throw Exception::RuntimeError( wxsFormat( L"(CpuUsageProviderMSW) CoInitializeSecurity failed with an unknown error code: %d", hr ), wxEmptyString );
|
||||
@ -221,7 +221,7 @@ void CpuUsageProviderMSW::UpdateStats()
|
||||
break;
|
||||
|
||||
case WBEM_E_OUT_OF_MEMORY:
|
||||
throw Exception::OutOfMemory( "(CpuUsageProviderMSW) Out of Memory Enumerating WMI Object." );
|
||||
throw Exception::OutOfMemory( L"(CpuUsageProviderMSW) Out of Memory Enumerating WMI Object." );
|
||||
|
||||
default:
|
||||
throw Exception::RuntimeError( wxsFormat( L"(CpuUsageProviderMSW) WMI Object Enumeration failed with an unknown error code: %d", hRes ), wxEmptyString );
|
||||
|
@ -104,14 +104,13 @@ bool FirstTimeWizard::UsermodePage::PrepForApply()
|
||||
if( path.FileExists() )
|
||||
{
|
||||
// FIXME: There's already a file by the same name.. not sure what we should do here.
|
||||
throw Exception::BadStream( path.ToString(),
|
||||
L"Targeted documents folder is already occupied by a file.",
|
||||
pxE( ".Error:DocsFolderFileConflict",
|
||||
throw Exception::BadStream( path.ToString() )
|
||||
.SetDiagMsg(L"Targeted documents folder is already occupied by a file.")
|
||||
.SetUserMsg(pxE( ".Error:DocsFolderFileConflict",
|
||||
L"PCSX2 cannot create a documents folder in the requested location. "
|
||||
L"The path name matches an existing file. Delete the file or change the documents location, "
|
||||
L"and then try again."
|
||||
)
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
if( !path.Exists() )
|
||||
|
@ -308,7 +308,18 @@ void pxEvtHandler::ProcessEvent( SysExecEvent* evt )
|
||||
}
|
||||
}
|
||||
|
||||
bool pxEvtHandler::ProcessMethodSelf( FnType_Void* method )
|
||||
bool pxEvtHandler::Rpc_TryInvokeAsync( FnType_Void* method )
|
||||
{
|
||||
if( wxThread::GetCurrentId() != m_OwnerThreadId )
|
||||
{
|
||||
PostEvent( new SysExecEvent_MethodVoid(method) );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pxEvtHandler::Rpc_TryInvoke( FnType_Void* method )
|
||||
{
|
||||
if( wxThread::GetCurrentId() != m_OwnerThreadId )
|
||||
{
|
||||
|
@ -47,7 +47,6 @@ void GSPanel::InitDefaultAccelerators()
|
||||
m_Accels->Map( AAC( WXK_F8 ).Shift(), "Sys_TakeSnapshot");
|
||||
m_Accels->Map( AAC( WXK_F8 ).Shift().Cmd(), "Sys_TakeSnapshot");
|
||||
m_Accels->Map( AAC( WXK_F9 ), "Sys_RenderswitchToggle");
|
||||
m_Accels->Map( AAC( WXK_F9 ), "Sys_RenderswitchToggle" );
|
||||
|
||||
//m_Accels->Map( AAC( WXK_F10 ), "Sys_LoggingToggle" );
|
||||
m_Accels->Map( AAC( WXK_F11 ), "Sys_FreezeGS" );
|
||||
|
@ -121,16 +121,12 @@ void Panels::BiosSelectorPanel::Apply()
|
||||
int sel = m_ComboBox->GetSelection();
|
||||
if( sel == wxNOT_FOUND )
|
||||
{
|
||||
throw Exception::CannotApplySettings( this,
|
||||
// English Log
|
||||
L"User did not specify a valid BIOS selection.",
|
||||
|
||||
// Translated
|
||||
pxE( ".Error:BIOS:InvalidSelection",
|
||||
throw Exception::CannotApplySettings(this)
|
||||
.SetDiagMsg(L"User did not specify a valid BIOS selection.")
|
||||
.SetUserMsg( pxE( ".Error:BIOS:InvalidSelection",
|
||||
L"Please select a valid BIOS. If you are unable to make a valid selection "
|
||||
L"then press cancel to close the Configuration panel."
|
||||
)
|
||||
);
|
||||
) );
|
||||
}
|
||||
|
||||
g_Conf->BaseFilenames.Bios = (*m_BiosList)[(int)m_ComboBox->GetClientData(sel)];
|
||||
|
@ -142,10 +142,9 @@ void Panels::GSWindowSettingsPanel::Apply()
|
||||
long xr, yr;
|
||||
|
||||
if( !m_text_WindowWidth->GetValue().ToLong( &xr ) || !m_text_WindowHeight->GetValue().ToLong( &yr ) )
|
||||
throw Exception::CannotApplySettings( this,
|
||||
L"User submitted non-numeric window size parameters!",
|
||||
_("Invalid window dimensions specified: Size cannot contain non-numeric digits! >_<")
|
||||
);
|
||||
throw Exception::CannotApplySettings( this )
|
||||
.SetDiagMsg(L"User submitted non-numeric window size parameters!")
|
||||
.SetUserMsg(_("Invalid window dimensions specified: Size cannot contain non-numeric digits! >_<"));
|
||||
|
||||
appconf.WindowSize.x = xr;
|
||||
appconf.WindowSize.y = yr;
|
||||
|
@ -58,7 +58,7 @@ namespace Exception
|
||||
class NotEnumerablePlugin : public BadStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, wxLt("File is not a PCSX2 plugin") );
|
||||
DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, BadStream, wxLt("File is not a PCSX2 plugin") );
|
||||
};
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ public:
|
||||
: m_plugpath( plugpath )
|
||||
{
|
||||
if( !m_plugin.Load( m_plugpath ) )
|
||||
throw Exception::BadStream( m_plugpath, "File is not a valid dynamic library." );
|
||||
throw Exception::BadStream( m_plugpath ).SetBothMsgs("File is not a valid dynamic library.");
|
||||
|
||||
wxDoNotLogInThisScope please;
|
||||
m_GetLibType = (_PS2EgetLibType)m_plugin.GetSymbol( L"PS2EgetLibType" );
|
||||
@ -241,7 +241,8 @@ void ApplyOverValidStateEvent::InvokeEvent()
|
||||
int result = pxIssueConfirmation( dialog, MsgButtons().OK().Cancel(), L"PluginSelector:ConfirmShutdown" );
|
||||
|
||||
if( result == wxID_CANCEL )
|
||||
throw Exception::CannotApplySettings( m_owner->GetApplicableConfigPanel(), "Cannot apply settings: canceled by user because plugins changed while the emulation state was active.", false );
|
||||
throw Exception::CannotApplySettings( m_owner->GetApplicableConfigPanel() ).Quiet()
|
||||
.SetDiagMsg(L"Cannot apply settings: canceled by user because plugins changed while the emulation state was active.");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
@ -465,13 +466,9 @@ void Panels::PluginSelectorPanel::Apply()
|
||||
{
|
||||
wxString plugname( pi->GetShortname() );
|
||||
|
||||
throw Exception::CannotApplySettings( this,
|
||||
// English Log
|
||||
wxsFormat( L"PluginSelectorPanel: Invalid or missing selection for the %s plugin.", plugname.c_str() ),
|
||||
|
||||
// Translated
|
||||
wxsFormat( L"Please select a valid plugin for the %s.", plugname.c_str() ) + L"\n\n" + GetApplyFailedMsg()
|
||||
);
|
||||
throw Exception::CannotApplySettings( this )
|
||||
.SetDiagMsg(wxsFormat( L"PluginSelectorPanel: Invalid or missing selection for the %s plugin.", plugname.c_str()) )
|
||||
.SetUserMsg(wxsFormat( L"Please select a valid plugin for the %s.", plugname.c_str() ) + L"\n\n" + GetApplyFailedMsg() );
|
||||
}
|
||||
|
||||
g_Conf->BaseFilenames.Plugins[pid] = GetFilename((int)m_ComponentBoxes->Get(pid).GetClientData(sel));
|
||||
@ -498,7 +495,7 @@ void Panels::PluginSelectorPanel::Apply()
|
||||
try
|
||||
{
|
||||
if( wxID_CANCEL == ApplyPluginsDialog( this ).ShowModal() )
|
||||
throw Exception::CannotApplySettings( this, "User canceled plugin load process.", false );
|
||||
throw Exception::CannotApplySettings( this ).Quiet().SetDiagMsg(L"User canceled plugin load process.");
|
||||
}
|
||||
catch( Exception::PluginError& ex )
|
||||
{
|
||||
@ -506,15 +503,12 @@ void Panels::PluginSelectorPanel::Apply()
|
||||
|
||||
wxString plugname( tbl_PluginInfo[ex.PluginId].GetShortname() );
|
||||
|
||||
throw Exception::CannotApplySettings( this,
|
||||
// Diagnostic
|
||||
ex.FormatDiagnosticMessage(),
|
||||
|
||||
// Translated
|
||||
wxsFormat( _("The selected %s plugin failed to load.\n\nReason: %s\n\n"),
|
||||
throw Exception::CannotApplySettings( this )
|
||||
.SetDiagMsg(ex.FormatDiagnosticMessage())
|
||||
.SetUserMsg(wxsFormat(
|
||||
_("The selected %s plugin failed to load.\n\nReason: %s\n\n"),
|
||||
plugname.c_str(), ex.FormatDisplayMessage().c_str()
|
||||
) + GetApplyFailedMsg()
|
||||
);
|
||||
) + GetApplyFailedMsg());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,9 +144,12 @@ void Panels::FramelimiterPanel::Apply()
|
||||
}
|
||||
catch( Exception::ParseError& )
|
||||
{
|
||||
throw Exception::CannotApplySettings( this,
|
||||
wxLt("Error while parsing either NTSC or PAL framerate settings. Settings must be valid floating point numerics.")
|
||||
);
|
||||
throw Exception::CannotApplySettings( this )
|
||||
.SetDiagMsg(wxsFormat(
|
||||
L"Error while parsing either NTSC or PAL framerate settings.\n\tNTSC Input = %s\n\tPAL Input = %s",
|
||||
m_text_BaseNtsc->GetValue(), m_text_BasePal->GetValue()
|
||||
) )
|
||||
.SetUserMsg(_("Error while parsing either NTSC or PAL framerate settings. Settings must be valid floating point numerics."));
|
||||
}
|
||||
|
||||
appfps.SanityCheck();
|
||||
|
@ -40,25 +40,41 @@ static void SaveStateFile_ReadHeader( IStreamReader& thr )
|
||||
thr.Read( ident );
|
||||
|
||||
if( strcmp(SavestateIdentString, ident) )
|
||||
throw Exception::SaveStateLoadError( thr.GetStreamName(),
|
||||
wxsFormat( L"Unrecognized file signature while loading savestate: %s", ident ),
|
||||
_("File is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2.")
|
||||
);
|
||||
throw Exception::SaveStateLoadError( thr.GetStreamName() )
|
||||
.SetDiagMsg(wxsFormat( L"Unrecognized file signature while loading savestate. [sig = %s]", ident ))
|
||||
.SetUserMsg(_("This is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2."));
|
||||
|
||||
u32 savever;
|
||||
thr.Read( savever );
|
||||
|
||||
if( (savever >> 16) != (g_SaveVersion >> 16) )
|
||||
throw Exception::SaveStateLoadError( thr.GetStreamName(),
|
||||
wxsFormat( L"Unrecognized file signature while loading savestate: %s", ident ),
|
||||
_("File is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2.")
|
||||
);
|
||||
|
||||
// Major version mismatch. Means we can't load this savestate at all. Support for it
|
||||
// was removed entirely.
|
||||
if( savever > g_SaveVersion )
|
||||
throw Exception::SaveStateLoadError( thr.GetStreamName(),
|
||||
wxsFormat( L"Unrecognized file signature while loading savestate: %s", ident ),
|
||||
_("File is not a valid PCSX2 savestate, or is from an older unsupported version of PCSX2.")
|
||||
);
|
||||
throw Exception::SaveStateLoadError( thr.GetStreamName() )
|
||||
.SetDiagMsg(wxsFormat( L"Savestate uses an unsupported or unknown savestate version.\n(PCSX2 ver=%d, state ver=%d)", g_SaveVersion, savever ))
|
||||
.SetUserMsg(_("Cannot load this savestate. The state is from an incompatible edition of PCSX2 that is either newer than this version, or is no longer supported."));
|
||||
|
||||
// check for a "minor" version incompatibility; which happens if the savestate being loaded is a newer version
|
||||
// than the emulator recognizes. 99% chance that trying to load it will just corrupt emulation or crash.
|
||||
if( (savever >> 16) != (g_SaveVersion >> 16) )
|
||||
throw Exception::SaveStateLoadError( thr.GetStreamName() )
|
||||
.SetDiagMsg(wxsFormat( L"Savestate uses an unknown (future?!) savestate version.\n(PCSX2 ver=%d, state ver=%d)", g_SaveVersion, savever ))
|
||||
.SetUserMsg(_("Cannot load this savestate. The state is an unsupported version, likely created by a newer edition of PCSX2."));
|
||||
};
|
||||
|
||||
class gzError : public Exception::BadStream
|
||||
{
|
||||
DEFINE_STREAM_EXCEPTION( gzError, BadStream, wxLt("Invalid or corrupted gzip archive") )
|
||||
};
|
||||
|
||||
class gzReadError : public gzError
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
class gzWriteError : public gzError
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
@ -79,7 +95,7 @@ public:
|
||||
: m_filename( filename )
|
||||
{
|
||||
if( NULL == (m_gzfp = gzopen( m_filename.ToUTF8(), "rb" )) )
|
||||
throw Exception::CannotCreateStream( m_filename, "Cannot open file for reading." );
|
||||
throw Exception::CannotCreateStream( m_filename ).SetDiagMsg(L"Cannot open file for reading.");
|
||||
|
||||
#if defined(ZLIB_VERNUM) && (ZLIB_VERNUM >= 0x1240)
|
||||
gzbuffer(m_gzfp, 0x100000); // 1mb buffer for zlib internal operations
|
||||
@ -97,7 +113,8 @@ public:
|
||||
{
|
||||
int result = gzread( m_gzfp, dest, size );
|
||||
if( result == -1)
|
||||
throw Exception::BadStream( m_filename, "Data read failed: Invalid or corrupted gzip archive." );
|
||||
//throw Exception::gzError( m_filename );
|
||||
throw Exception::BadStream( m_filename ).SetBothMsgs(wxLt("Data read failed: Invalid or corrupted gzip archive."));
|
||||
|
||||
if( (size_t)result < size )
|
||||
throw Exception::EndOfStream( m_filename );
|
||||
@ -136,7 +153,9 @@ protected:
|
||||
ScopedCoreThreadPause paused_core;
|
||||
|
||||
if( !SysHasValidState() )
|
||||
throw Exception::RuntimeError( L"Cannot complete state freeze request; the virtual machine state is reset.", _("You'll need to start a new virtual machine before you can save its state.") );
|
||||
throw Exception::RuntimeError()
|
||||
.SetDiagMsg(L"SysExecEvent_DownloadState: Cannot freeze/download an invalid VM state!")
|
||||
.SetUserMsg(L"There is no active virtual machine state to download or save." );
|
||||
|
||||
memSavingState(m_dest_buffer).FreezeAll();
|
||||
|
||||
|
@ -191,7 +191,8 @@ public:
|
||||
void ProcessEvent( SysExecEvent* evt );
|
||||
void ProcessEvent( SysExecEvent& evt );
|
||||
|
||||
bool ProcessMethodSelf( FnType_Void* method );
|
||||
bool Rpc_TryInvokeAsync( FnType_Void* method );
|
||||
bool Rpc_TryInvoke( FnType_Void* method );
|
||||
void SetActiveThread();
|
||||
|
||||
protected:
|
||||
@ -227,9 +228,14 @@ public:
|
||||
void ProcessEvent( SysExecEvent* evt );
|
||||
void ProcessEvent( SysExecEvent& evt );
|
||||
|
||||
bool ProcessMethodSelf( void (*evt)() )
|
||||
bool Rpc_TryInvokeAsync( void (*evt)() )
|
||||
{
|
||||
return m_EvtHandler ? m_EvtHandler->ProcessMethodSelf( evt ) : false;
|
||||
return m_EvtHandler ? m_EvtHandler->Rpc_TryInvokeAsync( evt ) : false;
|
||||
}
|
||||
|
||||
bool Rpc_TryInvoke( void (*evt)() )
|
||||
{
|
||||
return m_EvtHandler ? m_EvtHandler->Rpc_TryInvoke( evt ) : false;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -23,8 +23,9 @@
|
||||
|
||||
#define DIRENTRY_SIZE 16
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// --------------------------------------------------------------------------------------
|
||||
// romdir structure (packing required!)
|
||||
// --------------------------------------------------------------------------------------
|
||||
//
|
||||
#if defined(_MSC_VER)
|
||||
# pragma pack(1)
|
||||
@ -41,20 +42,16 @@ struct romdir
|
||||
# pragma pack()
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
u32 BiosVersion; // Used in Memory, Misc, CDVD
|
||||
|
||||
Exception::BiosLoadFailed::BiosLoadFailed( const wxString& filename, const wxString& msg_diag, const wxString& msg_user )
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::BiosLoadFailed (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
Exception::BiosLoadFailed::BiosLoadFailed( const wxString& filename )
|
||||
{
|
||||
wxString diag( msg_user.IsEmpty() ?
|
||||
L"BIOS has not been configured, or the configuration has been corrupted." : msg_user
|
||||
);
|
||||
wxString user( msg_user.IsEmpty() ?
|
||||
_("The PS2 BIOS has not been configured, or the configuration has been corrupted. Please re-configure.") : msg_user.c_str()
|
||||
);
|
||||
m_message_diag = L"BIOS has not been configured, or the configuration has been corrupted.";
|
||||
m_message_user = _("The PS2 BIOS could not be loaded. The BIOS has not been configured, or the configuration has been corrupted. Please re-configure.");
|
||||
|
||||
BaseException::InitBaseEx( diag, user );
|
||||
StreamName = filename;
|
||||
}
|
||||
|
||||
@ -156,10 +153,9 @@ void LoadBIOS()
|
||||
s64 filesize = Path::GetFileSize( Bios );
|
||||
if( filesize <= 0 )
|
||||
{
|
||||
throw Exception::BiosLoadFailed( Bios,
|
||||
L"Configured BIOS file does not exist.",
|
||||
_("The configured BIOS file does not exist. Please re-configure.")
|
||||
);
|
||||
throw Exception::BiosLoadFailed( Bios )
|
||||
.SetDiagMsg(L"Configured BIOS file does not exist.")
|
||||
.SetUserMsg(_("The configured BIOS file does not exist. Please re-configure."));
|
||||
}
|
||||
|
||||
wxFile fp( Bios );
|
||||
@ -168,10 +164,9 @@ void LoadBIOS()
|
||||
BiosVersion = GetBiosVersion();
|
||||
if( BiosVersion == -1 )
|
||||
{
|
||||
throw Exception::BiosLoadFailed( Bios,
|
||||
L"Configured BIOS file is not a valid PS2 BIOS.",
|
||||
_("The configured BIOS file is not a valid PS2 BIOS. Please re-configure.")
|
||||
);
|
||||
throw Exception::BiosLoadFailed( Bios )
|
||||
.SetDiagMsg(L"Configured BIOS file is not a valid PS2 BIOS.")
|
||||
.SetUserMsg(_("The configured BIOS file is not a valid PS2 BIOS. Please re-configure."));
|
||||
}
|
||||
|
||||
Console.WriteLn("Bios Version %d.%d", BiosVersion >> 8, BiosVersion & 0xff);
|
||||
|
@ -19,12 +19,12 @@ namespace Exception
|
||||
{
|
||||
class BiosLoadFailed : public FileNotFound
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( BiosLoadFailed )
|
||||
DEFINE_EXCEPTION_COPYTORS( BiosLoadFailed, FileNotFound )
|
||||
DEFINE_EXCEPTION_MESSAGES( BiosLoadFailed )
|
||||
DEFINE_STREAM_EXCEPTION_ACCESSORS( BiosLoadFailed )
|
||||
|
||||
explicit BiosLoadFailed( const wxString& filename,
|
||||
const wxString& msg_diag=wxEmptyString,
|
||||
const wxString& msg_user=wxEmptyString );
|
||||
public:
|
||||
BiosLoadFailed( const wxString& streamName );
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ using namespace vtlb_private;
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
#define verify(x) {if (!(x)) { (*(u8*)0)=3; }}
|
||||
#else
|
||||
#define verify jASSUME
|
||||
#define verify pxAssume
|
||||
#endif
|
||||
|
||||
namespace vtlb_private
|
||||
@ -221,32 +221,35 @@ void __fastcall vtlb_memWrite128(u32 mem, const mem128_t *value)
|
||||
MemOp_w1<128,mem128_t>(mem,value);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Error / TLB Miss Handlers
|
||||
// ===========================================================================================
|
||||
// Error / TLB Miss Handlers
|
||||
// ===========================================================================================
|
||||
// Important: Throwing exceptions isn't reliable *yet* because memory ops don't flush
|
||||
// the PC prior to invoking the indirect handlers. That feature will likely be added to
|
||||
// debug and dev builds soon, and later on to release builds as well.
|
||||
//
|
||||
|
||||
static const char* _getModeStr( u32 mode )
|
||||
{
|
||||
return (mode==0) ? "read" : "write";
|
||||
}
|
||||
|
||||
// Generates a tlbMiss Exception
|
||||
// Note: Don't throw exceptions yet, they cause a crash when otherwise
|
||||
// there would be a (slight) chance the game continues (rama).
|
||||
static __forceinline void vtlb_Miss(u32 addr,u32 mode)
|
||||
{
|
||||
Console.Error( "vtlb miss : addr 0x%X, mode %d [%s]", addr, mode, _getModeStr(mode) );
|
||||
//verify(false);
|
||||
//throw R5900Exception::TLBMiss( addr, !!mode );
|
||||
if( IsDevBuild )
|
||||
Cpu->ThrowException( R5900Exception::TLBMiss( addr, !!mode ) );
|
||||
else
|
||||
Console.Error( R5900Exception::TLBMiss( addr, !!mode ).FormatMessage() );
|
||||
}
|
||||
|
||||
// Just dies a horrible death for now.
|
||||
// Eventually should generate a BusError exception.
|
||||
// BusError exception: more serious than a TLB miss. If properly emulated the PS2 kernel
|
||||
// itself would invoke a diagnostic/assertion screen that displays the cpu state at the
|
||||
// time of the exception.
|
||||
static __forceinline void vtlb_BusError(u32 addr,u32 mode)
|
||||
{
|
||||
Console.Error( "vtlb bus error : addr 0x%X, mode %d\n", addr, _getModeStr(mode) );
|
||||
//verify(false);
|
||||
throw R5900Exception::BusError( addr, !!mode );
|
||||
// Throwing exceptions isn't reliable *yet* because memory ops don't flush
|
||||
// the PC prior to invoking the indirect handlers.
|
||||
|
||||
if( IsDevBuild )
|
||||
Cpu->ThrowException( R5900Exception::BusError( addr, !!mode ) );
|
||||
else
|
||||
Console.Error( R5900Exception::TLBMiss( addr, !!mode ).FormatMessage() );
|
||||
}
|
||||
|
||||
///// Virtual Mapping Errors (TLB Miss)
|
||||
@ -307,8 +310,9 @@ void __fastcall vtlbDefaultPhyWrite64(u32 addr,const mem64_t* data) { Console.Er
|
||||
void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data) { Console.Error("vtlbDefaultPhyWrite128: 0x%X",addr); verify(false); }
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// VTLB Public API -- Init/Term/RegisterHandler stuff
|
||||
// ===========================================================================================
|
||||
// VTLB Public API -- Init/Term/RegisterHandler stuff
|
||||
// ===========================================================================================
|
||||
//
|
||||
|
||||
// Assigns or re-assigns the callbacks for a VTLB memory handler. The handler defines specific behavior
|
||||
@ -582,7 +586,7 @@ void vtlb_Core_Alloc()
|
||||
// Win32 just needs this, since malloc always maps below 2GB.
|
||||
vtlbdata.alloc_base = (u8*)_aligned_malloc( VTLB_ALLOC_SIZE, 4096 );
|
||||
if( vtlbdata.alloc_base == NULL )
|
||||
throw Exception::OutOfMemory( "Fatal Error: could not allocate 42Meg buffer for PS2's mappable system ram." );
|
||||
throw Exception::OutOfMemory( L"PS2 mappable system ram (42 megs)" );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -26,30 +26,28 @@ void StreamException_ThrowFromErrno( const wxString& streamname, errno_t errcode
|
||||
{
|
||||
case EINVAL:
|
||||
pxFailDev( L"Invalid argument" );
|
||||
throw Exception::Stream( streamname, "Invalid argument" );
|
||||
throw Exception::Stream( streamname ).SetDiagMsg(L"Invalid argument" );
|
||||
|
||||
case EACCES: // Access denied!
|
||||
throw Exception::AccessDenied( streamname );
|
||||
|
||||
case EMFILE: // Too many open files!
|
||||
throw Exception::CannotCreateStream( streamname, "Too many open files" ); // File handle allocation failure
|
||||
throw Exception::CannotCreateStream( streamname ).SetDiagMsg(L"Too many open files"); // File handle allocation failure
|
||||
|
||||
case EEXIST:
|
||||
throw Exception::CannotCreateStream( streamname, "File already exists" );
|
||||
throw Exception::CannotCreateStream( streamname ).SetDiagMsg(L"File already exists");
|
||||
|
||||
case ENOENT: // File not found!
|
||||
throw Exception::FileNotFound( streamname );
|
||||
|
||||
case EPIPE:
|
||||
throw Exception::BadStream( streamname, "Broken pipe" );
|
||||
throw Exception::BadStream( streamname ).SetDiagMsg(L"Broken pipe");
|
||||
|
||||
case EBADF:
|
||||
throw Exception::BadStream( streamname, "Bad file number" );
|
||||
throw Exception::BadStream( streamname ).SetDiagMsg(L"Bad file number");
|
||||
|
||||
default:
|
||||
throw Exception::Stream( streamname,
|
||||
wxsFormat( L"General file/stream error [errno: %d]", errcode )
|
||||
);
|
||||
throw Exception::Stream( streamname ).SetDiagMsg(wxsFormat( L"General file/stream error [errno: %d]", errcode ));
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,22 +68,20 @@ void StreamException_ThrowLastError( const wxString& streamname, HANDLE result )
|
||||
throw Exception::FileNotFound( streamname );
|
||||
|
||||
case ERROR_TOO_MANY_OPEN_FILES:
|
||||
throw Exception::CannotCreateStream( streamname, "Too many open files" );
|
||||
throw Exception::CannotCreateStream( streamname ).SetDiagMsg(L"Too many open files");
|
||||
|
||||
case ERROR_ACCESS_DENIED:
|
||||
throw Exception::AccessDenied( streamname );
|
||||
|
||||
case ERROR_INVALID_HANDLE:
|
||||
throw Exception::BadStream( streamname, "Stream object or handle is invalid" );
|
||||
throw Exception::BadStream( streamname ).SetDiagMsg(L"Stream object or handle is invalid");
|
||||
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
throw Exception::AccessDenied( streamname, "Sharing violation" );
|
||||
throw Exception::AccessDenied( streamname ).SetDiagMsg(L"Sharing violation");
|
||||
|
||||
default:
|
||||
{
|
||||
throw Exception::Stream( streamname,
|
||||
wxsFormat( L"General Win32 File/stream error [GetLastError: %d]", error )
|
||||
);
|
||||
throw Exception::Stream( streamname ).SetDiagMsg(wxsFormat( L"General Win32 File/stream error [GetLastError: %d]", error ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,35 +19,6 @@
|
||||
#include "App.h"
|
||||
#include "ConsoleLogger.h"
|
||||
|
||||
Exception::WinApiError::WinApiError( const char* msg )
|
||||
{
|
||||
ErrorId = GetLastError();
|
||||
BaseException::InitBaseEx( msg );
|
||||
}
|
||||
|
||||
wxString Exception::WinApiError::GetMsgFromWindows() const
|
||||
{
|
||||
if (!ErrorId)
|
||||
return wxString();
|
||||
|
||||
const DWORD BUF_LEN = 2048;
|
||||
TCHAR t_Msg[BUF_LEN];
|
||||
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, ErrorId, 0, t_Msg, BUF_LEN, 0))
|
||||
return wxsFormat( L"Win32 Error #%d: %s", ErrorId, t_Msg );
|
||||
|
||||
return wxsFormat( L"Win32 Error #%d (no text msg available)", ErrorId );
|
||||
}
|
||||
|
||||
wxString Exception::WinApiError::FormatDisplayMessage() const
|
||||
{
|
||||
return m_message_user + L"\n\n" + GetMsgFromWindows();
|
||||
}
|
||||
|
||||
wxString Exception::WinApiError::FormatDiagnosticMessage() const
|
||||
{
|
||||
return m_message_diag + L"\n\t" + GetMsgFromWindows();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Win32 Console Pipes
|
||||
// As a courtesy and convenience, we redirect stdout/stderr to the console and logfile.
|
||||
@ -102,7 +73,7 @@ protected:
|
||||
continue;
|
||||
}
|
||||
|
||||
throw Exception::WinApiError( "ReadFile from pipe failed." );
|
||||
throw Exception::WinApiError().SetDiagMsg(L"ReadFile from pipe failed.");
|
||||
}
|
||||
|
||||
if( u32_Read <= 3 )
|
||||
@ -120,7 +91,7 @@ protected:
|
||||
{
|
||||
Yield();
|
||||
if( !PeekNamedPipe(m_outpipe, 0, 0, 0, &u32_avail, 0) )
|
||||
throw Exception::WinApiError( "Error peeking Pipe." );
|
||||
throw Exception::WinApiError().SetDiagMsg(L"Error peeking Pipe.");
|
||||
|
||||
if( u32_avail == 0 ) break;
|
||||
|
||||
@ -190,10 +161,10 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
|
||||
try
|
||||
{
|
||||
if( 0 == CreatePipe( &m_readpipe, &m_writepipe, NULL, 0 ) )
|
||||
throw Exception::WinApiError( "CreatePipe failed." );
|
||||
throw Exception::WinApiError().SetDiagMsg(L"CreatePipe failed.");
|
||||
|
||||
if( 0 == SetStdHandle( m_stdhandle, m_writepipe ) )
|
||||
throw Exception::WinApiError( "SetStdHandle failed." );
|
||||
throw Exception::WinApiError().SetDiagMsg(L"SetStdHandle failed.");
|
||||
|
||||
// Note: Don't use GetStdHandle to "confirm" the handle.
|
||||
//
|
||||
@ -224,7 +195,7 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
|
||||
// the constructor, so re-pack a new exception:
|
||||
|
||||
Cleanup();
|
||||
throw Exception::RuntimeError( ex.FormatDiagnosticMessage(), ex.FormatDisplayMessage() );
|
||||
throw Exception::RuntimeError().SetDiagMsg( ex.FormatDiagnosticMessage() ).SetUserMsg( ex.FormatDisplayMessage() );
|
||||
}
|
||||
catch( BaseException& ex )
|
||||
{
|
||||
|
@ -772,7 +772,7 @@ static void recAlloc()
|
||||
recMem = (u8*)SysMmapEx( 0x28000000, RECMEM_SIZE, 0, "recAlloc(R3000a)" );
|
||||
|
||||
if( recMem == NULL )
|
||||
throw Exception::OutOfMemory( "R3000a Init > failed to allocate memory for the recompiler." );
|
||||
throw Exception::OutOfMemory( L"R3000A recompiled code cache" );
|
||||
|
||||
// Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory.
|
||||
// Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
|
||||
@ -782,7 +782,7 @@ static void recAlloc()
|
||||
m_recBlockAlloc = (u8*)_aligned_malloc( m_recBlockAllocSize, 4096 );
|
||||
|
||||
if( m_recBlockAlloc == NULL )
|
||||
throw Exception::OutOfMemory( "R3000a Init > Failed to allocate memory for baseblock lookup tables." );
|
||||
throw Exception::OutOfMemory( L"R3000A BASEBLOCK lookup tables" );
|
||||
|
||||
u8* curpos = m_recBlockAlloc;
|
||||
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::IopRam / 4) * sizeof(BASEBLOCK);
|
||||
@ -796,7 +796,7 @@ static void recAlloc()
|
||||
}
|
||||
|
||||
if( s_pInstCache == NULL )
|
||||
throw Exception::OutOfMemory( "R3000a Init > Failed to allocate memory for pInstCache." );
|
||||
throw Exception::OutOfMemory( L"R3000 InstCache." );
|
||||
|
||||
ProfilerRegisterSource( "IOP Rec", recMem, RECMEM_SIZE );
|
||||
_DynGen_Dispatchers();
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
#include "Common.h"
|
||||
#include "Memory.h"
|
||||
|
||||
#include "R5900Exceptions.h"
|
||||
#include "R5900OpcodeTables.h"
|
||||
#include "iR5900.h"
|
||||
|
||||
@ -61,6 +63,8 @@ bool g_cpuFlushedPC, g_recompilingDelaySlot, g_maySignalException;
|
||||
#define X86
|
||||
static const int RECCONSTBUF_SIZE = 16384 * 2; // 64 bit consts in 32 bit units
|
||||
|
||||
static ScopedPtr<BaseR5900Exception> m_vmException;
|
||||
|
||||
static u8 *recMem = NULL; // the recompiled blocks will be here
|
||||
static u32* recConstBuf = NULL; // 64-bit pseudo-immediates
|
||||
static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here
|
||||
@ -534,10 +538,9 @@ static const uint m_recBlockAllocSize =
|
||||
|
||||
static void recThrowHardwareDeficiency( const wxChar* extFail )
|
||||
{
|
||||
throw Exception::HardwareDeficiency(
|
||||
wxsFormat( L"R5900-32 recompiler init failed: %s is not available.", extFail),
|
||||
wxsFormat(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )
|
||||
);
|
||||
throw Exception::HardwareDeficiency()
|
||||
.SetDiagMsg(wxsFormat( L"R5900-32 recompiler init failed: %s is not available.", extFail))
|
||||
.SetUserMsg(wxsFormat(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail ));
|
||||
}
|
||||
|
||||
static void recAlloc()
|
||||
@ -569,7 +572,7 @@ static void recAlloc()
|
||||
}
|
||||
|
||||
if( recMem == NULL )
|
||||
throw Exception::OutOfMemory( "R5900-32: Out of memory allocating recompiled code buffer." );
|
||||
throw Exception::OutOfMemory( L"R5900-32 recompiled code cache" );
|
||||
|
||||
// Goal: Allocate BASEBLOCKs for every possible branch target in PS2 memory.
|
||||
// Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
|
||||
@ -579,7 +582,7 @@ static void recAlloc()
|
||||
m_recBlockAlloc = (u8*) _aligned_malloc( m_recBlockAllocSize, 4096 );
|
||||
|
||||
if( m_recBlockAlloc == NULL )
|
||||
throw Exception::OutOfMemory( "R5900-32: Out of memory allocating BASEBLOCK tables." );
|
||||
throw Exception::OutOfMemory( L"R5900-32 BASEBLOCK tables" );
|
||||
|
||||
u8* curpos = m_recBlockAlloc;
|
||||
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK);
|
||||
@ -595,7 +598,7 @@ static void recAlloc()
|
||||
}
|
||||
|
||||
if( s_pInstCache == NULL )
|
||||
throw Exception::OutOfMemory( "R5900-32: Out of memory allocating InstCache." );
|
||||
throw Exception::OutOfMemory( L"R5900-32 InstCache" );
|
||||
|
||||
// No errors.. Proceed with initialization:
|
||||
|
||||
@ -722,12 +725,14 @@ static void recExitExecution()
|
||||
|
||||
static void recCheckExecutionState()
|
||||
{
|
||||
if( eeRecIsReset || GetCoreThread().HasPendingStateChangeRequest() )
|
||||
if( eeRecIsReset || m_vmException || GetCoreThread().HasPendingStateChangeRequest() )
|
||||
{
|
||||
recExitExecution();
|
||||
}
|
||||
}
|
||||
|
||||
static bool m_recExecutingCode = false;
|
||||
|
||||
static void recExecute()
|
||||
{
|
||||
// Implementation Notes:
|
||||
@ -735,7 +740,9 @@ static void recExecute()
|
||||
|
||||
#if PCSX2_SEH
|
||||
eeRecIsReset = false;
|
||||
m_vmException = NULL;
|
||||
g_EEFreezeRegs = true;
|
||||
ScopedBool executing(m_recExecutingCode);
|
||||
|
||||
try {
|
||||
EnterRecompiledCode();
|
||||
@ -766,6 +773,8 @@ static void recExecute()
|
||||
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
|
||||
}
|
||||
#endif
|
||||
|
||||
if(m_vmException) m_vmException->Rethrow();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
@ -1813,6 +1822,18 @@ StartRecomp:
|
||||
s_pCurBlockEx = NULL;
|
||||
}
|
||||
|
||||
// The only *safe* way to throw exceptions from the context of recompiled code.
|
||||
// The exception is cached and the recompiler is exited safely using either an
|
||||
// SEH unwind (MSW) or setjmp/longjmp (GCC).
|
||||
void recThrowException( const BaseR5900Exception& ex )
|
||||
{
|
||||
if (!m_recExecutingCode) ex.Rethrow();
|
||||
|
||||
m_vmException = ex.Clone();
|
||||
recExitExecution();
|
||||
}
|
||||
|
||||
|
||||
R5900cpu recCpu =
|
||||
{
|
||||
recAlloc,
|
||||
@ -1823,5 +1844,6 @@ R5900cpu recCpu =
|
||||
recExecute,
|
||||
|
||||
recCheckExecutionState,
|
||||
recThrowException,
|
||||
recClear,
|
||||
};
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "Common.h"
|
||||
#include <deque>
|
||||
#include "microVU.h"
|
||||
|
||||
//------------------------------------------------------------------
|
||||
@ -64,10 +65,9 @@ const __aligned(32) mVU_Globals mVUglob = {
|
||||
//------------------------------------------------------------------
|
||||
|
||||
_f void mVUthrowHardwareDeficiency(const wxChar* extFail, int vuIndex) {
|
||||
throw Exception::HardwareDeficiency(
|
||||
wxsFormat( L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail),
|
||||
wxsFormat(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )
|
||||
);
|
||||
throw Exception::HardwareDeficiency()
|
||||
.SetDiagMsg(wxsFormat(L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail))
|
||||
.SetUserMsg(wxsFormat(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail ));
|
||||
}
|
||||
|
||||
// Only run this once per VU! ;)
|
||||
@ -96,7 +96,7 @@ _f void mVUinit(VURegs* vuRegsPtr, int vuIndex) {
|
||||
}
|
||||
|
||||
mVU->dispCache = SysMmapEx(NULL, mVUdispCacheSize, 0, (mVU->index ? "Micro VU1 Dispatcher" : "Micro VU0 Dispatcher"));
|
||||
if (!mVU->dispCache) throw Exception::OutOfMemory("microVU Error: Failed to allocate dispatcher memory!");
|
||||
if (!mVU->dispCache) throw Exception::OutOfMemory( mVU->index ? L"Micro VU1 Dispatcher" : L"Micro VU0 Dispatcher" );
|
||||
memset(mVU->dispCache, 0xcc, mVUdispCacheSize);
|
||||
|
||||
// Setup Entrance/Exit Points
|
||||
@ -165,12 +165,8 @@ void mVUresizeCache(mV, u32 size) {
|
||||
if (size > (u32)mVUcacheMaxSize) { if (mVU->cacheSize==mVUcacheMaxSize) return; size = mVUcacheMaxSize; }
|
||||
if (mVU->cache) Console.WriteLn(Color_Green, "microVU%d: Attempting to resize Cache [%dmb]", mVU->index, size/_1mb);
|
||||
|
||||
// Give SysMmapEx a NULL and let the OS pick the memory for us: mVU can work with any
|
||||
// address the operating system gives us, and unlike the EE/IOP there's not much convenience
|
||||
// to debugging if the address is known anyway due to mVU's complex memory layouts (caching).
|
||||
|
||||
u8* cache = SysMmapEx(NULL, size, 0, (mVU->index ? "Micro VU1" : "Micro VU0"));
|
||||
if(!cache && !mVU->cache) throw Exception::OutOfMemory("microVU Error: Failed to allocate recompiler memory!");
|
||||
u8* cache = SysMmapEx(NULL, size, 0, (mVU->index ? "Micro VU1 RecCache" : "Micro VU0 RecCache"));
|
||||
if(!cache && !mVU->cache) throw Exception::OutOfMemory( wxsFormat( L"Micro VU%d recompiled code cache", mVU->index) );
|
||||
if(!cache) { Console.Error("microVU%d Error - Cache Resize Failed...", mVU->index); return; }
|
||||
if (mVU->cache) {
|
||||
HostSys::Munmap(mVU->cache, mVU->cacheSize);
|
||||
@ -272,7 +268,7 @@ _mVUt _f void* mVUsearchProg(u32 startPC, uptr pState) {
|
||||
microProgramQuick& quick = mVU->prog.quick[startPC/8];
|
||||
microProgramList& list = mVU->prog.prog [startPC/8];
|
||||
if(!quick.prog) { // If null, we need to search for new program
|
||||
deque<microProgram*>::iterator it = list.list->begin();
|
||||
deque<microProgram*>::iterator it( list.list->begin() );
|
||||
for ( ; it != list.list->end(); it++) {
|
||||
if (mVUcmpProg<vuIndex>(*it[0], 0)) {
|
||||
quick.block = it[0]->block[startPC/8];
|
||||
@ -282,15 +278,30 @@ _mVUt _f void* mVUsearchProg(u32 startPC, uptr pState) {
|
||||
return mVUentryGet(mVU, quick.block, startPC, pState);
|
||||
}
|
||||
}
|
||||
|
||||
// If cleared and program not found, make a new program instance
|
||||
mVU->prog.cleared = 0;
|
||||
mVU->prog.isSame = 1;
|
||||
mVU->prog.cur = mVUcreateProg<vuIndex>(startPC/8);
|
||||
void* entryPoint = mVUblockFetch(mVU, startPC, pState);
|
||||
quick.block = mVU->prog.cur->block[startPC/8];
|
||||
quick.prog = mVU->prog.cur;
|
||||
list.list->push_front(mVU->prog.cur);
|
||||
return entryPoint;
|
||||
// Exception note: It's bad news if the recompiler throws any exceptions, so we have a clause to
|
||||
// assert if an exception occurs. The rec should be pretty much exception safe, except for
|
||||
// critical errors that would result in a crash regardless.
|
||||
|
||||
try {
|
||||
mVU->prog.cleared = 0;
|
||||
mVU->prog.isSame = 1;
|
||||
mVU->prog.cur = mVUcreateProg<vuIndex>(startPC/8);
|
||||
void* entryPoint = mVUblockFetch(mVU, startPC, pState);
|
||||
quick.block = mVU->prog.cur->block[startPC/8];
|
||||
quick.prog = mVU->prog.cur;
|
||||
list.list->push_front(mVU->prog.cur);
|
||||
|
||||
return entryPoint;
|
||||
|
||||
} catch( BaseException& ex ) {
|
||||
pxFailDev( wxsFormat(L"microVU%d recompiler exception: " + ex.FormatDiagnosticMessage(), mVU->index) );
|
||||
} catch( std::exception& ex ) {
|
||||
pxFailDev( wxsFormat(L"microVU%d recompiler exception: " + Exception::RuntimeError(ex).FormatDiagnosticMessage(), mVU->index) );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
// If list.quick, then we've already found and recompiled the program ;)
|
||||
mVU->prog.isSame = -1;
|
||||
|
@ -33,7 +33,7 @@ protected:
|
||||
|
||||
void alloc(int size) {
|
||||
mData = SysMmapEx(NULL, size, 0, "nVif_BlockBuffer");
|
||||
if (!mData) throw Exception::OutOfMemory("nVif Error: Failed to allocate recompiler memory!");
|
||||
if (!mData) throw Exception::OutOfMemory(L"nVif recompiled code buffer (nVif_BlockBuffer)");
|
||||
clear();
|
||||
}
|
||||
void dealloc(u8* &dPtr, int size) {
|
||||
|
@ -83,8 +83,7 @@ public:
|
||||
|
||||
if( bucket.Chain = (T*)_aligned_realloc( bucket.Chain, sizeof(T)*(bucket.Size+1), 16), bucket.Chain==NULL ) {
|
||||
throw Exception::OutOfMemory(
|
||||
wxsFormat(L"Out of memory re-allocating hash bucket (bucket size=%d)", bucket.Size+1),
|
||||
wxEmptyString
|
||||
wxsFormat(L"HashBucket Chain (bucket size=%d)", bucket.Size+1)
|
||||
);
|
||||
}
|
||||
memcpy_const(&bucket.Chain[bucket.Size++], &dataPtr, sizeof(T));
|
||||
|
@ -2008,8 +2008,10 @@ void __fastcall VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr)
|
||||
size = GIFPath_ParseTagQuick(GIF_PATH_1, data, diff);
|
||||
pDest = &Path1Buffer[Path1WritePos*16];
|
||||
|
||||
|
||||
|
||||
pxAssumeMsg((Path1WritePos+size < sizeof(Path1Buffer)), "XGKick Buffer Overflow detected on Path1Buffer!");
|
||||
|
||||
|
||||
//DevCon.Warning("Storing size %x PATH 1", size);
|
||||
if (size > diff) {
|
||||
// fixme: one of these days the following *16's will get cleaned up when we introduce
|
||||
|
@ -360,13 +360,13 @@ static void SuperVUAlloc(int vuindex)
|
||||
|
||||
if (s_recVUMem == NULL)
|
||||
{
|
||||
throw Exception::VirtualMemoryMapConflict(
|
||||
// untranslated diagnostic msg, use exception's default for translation
|
||||
wxsFormat( L"SuperVU failed to allocate virtual memory below 256MB." ),
|
||||
|
||||
// Translated message
|
||||
_("Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory ranges required.")
|
||||
);
|
||||
throw Exception::VirtualMemoryMapConflict()
|
||||
.SetDiagMsg(wxsFormat( L"SuperVU failed to allocate virtual memory below 256MB." ))
|
||||
.SetUserMsg(pxE( ".Error:superVU:VirtualMemoryAlloc",
|
||||
L"Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory "
|
||||
L"ranges required, and will not be available for use. This is not a critical error, since "
|
||||
L"the sVU rec is obsolete, and you should use microVU instead anyway. :)"
|
||||
));
|
||||
}
|
||||
|
||||
ProfilerRegisterSource("sVU Rec", s_recVUMem, VU_EXESIZE);
|
||||
@ -453,7 +453,7 @@ void SuperVUReset(int vuindex)
|
||||
if (s_recVUMem == NULL)
|
||||
return;
|
||||
|
||||
//jASSUME( s_recVUMem != NULL );
|
||||
//pxAssume( s_recVUMem != NULL );
|
||||
|
||||
if (vuindex < 0)
|
||||
{
|
||||
@ -470,7 +470,6 @@ void SuperVUReset(int vuindex)
|
||||
else
|
||||
{
|
||||
DbgCon.WriteLn("SuperVU [VU%d]: Resetting the recs and junk", vuindex);
|
||||
list<VuFunctionHeader*>::iterator it;
|
||||
if (recVUHeaders[vuindex]) memset(recVUHeaders[vuindex], 0, sizeof(VuFunctionHeader*) * (s_MemSize[vuindex] / 8));
|
||||
if (recVUBlocks[vuindex]) memset(recVUBlocks[vuindex], 0, sizeof(VuBlockHeader) * (s_MemSize[vuindex] / 8));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user