mirror of https://github.com/PCSX2/pcsx2.git
Merge newHostVM branch. Feature overview:
* PCSX2 uses significantly less memory when starting. * Overall memory use reduced (mildly for some games, significantly for most). * EE and IOP main memory are now fixed at 0x20000000 and 0x24000000 -- useful when using external cheat apps. * Properly implemented the 'Shutdown' menu option -- Shutdown now unloads the entire PS2 virtual machine and reduced PCSX2's memory footprint to bare minimums. * Some more meaningful errors for when memory is a problem (out of memory, low virtual memory, etc). * Bugfix for pxsFmt when formatting long/large strings (over 1k) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4029 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
commit
2ee6b7abc6
|
@ -155,6 +155,8 @@
|
|||
<Unit filename="../../include/Utilities/HashMap.h" />
|
||||
<Unit filename="../../include/Utilities/IniInterface.h" />
|
||||
<Unit filename="../../include/Utilities/MemcpyFast.h" />
|
||||
<Unit filename="../../include/Utilities/MemsetFast.inl" />
|
||||
<Unit filename="../../include/Utilities/PageFaultSource.h" />
|
||||
<Unit filename="../../include/Utilities/Path.h" />
|
||||
<Unit filename="../../include/Utilities/PersistentThread.h" />
|
||||
<Unit filename="../../include/Utilities/RedtapeWindows.h" />
|
||||
|
@ -200,6 +202,7 @@
|
|||
<Unit filename="../../src/Utilities/ThreadTools.cpp" />
|
||||
<Unit filename="../../src/Utilities/ThreadingDialogs.cpp" />
|
||||
<Unit filename="../../src/Utilities/ThreadingInternal.h" />
|
||||
<Unit filename="../../src/Utilities/VirtualMemory.cpp" />
|
||||
<Unit filename="../../src/Utilities/pxCheckBox.cpp" />
|
||||
<Unit filename="../../src/Utilities/pxRadioPanel.cpp" />
|
||||
<Unit filename="../../src/Utilities/pxStaticText.cpp" />
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -160,7 +160,7 @@ public:
|
|||
|
||||
~ScopedBool() throw()
|
||||
{
|
||||
m_boolme = false;
|
||||
*m_boolme = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -177,6 +177,21 @@ public:
|
|||
|
||||
#include "Pcsx2Defs.h"
|
||||
|
||||
static const sptr _64kb = 0x10000;
|
||||
static const sptr _16kb = _64kb / 4;
|
||||
static const sptr _128kb = _64kb * 2;
|
||||
static const sptr _256kb = _128kb * 2;
|
||||
|
||||
static const s64 _1mb = 0x100000;
|
||||
static const s64 _8mb = _1mb * 8;
|
||||
static const s64 _16mb = _1mb * 16;
|
||||
static const s64 _32mb = _1mb * 32;
|
||||
static const s64 _64mb = _1mb * 64;
|
||||
static const s64 _256mb = _1mb * 256;
|
||||
static const s64 _1gb = _256mb * 4;
|
||||
static const s64 _4gb = _1gb * 4;
|
||||
|
||||
|
||||
// ===========================================================================================
|
||||
// i18n/Translation Feature Set!
|
||||
// ===========================================================================================
|
||||
|
|
|
@ -209,7 +209,7 @@ public: \
|
|||
//
|
||||
class OutOfMemory : public RuntimeError
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION( OutOfMemory, RuntimeError, wxLt("Out of memory?!") )
|
||||
DEFINE_RUNTIME_EXCEPTION( OutOfMemory, RuntimeError, wxEmptyString )
|
||||
|
||||
public:
|
||||
wxString AllocDescription;
|
||||
|
@ -236,7 +236,12 @@ public: \
|
|||
// we'd really like to have access to.
|
||||
class VirtualMemoryMapConflict : public OutOfMemory
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION( VirtualMemoryMapConflict, OutOfMemory, wxLt("Virtual memory map confict: Unable to claim specific required memory regions.") )
|
||||
DEFINE_RUNTIME_EXCEPTION( VirtualMemoryMapConflict, OutOfMemory, wxEmptyString )
|
||||
|
||||
VirtualMemoryMapConflict( const wxString& allocdesc );
|
||||
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
};
|
||||
|
||||
class HardwareDeficiency : public RuntimeError
|
||||
|
@ -254,43 +259,40 @@ public: \
|
|||
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 ) \
|
||||
#define DEFINE_STREAM_EXCEPTION( classname, parent ) \
|
||||
DEFINE_RUNTIME_EXCEPTION( classname, parent, wxEmptyString ) \
|
||||
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.
|
||||
// A generic base error class for bad streams -- corrupted data, sudden closures, loss of
|
||||
// connection, or anything else that would indicate a failure to open a stream or read the
|
||||
// data after the stream was successfully opened.
|
||||
//
|
||||
class Stream : public RuntimeError
|
||||
class BadStream : public RuntimeError
|
||||
{
|
||||
DEFINE_STREAM_EXCEPTION( Stream, RuntimeError, wxLt("General file operation error.") )
|
||||
DEFINE_STREAM_EXCEPTION( BadStream, RuntimeError )
|
||||
|
||||
public:
|
||||
wxString StreamName; // name of the stream (if applicable)
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
// A generic base error class for bad streams -- corrupted data, sudden closures, loss of
|
||||
// connection, or anything else that would indicate a failure to read the data after the
|
||||
// stream was successfully opened.
|
||||
//
|
||||
class BadStream : public Stream
|
||||
{
|
||||
DEFINE_STREAM_EXCEPTION( BadStream, Stream, wxLt("File data is corrupted or incomplete, or the stream connection closed unexpectedly.") )
|
||||
protected:
|
||||
void _formatDiagMsg( FastFormatUnicode& dest ) const;
|
||||
void _formatUserMsg( FastFormatUnicode& dest ) const;
|
||||
};
|
||||
|
||||
// A generic exception for odd-ball stream creation errors.
|
||||
//
|
||||
class CannotCreateStream : public Stream
|
||||
class CannotCreateStream : public BadStream
|
||||
{
|
||||
DEFINE_STREAM_EXCEPTION( CannotCreateStream, Stream, wxLt("File could not be created or opened.") )
|
||||
DEFINE_STREAM_EXCEPTION( CannotCreateStream, BadStream )
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
// Exception thrown when an attempt to open a non-existent file is made.
|
||||
|
@ -299,22 +301,31 @@ public: \
|
|||
class FileNotFound : public CannotCreateStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( FileNotFound, CannotCreateStream, wxLt("File not found.") )
|
||||
DEFINE_STREAM_EXCEPTION( FileNotFound, CannotCreateStream )
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
class AccessDenied : public CannotCreateStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( AccessDenied, CannotCreateStream, wxLt("Permission denied to file.") )
|
||||
DEFINE_STREAM_EXCEPTION( AccessDenied, CannotCreateStream )
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
// EndOfStream can be used either as an error, or used just as a shortcut for manual
|
||||
// feof checks.
|
||||
//
|
||||
class EndOfStream : public Stream
|
||||
class EndOfStream : public BadStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( EndOfStream, Stream, wxLt("Unexpected end of file or stream.") );
|
||||
DEFINE_STREAM_EXCEPTION( EndOfStream, BadStream )
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
#ifdef __WXMSW__
|
||||
|
|
|
@ -133,14 +133,84 @@ protected:
|
|||
virtual void DoDeletion();
|
||||
};
|
||||
|
||||
|
||||
enum PageProtectionMode
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PageProtectionMode
|
||||
// --------------------------------------------------------------------------------------
|
||||
class PageProtectionMode
|
||||
{
|
||||
Protect_NoAccess = 0,
|
||||
Protect_ReadOnly,
|
||||
Protect_ReadWrite
|
||||
protected:
|
||||
bool m_read;
|
||||
bool m_write;
|
||||
bool m_exec;
|
||||
|
||||
public:
|
||||
PageProtectionMode()
|
||||
{
|
||||
All( false );
|
||||
}
|
||||
|
||||
PageProtectionMode& Read( bool allow=true )
|
||||
{
|
||||
m_read = allow;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PageProtectionMode& Write( bool allow=true )
|
||||
{
|
||||
m_write = allow;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PageProtectionMode& Execute( bool allow=true )
|
||||
{
|
||||
m_exec = allow;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PageProtectionMode& All( bool allow=true )
|
||||
{
|
||||
m_read = m_write = m_exec = allow;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CanRead() const { return m_read; }
|
||||
bool CanWrite() const { return m_write; }
|
||||
bool CanExecute() const { return m_exec && m_read; }
|
||||
bool IsNone() const { return !m_read && !m_write; }
|
||||
|
||||
wxString ToString() const;
|
||||
};
|
||||
|
||||
static __fi PageProtectionMode PageAccess_None()
|
||||
{
|
||||
return PageProtectionMode();
|
||||
}
|
||||
|
||||
static __fi PageProtectionMode PageAccess_ReadOnly()
|
||||
{
|
||||
return PageProtectionMode().Read();
|
||||
}
|
||||
|
||||
static __fi PageProtectionMode PageAccess_WriteOnly()
|
||||
{
|
||||
return PageProtectionMode().Write();
|
||||
}
|
||||
|
||||
static __fi PageProtectionMode PageAccess_ReadWrite()
|
||||
{
|
||||
return PageAccess_ReadOnly().Write();
|
||||
}
|
||||
|
||||
static __fi PageProtectionMode PageAccess_ExecOnly()
|
||||
{
|
||||
return PageAccess_ReadOnly().Execute();
|
||||
}
|
||||
|
||||
static __fi PageProtectionMode PageAccess_Any()
|
||||
{
|
||||
return PageProtectionMode().All();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// HostSys
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -148,22 +218,29 @@ enum PageProtectionMode
|
|||
// platform prior to wxWidgets .. it should prolly be removed -- air)
|
||||
namespace HostSys
|
||||
{
|
||||
void* MmapReserve(uptr base, size_t size);
|
||||
bool MmapCommit(uptr base, size_t size, const PageProtectionMode& mode);
|
||||
void MmapReset(uptr base, size_t size);
|
||||
|
||||
void* MmapReservePtr(void* base, size_t size);
|
||||
bool MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode);
|
||||
void MmapResetPtr(void* base, size_t size);
|
||||
|
||||
// Maps a block of memory for use as a recompiled code buffer.
|
||||
// The allocated block has code execution privileges.
|
||||
// Returns NULL on allocation failure.
|
||||
extern void *Mmap(uptr base, u32 size);
|
||||
extern void* Mmap(uptr base, size_t size);
|
||||
|
||||
// Unmaps a block allocated by SysMmap
|
||||
extern void Munmap(uptr base, u32 size);
|
||||
extern void Munmap(uptr base, size_t size);
|
||||
|
||||
extern void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution=false );
|
||||
extern void MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode );
|
||||
|
||||
extern void Munmap( void* base, u32 size );
|
||||
extern void Munmap( void* base, size_t size );
|
||||
|
||||
template< uint size >
|
||||
void MemProtectStatic( u8 (&arr)[size], PageProtectionMode mode, bool allowExecution=false )
|
||||
void MemProtectStatic( u8 (&arr)[size], const PageProtectionMode& mode )
|
||||
{
|
||||
MemProtect( arr, size, mode, allowExecution );
|
||||
MemProtect( arr, size, mode );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#define StoreDestIdx(idx) case idx: _mm_store_ps(&destxmm[idx-1][0], srcreg)
|
||||
|
||||
template< u8 data >
|
||||
__noinline void memset_sse_a( void* dest, const size_t size )
|
||||
{
|
||||
const uint MZFqwc = size / 16;
|
||||
|
||||
pxAssert( (size & 0xf) == 0 );
|
||||
|
||||
__m128 srcreg;
|
||||
|
||||
if (data != 0)
|
||||
{
|
||||
static __aligned16 const u8 loadval[8] = { data,data,data,data,data,data,data,data };
|
||||
srcreg = _mm_loadh_pi( _mm_load_ps( (float*)loadval ), (__m64*)loadval );
|
||||
}
|
||||
else
|
||||
srcreg = _mm_setzero_ps();
|
||||
|
||||
float (*destxmm)[4] = (float(*)[4])dest;
|
||||
|
||||
switch( MZFqwc & 0x07 )
|
||||
{
|
||||
StoreDestIdx(0x07);
|
||||
StoreDestIdx(0x06);
|
||||
StoreDestIdx(0x05);
|
||||
StoreDestIdx(0x04);
|
||||
StoreDestIdx(0x03);
|
||||
StoreDestIdx(0x02);
|
||||
StoreDestIdx(0x01);
|
||||
}
|
||||
|
||||
destxmm += (MZFqwc & 0x07);
|
||||
for( uint i=0; i<MZFqwc / 8; ++i, destxmm+=8 )
|
||||
{
|
||||
_mm_store_ps(&destxmm[0][0], srcreg);
|
||||
_mm_store_ps(&destxmm[1][0], srcreg);
|
||||
_mm_store_ps(&destxmm[2][0], srcreg);
|
||||
_mm_store_ps(&destxmm[3][0], srcreg);
|
||||
_mm_store_ps(&destxmm[4][0], srcreg);
|
||||
_mm_store_ps(&destxmm[5][0], srcreg);
|
||||
_mm_store_ps(&destxmm[6][0], srcreg);
|
||||
_mm_store_ps(&destxmm[7][0], srcreg);
|
||||
}
|
||||
};
|
||||
|
||||
static __fi void memzero_sse_a( void* dest, const size_t size )
|
||||
{
|
||||
memset_sse_a<0>( dest, size );
|
||||
}
|
||||
|
||||
#undef StoreDestIdx
|
||||
|
||||
template< u8 data, typename T >
|
||||
__noinline void memset_sse_a( T& dest )
|
||||
{
|
||||
C_ASSERT( (sizeof(dest) & 0xf) == 0 );
|
||||
memset_sse_a<data>( &dest, sizeof(dest) );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
void memzero_sse_a( T& dest )
|
||||
{
|
||||
C_ASSERT( (sizeof(dest) & 0xf) == 0 );
|
||||
memset_sse_a<0>( &dest, sizeof(dest) );
|
||||
}
|
|
@ -0,0 +1,337 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// [TODO] Rename this file to VirtualMemory.h !!
|
||||
|
||||
#pragma once
|
||||
|
||||
// =====================================================================================================
|
||||
// Cross-Platform Memory Protection (Used by VTLB, Recompilers and Texture caches)
|
||||
// =====================================================================================================
|
||||
// Win32 platforms use the SEH model: __try {} __except {}
|
||||
// Linux platforms use the POSIX Signals model: sigaction()
|
||||
// [TODO] OS-X (Darwin) platforms should use the Mach exception model (not implemented)
|
||||
|
||||
#include "EventSource.h"
|
||||
|
||||
struct PageFaultInfo
|
||||
{
|
||||
uptr addr;
|
||||
|
||||
PageFaultInfo( uptr address )
|
||||
{
|
||||
addr = address;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IEventListener_PageFault
|
||||
// --------------------------------------------------------------------------------------
|
||||
class IEventListener_PageFault : public IEventDispatcher<PageFaultInfo>
|
||||
{
|
||||
public:
|
||||
typedef PageFaultInfo EvtParams;
|
||||
|
||||
public:
|
||||
virtual ~IEventListener_PageFault() throw() {}
|
||||
|
||||
virtual void DispatchEvent( const PageFaultInfo& evtinfo, bool& handled )
|
||||
{
|
||||
OnPageFaultEvent( evtinfo, handled );
|
||||
}
|
||||
|
||||
virtual void DispatchEvent( const PageFaultInfo& evtinfo )
|
||||
{
|
||||
pxFailRel( "Don't call me, damnit. Use DispatchException instead." );
|
||||
}
|
||||
|
||||
virtual void OnPageFaultEvent( const PageFaultInfo& evtinfo, bool& handled ) {}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EventListener_PageFault / EventListenerHelper_PageFault
|
||||
// --------------------------------------------------------------------------------------
|
||||
class EventListener_PageFault : public IEventListener_PageFault
|
||||
{
|
||||
public:
|
||||
EventListener_PageFault();
|
||||
virtual ~EventListener_PageFault() throw();
|
||||
};
|
||||
|
||||
template< typename TypeToDispatchTo >
|
||||
class EventListenerHelper_PageFault : public EventListener_PageFault
|
||||
{
|
||||
public:
|
||||
TypeToDispatchTo* Owner;
|
||||
|
||||
public:
|
||||
EventListenerHelper_PageFault( TypeToDispatchTo& dispatchTo )
|
||||
{
|
||||
Owner = &dispatchTo;
|
||||
}
|
||||
|
||||
EventListenerHelper_PageFault( TypeToDispatchTo* dispatchTo )
|
||||
{
|
||||
Owner = dispatchTo;
|
||||
}
|
||||
|
||||
virtual ~EventListenerHelper_PageFault() throw() {}
|
||||
|
||||
protected:
|
||||
virtual void OnPageFaultEvent( const PageFaultInfo& info, bool& handled )
|
||||
{
|
||||
Owner->OnPageFaultEvent( info, handled );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SrcType_PageFault
|
||||
// --------------------------------------------------------------------------------------
|
||||
class SrcType_PageFault : public EventSource<IEventListener_PageFault>
|
||||
{
|
||||
protected:
|
||||
typedef EventSource<IEventListener_PageFault> _parent;
|
||||
|
||||
protected:
|
||||
bool m_handled;
|
||||
|
||||
public:
|
||||
SrcType_PageFault() {}
|
||||
virtual ~SrcType_PageFault() throw() { }
|
||||
|
||||
bool WasHandled() const { return m_handled; }
|
||||
virtual void Dispatch( const PageFaultInfo& params );
|
||||
|
||||
protected:
|
||||
virtual void _DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt );
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VirtualMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class VirtualMemoryReserve
|
||||
{
|
||||
DeclareNoncopyableObject( VirtualMemoryReserve );
|
||||
|
||||
protected:
|
||||
wxString m_name;
|
||||
|
||||
// Default size of the reserve, in bytes. Can be specified when the object is contructed.
|
||||
// Is used as the reserve size when Reserve() is called, unless an override is specified
|
||||
// in the Reserve parameters.
|
||||
size_t m_defsize;
|
||||
|
||||
void* m_baseptr;
|
||||
|
||||
// reserved memory (in pages).
|
||||
uptr m_pages_reserved;
|
||||
|
||||
// Protection mode to be applied to committed blocks.
|
||||
PageProtectionMode m_prot_mode;
|
||||
|
||||
// Records the number of pages committed to memory.
|
||||
// (metric for analysis of buffer usage)
|
||||
uptr m_pages_commited;
|
||||
|
||||
public:
|
||||
VirtualMemoryReserve( const wxString& name=wxEmptyString, size_t size = 0 );
|
||||
virtual ~VirtualMemoryReserve() throw()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
virtual void* Reserve( size_t size = 0, uptr base = 0, uptr upper_bounds = 0 );
|
||||
virtual void* ReserveAt( uptr base = 0, uptr upper_bounds = 0 )
|
||||
{
|
||||
return Reserve(m_defsize, base, upper_bounds);
|
||||
}
|
||||
|
||||
virtual void Reset();
|
||||
virtual void Release();
|
||||
virtual bool TryResize( uint newsize );
|
||||
virtual bool Commit();
|
||||
|
||||
bool IsOk() const { return m_baseptr != NULL; }
|
||||
wxString GetName() const { return m_name; }
|
||||
|
||||
uptr GetReserveSizeInBytes() const { return m_pages_reserved * __pagesize; }
|
||||
uptr GetReserveSizeInPages() const { return m_pages_reserved; }
|
||||
uint GetCommittedPageCount() const { return m_pages_commited; }
|
||||
uint GetCommittedBytes() const { return m_pages_commited * __pagesize; }
|
||||
|
||||
u8* GetPtr() { return (u8*)m_baseptr; }
|
||||
const u8* GetPtr() const { return (u8*)m_baseptr; }
|
||||
u8* GetPtrEnd() { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); }
|
||||
const u8* GetPtrEnd() const { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); }
|
||||
|
||||
VirtualMemoryReserve& SetName( const wxString& newname );
|
||||
VirtualMemoryReserve& SetBaseAddr( uptr newaddr );
|
||||
VirtualMemoryReserve& SetPageAccessOnCommit( const PageProtectionMode& mode );
|
||||
|
||||
operator void*() { return m_baseptr; }
|
||||
operator const void*() const { return m_baseptr; }
|
||||
|
||||
operator u8*() { return (u8*)m_baseptr; }
|
||||
operator const u8*() const { return (u8*)m_baseptr; }
|
||||
|
||||
u8& operator[](uint idx)
|
||||
{
|
||||
pxAssume(idx < (m_pages_reserved * __pagesize));
|
||||
return *((u8*)m_baseptr + idx);
|
||||
}
|
||||
|
||||
const u8& operator[](uint idx) const
|
||||
{
|
||||
pxAssume(idx < (m_pages_reserved * __pagesize));
|
||||
return *((u8*)m_baseptr + idx);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseVmReserveListener
|
||||
// --------------------------------------------------------------------------------------
|
||||
class BaseVmReserveListener : public VirtualMemoryReserve
|
||||
{
|
||||
DeclareNoncopyableObject( BaseVmReserveListener );
|
||||
|
||||
typedef VirtualMemoryReserve _parent;
|
||||
|
||||
protected:
|
||||
EventListenerHelper_PageFault<BaseVmReserveListener> m_pagefault_listener;
|
||||
|
||||
// Incremental size by which the buffer grows (in pages)
|
||||
uptr m_blocksize;
|
||||
|
||||
public:
|
||||
BaseVmReserveListener( const wxString& name, size_t size = 0 );
|
||||
virtual ~BaseVmReserveListener() throw() { }
|
||||
|
||||
operator void*() { return m_baseptr; }
|
||||
operator const void*() const { return m_baseptr; }
|
||||
|
||||
operator u8*() { return (u8*)m_baseptr; }
|
||||
operator const u8*() const { return (u8*)m_baseptr; }
|
||||
|
||||
using _parent::operator[];
|
||||
|
||||
void OnPageFaultEvent( const PageFaultInfo& info, bool& handled );
|
||||
|
||||
protected:
|
||||
|
||||
// This function is called from OnPageFaultEvent after the address has been translated
|
||||
// and confirmed to apply to this reserved area in question. OnPageFaultEvent contains
|
||||
// a try/catch exception handler, which ensures "reasonable" error response behavior if
|
||||
// this function throws exceptions.
|
||||
//
|
||||
// Important: This method is called from the context of an exception/signal handler. On
|
||||
// Windows this isn't a big deal (most operations are ok). On Linux, however, logging
|
||||
// and other facilities are probably not a good idea.
|
||||
virtual void DoCommitAndProtect( uptr offset )=0;
|
||||
|
||||
// This function is called for every committed block.
|
||||
virtual void OnCommittedBlock( void* block )=0;
|
||||
|
||||
virtual void CommitBlocks( uptr page, uint blocks );
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SpatialArrayReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
// A spatial array is one where large areas of the memory reserve will remain unused during
|
||||
// process execution. Only areas put to use will be committed to virtual memory.
|
||||
//
|
||||
// Spatial array efficiency depends heavily on selecting the right parameters for the array's
|
||||
// primary intended use. Memory in a spatial array is arranged by blocks, with each block
|
||||
// containing some number of pages (pages are 4096 bytes each on most platforms). When the
|
||||
// array is accessed, the entire block containing the addressed memory will be committed at
|
||||
// once. Blocks can be a single page in size (4096 bytes), though this is highly discouraged
|
||||
// due to overhead and fragmentation penalties.
|
||||
//
|
||||
// Balancing block sizes:
|
||||
// Larger blocks are good for reducing memory fragmentation and block-tracking overhead, but
|
||||
// can also result in a lot of otherwise unused memory being committed to memory. Smaller
|
||||
// blocks are good for arrays that will tend toward more sequential behavior, as they reduce
|
||||
// the amount of unused memory being committed. However, since every block requires a
|
||||
// tracking entry, assigning small blocks to a very large array can result in quite a bit of
|
||||
// unwanted overhead. Furthermore, if the array is accessed randomly, system physical memory
|
||||
// will become very fragmented, which will also hurt performance.
|
||||
//
|
||||
// By default, the base block size is based on a heuristic that balances the size of the spatial
|
||||
// array reserve against a best-guess performance profile for the target platform.
|
||||
//
|
||||
class SpatialArrayReserve : public BaseVmReserveListener
|
||||
{
|
||||
typedef BaseVmReserveListener _parent;
|
||||
|
||||
protected:
|
||||
uint m_numblocks;
|
||||
|
||||
// Array of block bits, each bit indicating if the block has been committed to memory
|
||||
// or not. The array length is typically determined via ((numblocks+7) / 8), though the
|
||||
// actual array size may be larger in order to accommodate 32-bit or 128-bit accelerated
|
||||
// operations.
|
||||
ScopedAlignedAlloc<u8,16> m_blockbits;
|
||||
|
||||
public:
|
||||
SpatialArrayReserve( const wxString& name );
|
||||
|
||||
virtual void* Reserve( size_t size = 0, uptr base = 0, uptr upper_bounds = 0 );
|
||||
virtual void Reset();
|
||||
virtual bool TryResize( uint newsize );
|
||||
|
||||
void OnCommittedBlock( void* block );
|
||||
|
||||
SpatialArrayReserve& SetBlockCount( uint blocks );
|
||||
SpatialArrayReserve& SetBlockSizeInPages( uint bytes );
|
||||
uint SetBlockSize( uint bytes );
|
||||
|
||||
operator void*() { return m_baseptr; }
|
||||
operator const void*() const { return m_baseptr; }
|
||||
|
||||
operator u8*() { return (u8*)m_baseptr; }
|
||||
operator const u8*() const { return (u8*)m_baseptr; }
|
||||
|
||||
using _parent::operator[];
|
||||
|
||||
protected:
|
||||
void DoCommitAndProtect( uptr page );
|
||||
uint _calcBlockBitArrayLength() const;
|
||||
};
|
||||
|
||||
#ifdef __LINUX__
|
||||
|
||||
# define PCSX2_PAGEFAULT_PROTECT
|
||||
# define PCSX2_PAGEFAULT_EXCEPT
|
||||
|
||||
#elif defined( _WIN32 )
|
||||
|
||||
struct _EXCEPTION_POINTERS;
|
||||
extern int SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps);
|
||||
|
||||
# define PCSX2_PAGEFAULT_PROTECT __try
|
||||
# define PCSX2_PAGEFAULT_EXCEPT __except(SysPageFaultExceptionFilter(GetExceptionInformation())) {}
|
||||
|
||||
#else
|
||||
# error PCSX2 - Unsupported operating system platform.
|
||||
#endif
|
||||
|
||||
extern void pxInstallSignalHandler();
|
||||
extern void _platform_InstallSignalHandler();
|
||||
|
||||
extern SrcType_PageFault* Source_PageFault;
|
||||
|
|
@ -102,6 +102,7 @@ public:
|
|||
|
||||
wxFileName operator+( const wxFileName& right ) const { return Combine( right ); }
|
||||
wxDirName operator+( const wxDirName& right ) const { return Combine( right ); }
|
||||
wxFileName operator+( const wxString& right ) const { return Combine( wxFileName(right) ); }
|
||||
|
||||
bool operator==(const wxDirName& filename) const { return SameAs(filename); }
|
||||
bool operator!=(const wxDirName& filename) const { return !SameAs(filename); }
|
||||
|
@ -122,7 +123,7 @@ public:
|
|||
// --------------------------------------------------------------------------------------
|
||||
// Cross-platform utilities for manipulation of paths and filenames. Mostly these fall
|
||||
// back on wxWidgets APIs internally, but are still helpful because some of wx's file stuff
|
||||
// has minor glitches, or requies sloppy wxFileName typecasting.
|
||||
// has minor glitches, or requires sloppy wxFileName typecasting.
|
||||
//
|
||||
namespace Path
|
||||
{
|
||||
|
|
|
@ -31,7 +31,8 @@ SafeArray<T>::SafeArray( const wxChar* name, T* allocated_mem, int initSize )
|
|||
m_size = initSize;
|
||||
|
||||
if( m_ptr == NULL )
|
||||
throw Exception::OutOfMemory(name + wxsFormat(L" (SafeArray::constructor) [size=%d]", initSize));
|
||||
throw Exception::OutOfMemory(name)
|
||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initSize));
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
|
@ -79,7 +80,8 @@ SafeArray<T>::SafeArray( int initialSize, const wxChar* name )
|
|||
m_size = initialSize;
|
||||
|
||||
if( (initialSize != 0) && (m_ptr == NULL) )
|
||||
throw Exception::OutOfMemory(name + wxsFormat(L" (SafeArray::constructor) [size=%d]", initialSize));
|
||||
throw Exception::OutOfMemory(name)
|
||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initialSize));
|
||||
}
|
||||
|
||||
// Clears the contents of the array to zero, and frees all memory allocations.
|
||||
|
@ -106,9 +108,8 @@ void SafeArray<T>::ExactAlloc( int newsize )
|
|||
|
||||
m_ptr = _virtual_realloc( newsize );
|
||||
if( m_ptr == NULL )
|
||||
throw Exception::OutOfMemory(Name +
|
||||
wxsFormat(L" (SafeArray::ExactAlloc) [oldsize=%d] [newsize=%d]", m_size, newsize)
|
||||
);
|
||||
throw Exception::OutOfMemory(Name)
|
||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ExactAlloc' [oldsize=%d] [newsize=%d]", m_size, newsize));
|
||||
|
||||
m_size = newsize;
|
||||
}
|
||||
|
@ -199,9 +200,8 @@ SafeList<T>::SafeList( int initialSize, const wxChar* name )
|
|||
m_ptr = (T*)malloc( initialSize * sizeof(T) );
|
||||
|
||||
if( m_ptr == NULL )
|
||||
throw Exception::OutOfMemory(Name +
|
||||
wxsFormat(L" (SafeList::Constructor) [length=%d]", m_length)
|
||||
);
|
||||
throw Exception::OutOfMemory(Name)
|
||||
.SetDiagMsg(wxsFormat(L"called from 'SafeList::ctor' [length=%d]", m_length));
|
||||
|
||||
for( int i=0; i<m_allocsize; ++i )
|
||||
{
|
||||
|
@ -227,9 +227,8 @@ void SafeList<T>::MakeRoomFor( int blockSize )
|
|||
const int newalloc = blockSize + ChunkSize;
|
||||
m_ptr = _virtual_realloc( newalloc );
|
||||
if( m_ptr == NULL )
|
||||
throw Exception::OutOfMemory(Name +
|
||||
wxsFormat(L" (SafeList::MakeRoomFor) [oldlen=%d] [newlen=%d]", m_length, blockSize)
|
||||
);
|
||||
throw Exception::OutOfMemory(Name)
|
||||
.SetDiagMsg(wxsFormat(L"Called from 'SafeList::MakeRoomFor' [oldlen=%d] [newlen=%d]", m_length, blockSize));
|
||||
|
||||
for( ; m_allocsize<newalloc; ++m_allocsize )
|
||||
{
|
||||
|
|
|
@ -60,6 +60,26 @@ extern void pcsx2_aligned_free(void* pmem);
|
|||
# define _aligned_realloc pcsx2_aligned_realloc
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxDoOutOfMemory
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
typedef void FnType_OutOfMemory( uptr blocksize );
|
||||
typedef FnType_OutOfMemory* Fnptr_OutOfMemory;
|
||||
|
||||
// This method is meant to be assigned by applications that link against pxWex. It is called
|
||||
// (invoked) prior to most pxWex built-in memory/array classes throwing exceptions, and can be
|
||||
// used by an application to remove unneeded memory allocations and/or reduce internal cache
|
||||
// reserves.
|
||||
//
|
||||
// Example: PCSX2 uses several bloated recompiler code caches. Larger caches improve performance,
|
||||
// however a rouge cache growth could cause memory constraints in the operating system. If an out-
|
||||
// of-memory error occurs, PCSX2's implementation of this function attempts to reset all internal
|
||||
// recompiler caches. This can typically free up 100-150 megs of memory, and will allow the app
|
||||
// to continue running without crashing or hanging the operating system, etc.
|
||||
//
|
||||
extern Fnptr_OutOfMemory pxDoOutOfMemory;
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseScopedAlloc
|
||||
|
|
|
@ -222,6 +222,8 @@ extern bool pxParseAssignmentString( const wxString& src, wxString& ldest, wxStr
|
|||
#define pxsFmt FastFormatUnicode().Write
|
||||
#define pxsFmtV FastFormatUnicode().WriteV
|
||||
|
||||
#define pxsPtr(ptr) pxsFmt("0x%08X", (ptr)).c_str()
|
||||
|
||||
extern wxString& operator+=(wxString& str1, const FastFormatUnicode& str2);
|
||||
extern wxString operator+(const wxString& str1, const FastFormatUnicode& str2);
|
||||
extern wxString operator+(const wxChar* str1, const FastFormatUnicode& str2);
|
||||
|
|
|
@ -1,181 +1,184 @@
|
|||
# Check that people use the good file
|
||||
if(NOT TOP_CMAKE_WAS_SOURCED)
|
||||
message(FATAL_ERROR "
|
||||
You did not 'cmake' the good CMakeLists.txt file. Use the one in the top dir.
|
||||
It is advice to delete all wrongly generated cmake stuff => CMakeFiles & CMakeCache.txt")
|
||||
endif(NOT TOP_CMAKE_WAS_SOURCED)
|
||||
|
||||
|
||||
# library name
|
||||
set(Output Utilities)
|
||||
|
||||
# set common flags
|
||||
set(CommonFlags
|
||||
-pthread
|
||||
-fvisibility=hidden
|
||||
-fno-dse
|
||||
-fno-guess-branch-probability
|
||||
-fno-strict-aliasing
|
||||
-fno-tree-dse
|
||||
-pipe
|
||||
-Wno-format
|
||||
-Wno-unused-parameter
|
||||
-Wno-unused-value
|
||||
-Wunused-variable)
|
||||
|
||||
# set warning flags
|
||||
set(DebugFlags
|
||||
-g
|
||||
-W)
|
||||
|
||||
# set optimization flags
|
||||
set(OptimizationFlags
|
||||
-falign-functions
|
||||
-falign-jumps
|
||||
-falign-labels
|
||||
-falign-loops
|
||||
-fcaller-saves
|
||||
-fcprop-registers
|
||||
-fcrossjumping
|
||||
-fcse-follow-jumps
|
||||
-fcse-skip-blocks
|
||||
-fdefer-pop
|
||||
-fdelete-null-pointer-checks
|
||||
-fgcse
|
||||
-fgcse-lm
|
||||
-fif-conversion
|
||||
-fif-conversion2
|
||||
-fmerge-constants
|
||||
-foptimize-sibling-calls
|
||||
-fpeephole2
|
||||
-fregmove
|
||||
-freorder-blocks
|
||||
-freorder-functions
|
||||
-frerun-cse-after-loop
|
||||
-fsched-interblock
|
||||
-fsched-spec
|
||||
-fstrict-overflow
|
||||
-fthread-jumps
|
||||
-ftree-ccp
|
||||
-ftree-ch
|
||||
-ftree-copyrename
|
||||
-ftree-dce
|
||||
-ftree-dominator-opts
|
||||
-ftree-fre
|
||||
-ftree-lrs
|
||||
-ftree-pre
|
||||
-ftree-sra
|
||||
-ftree-ter
|
||||
-ftree-vrp
|
||||
-funit-at-a-time)
|
||||
|
||||
# Debug - Build
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
|
||||
# add defines
|
||||
add_definitions(${CommonFlags} ${DebugFlags} -DPCSX2_DEBUG -DPCSX2_DEVBUILD)
|
||||
endif(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
|
||||
# Devel - Build
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Devel)
|
||||
|
||||
# add defines
|
||||
add_definitions(${CommonFlags} ${OptimizationFlags} -DPCSX2_DEVBUILD)
|
||||
endif(CMAKE_BUILD_TYPE STREQUAL Devel)
|
||||
|
||||
# Release - Build
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Release)
|
||||
|
||||
# add defines
|
||||
add_definitions(${CommonFlags} ${OptimizationFlags})
|
||||
endif(CMAKE_BUILD_TYPE STREQUAL Release)
|
||||
|
||||
# variable with all sources of this library
|
||||
set(UtilitiesSources
|
||||
../../include/Utilities/FixedPointTypes.inl
|
||||
../../include/Utilities/EventSource.inl
|
||||
../../include/Utilities/SafeArray.inl
|
||||
../../include/Utilities/TlsVariable.inl
|
||||
AlignedMalloc.cpp
|
||||
CheckedStaticBox.cpp
|
||||
Console.cpp
|
||||
EventSource.cpp
|
||||
Exceptions.cpp
|
||||
FastFormatString.cpp
|
||||
HashTools.cpp
|
||||
IniInterface.cpp
|
||||
Linux/LnxHostSys.cpp
|
||||
Linux/LnxMisc.cpp
|
||||
Linux/LnxThreads.cpp
|
||||
Mutex.cpp
|
||||
PathUtils.cpp
|
||||
PrecompiledHeader.cpp
|
||||
pxCheckBox.cpp
|
||||
pxRadioPanel.cpp
|
||||
pxStaticText.cpp
|
||||
pxStreams.cpp
|
||||
pxTranslate.cpp
|
||||
pxWindowTextWriter.cpp
|
||||
Semaphore.cpp
|
||||
StringHelpers.cpp
|
||||
ThreadingDialogs.cpp
|
||||
ThreadTools.cpp
|
||||
vssprintf.cpp
|
||||
wxAppWithHelpers.cpp
|
||||
wxGuiTools.cpp
|
||||
wxHelpers.cpp
|
||||
x86/MemcpyVibes.cpp
|
||||
# x86/MemcpyFast.cpp
|
||||
)
|
||||
|
||||
# collect .S files
|
||||
set(UtilitiesSSources
|
||||
x86/MemcpyFast.S)
|
||||
|
||||
# variable with all headers of this library
|
||||
set(UtilitiesHeaders
|
||||
../../include/Utilities/Assertions.h
|
||||
../../include/Utilities/CheckedStaticBox.h
|
||||
../../include/Utilities/Console.h
|
||||
../../include/Utilities/Dependencies.h
|
||||
../../include/Utilities/EventSource.h
|
||||
../../include/Utilities/Exceptions.h
|
||||
../../include/Utilities/FixedPointTypes.h
|
||||
../../include/Utilities/General.h
|
||||
../../include/Utilities/HashMap.h
|
||||
../../include/Utilities/lnx_memzero.h
|
||||
../../include/Utilities/MemcpyFast.h
|
||||
../../include/Utilities/Path.h
|
||||
../../include/Utilities/pxCheckBox.h
|
||||
../../include/Utilities/pxRadioPanel.h
|
||||
../../include/Utilities/pxStaticText.h
|
||||
../../include/Utilities/pxStreams.h
|
||||
../../include/Utilities/RedtapeWindows.h
|
||||
../../include/Utilities/SafeArray.h
|
||||
../../include/Utilities/ScopedAlloc.h
|
||||
../../include/Utilities/ScopedPtr.h
|
||||
../../include/Utilities/ScopedPtrMT.h
|
||||
../../include/Utilities/StringHelpers.h
|
||||
../../include/Utilities/Threading.h
|
||||
../../include/Utilities/ThreadingDialogs.h
|
||||
../../include/Utilities/TraceLog.h
|
||||
../../include/Utilities/wxAppWithHelpers.h
|
||||
../../include/Utilities/wxBaseTools.h
|
||||
../../include/Utilities/wxGuiTools.h
|
||||
PrecompiledHeader.h)
|
||||
|
||||
include_directories(.)
|
||||
|
||||
# change language of .S-files to c++
|
||||
set_source_files_properties(${UtilitiesSSources} PROPERTIES LANGUAGE CXX)
|
||||
|
||||
# add library
|
||||
add_library(${Output} STATIC ${UtilitiesSources} ${UtilitiesHeaders} ${UtilitiesSSources})
|
||||
|
||||
# link target with wx
|
||||
target_link_libraries(${Output} ${wxWidgets_LIBRARIES})
|
||||
|
||||
# User flags options
|
||||
if(NOT USER_CMAKE_LD_FLAGS STREQUAL "")
|
||||
target_link_libraries(${Output} "${USER_CMAKE_LD_FLAGS}")
|
||||
endif(NOT USER_CMAKE_LD_FLAGS STREQUAL "")
|
||||
# Check that people use the good file
|
||||
if(NOT TOP_CMAKE_WAS_SOURCED)
|
||||
message(FATAL_ERROR "
|
||||
You did not 'cmake' the good CMakeLists.txt file. Use the one in the top dir.
|
||||
It is advice to delete all wrongly generated cmake stuff => CMakeFiles & CMakeCache.txt")
|
||||
endif(NOT TOP_CMAKE_WAS_SOURCED)
|
||||
|
||||
|
||||
# library name
|
||||
set(Output Utilities)
|
||||
|
||||
# set common flags
|
||||
set(CommonFlags
|
||||
-pthread
|
||||
-fvisibility=hidden
|
||||
-fno-dse
|
||||
-fno-guess-branch-probability
|
||||
-fno-strict-aliasing
|
||||
-fno-tree-dse
|
||||
-pipe
|
||||
-Wno-format
|
||||
-Wno-unused-parameter
|
||||
-Wno-unused-value
|
||||
-Wunused-variable)
|
||||
|
||||
# set warning flags
|
||||
set(DebugFlags
|
||||
-g
|
||||
-W)
|
||||
|
||||
# set optimization flags
|
||||
set(OptimizationFlags
|
||||
-falign-functions
|
||||
-falign-jumps
|
||||
-falign-labels
|
||||
-falign-loops
|
||||
-fcaller-saves
|
||||
-fcprop-registers
|
||||
-fcrossjumping
|
||||
-fcse-follow-jumps
|
||||
-fcse-skip-blocks
|
||||
-fdefer-pop
|
||||
-fdelete-null-pointer-checks
|
||||
-fgcse
|
||||
-fgcse-lm
|
||||
-fif-conversion
|
||||
-fif-conversion2
|
||||
-fmerge-constants
|
||||
-foptimize-sibling-calls
|
||||
-fpeephole2
|
||||
-fregmove
|
||||
-freorder-blocks
|
||||
-freorder-functions
|
||||
-frerun-cse-after-loop
|
||||
-fsched-interblock
|
||||
-fsched-spec
|
||||
-fstrict-overflow
|
||||
-fthread-jumps
|
||||
-ftree-ccp
|
||||
-ftree-ch
|
||||
-ftree-copyrename
|
||||
-ftree-dce
|
||||
-ftree-dominator-opts
|
||||
-ftree-fre
|
||||
-ftree-lrs
|
||||
-ftree-pre
|
||||
-ftree-sra
|
||||
-ftree-ter
|
||||
-ftree-vrp
|
||||
-funit-at-a-time)
|
||||
|
||||
# Debug - Build
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
|
||||
# add defines
|
||||
add_definitions(${CommonFlags} ${DebugFlags} -DPCSX2_DEBUG -DPCSX2_DEVBUILD)
|
||||
endif(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
|
||||
# Devel - Build
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Devel)
|
||||
|
||||
# add defines
|
||||
add_definitions(${CommonFlags} ${OptimizationFlags} -DPCSX2_DEVBUILD)
|
||||
endif(CMAKE_BUILD_TYPE STREQUAL Devel)
|
||||
|
||||
# Release - Build
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Release)
|
||||
|
||||
# add defines
|
||||
add_definitions(${CommonFlags} ${OptimizationFlags})
|
||||
endif(CMAKE_BUILD_TYPE STREQUAL Release)
|
||||
|
||||
# variable with all sources of this library
|
||||
set(UtilitiesSources
|
||||
../../include/Utilities/FixedPointTypes.inl
|
||||
../../include/Utilities/EventSource.inl
|
||||
../../include/Utilities/SafeArray.inl
|
||||
../../include/Utilities/TlsVariable.inl
|
||||
AlignedMalloc.cpp
|
||||
CheckedStaticBox.cpp
|
||||
Console.cpp
|
||||
EventSource.cpp
|
||||
Exceptions.cpp
|
||||
FastFormatString.cpp
|
||||
HashTools.cpp
|
||||
IniInterface.cpp
|
||||
Linux/LnxHostSys.cpp
|
||||
Linux/LnxMisc.cpp
|
||||
Linux/LnxThreads.cpp
|
||||
Mutex.cpp
|
||||
PathUtils.cpp
|
||||
PrecompiledHeader.cpp
|
||||
pxCheckBox.cpp
|
||||
pxRadioPanel.cpp
|
||||
pxStaticText.cpp
|
||||
pxStreams.cpp
|
||||
pxTranslate.cpp
|
||||
pxWindowTextWriter.cpp
|
||||
Semaphore.cpp
|
||||
StringHelpers.cpp
|
||||
ThreadingDialogs.cpp
|
||||
ThreadTools.cpp
|
||||
vssprintf.cpp
|
||||
VirtualMemory.cpp
|
||||
wxAppWithHelpers.cpp
|
||||
wxGuiTools.cpp
|
||||
wxHelpers.cpp
|
||||
x86/MemcpyVibes.cpp
|
||||
# x86/MemcpyFast.cpp
|
||||
)
|
||||
|
||||
# collect .S files
|
||||
set(UtilitiesSSources
|
||||
x86/MemcpyFast.S)
|
||||
|
||||
# variable with all headers of this library
|
||||
set(UtilitiesHeaders
|
||||
../../include/Utilities/Assertions.h
|
||||
../../include/Utilities/CheckedStaticBox.h
|
||||
../../include/Utilities/Console.h
|
||||
../../include/Utilities/Dependencies.h
|
||||
../../include/Utilities/EventSource.h
|
||||
../../include/Utilities/Exceptions.h
|
||||
../../include/Utilities/FixedPointTypes.h
|
||||
../../include/Utilities/General.h
|
||||
../../include/Utilities/HashMap.h
|
||||
../../include/Utilities/lnx_memzero.h
|
||||
../../include/Utilities/MemcpyFast.h
|
||||
../../include/Utilities/MemsetFast.inl
|
||||
../../include/Utilities/Path.h
|
||||
../../include/Utilities/PageFaultSource.h
|
||||
../../include/Utilities/pxCheckBox.h
|
||||
../../include/Utilities/pxRadioPanel.h
|
||||
../../include/Utilities/pxStaticText.h
|
||||
../../include/Utilities/pxStreams.h
|
||||
../../include/Utilities/RedtapeWindows.h
|
||||
../../include/Utilities/SafeArray.h
|
||||
../../include/Utilities/ScopedAlloc.h
|
||||
../../include/Utilities/ScopedPtr.h
|
||||
../../include/Utilities/ScopedPtrMT.h
|
||||
../../include/Utilities/StringHelpers.h
|
||||
../../include/Utilities/Threading.h
|
||||
../../include/Utilities/ThreadingDialogs.h
|
||||
../../include/Utilities/TraceLog.h
|
||||
../../include/Utilities/wxAppWithHelpers.h
|
||||
../../include/Utilities/wxBaseTools.h
|
||||
../../include/Utilities/wxGuiTools.h
|
||||
PrecompiledHeader.h)
|
||||
|
||||
include_directories(.)
|
||||
|
||||
# change language of .S-files to c++
|
||||
set_source_files_properties(${UtilitiesSSources} PROPERTIES LANGUAGE CXX)
|
||||
|
||||
# add library
|
||||
add_library(${Output} STATIC ${UtilitiesSources} ${UtilitiesHeaders} ${UtilitiesSSources})
|
||||
|
||||
# link target with wx
|
||||
target_link_libraries(${Output} ${wxWidgets_LIBRARIES})
|
||||
|
||||
# User flags options
|
||||
if(NOT USER_CMAKE_LD_FLAGS STREQUAL "")
|
||||
target_link_libraries(${Output} "${USER_CMAKE_LD_FLAGS}")
|
||||
endif(NOT USER_CMAKE_LD_FLAGS STREQUAL "")
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
// for lack of a better place...
|
||||
Fnptr_OutOfMemory pxDoOutOfMemory = NULL;
|
||||
|
||||
static wxString GetTranslation( const wxChar* msg )
|
||||
{
|
||||
return msg ? wxGetTranslation( msg ) : wxEmptyString;
|
||||
|
@ -68,12 +71,6 @@ wxString DiagnosticOrigin::ToString( const wxChar* msg ) const
|
|||
}
|
||||
|
||||
|
||||
bool pxAssertImpl_LogIt( const DiagnosticOrigin& origin, const wxChar *msg )
|
||||
{
|
||||
wxLogError( L"%s", origin.ToString( msg ).c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Because wxTrap isn't available on Linux builds of wxWidgets (non-Debug, typically)
|
||||
void pxTrap()
|
||||
{
|
||||
|
@ -94,6 +91,16 @@ void pxTrap()
|
|||
#endif // Win/Unix
|
||||
}
|
||||
|
||||
|
||||
bool pxAssertImpl_LogIt( const DiagnosticOrigin& origin, const wxChar *msg )
|
||||
{
|
||||
//wxLogError( L"%s", origin.ToString( msg ).c_str() );
|
||||
wxMessageOutputDebug().Printf( L"%s", origin.ToString( msg ).c_str() );
|
||||
pxTrap();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
DEVASSERT_INLINE void pxOnAssert( const DiagnosticOrigin& origin, const wxChar* msg )
|
||||
{
|
||||
// Recursion guard: Allow at least one recursive call. This is useful because sometimes
|
||||
|
@ -191,19 +198,69 @@ Exception::RuntimeError::RuntimeError( const std::exception& ex, const wxString&
|
|||
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());
|
||||
FastFormatUnicode retmsg;
|
||||
retmsg.Write(L"Out of memory");
|
||||
if (!AllocDescription.IsEmpty())
|
||||
retmsg.Write(L" while allocating '%s'", AllocDescription.c_str());
|
||||
|
||||
if (!m_message_diag.IsEmpty())
|
||||
retmsg.Write(L":\n%s", m_message_diag.c_str());
|
||||
|
||||
return retmsg;
|
||||
}
|
||||
|
||||
wxString Exception::OutOfMemory::FormatDisplayMessage() const
|
||||
{
|
||||
if (m_message_user.IsEmpty()) return FormatDisplayMessage();
|
||||
return m_message_user + pxsFmt( L"\n\nInternal allocation descriptor: %s", AllocDescription.c_str());
|
||||
FastFormatUnicode retmsg;
|
||||
retmsg.Write( L"%s", _("Oh noes! Out of memory!") );
|
||||
|
||||
if (!m_message_diag.IsEmpty())
|
||||
retmsg.Write(L"\n\n%s", m_message_diag.c_str());
|
||||
|
||||
return retmsg;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::VirtualMemoryMapConflict (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
Exception::VirtualMemoryMapConflict::VirtualMemoryMapConflict( const wxString& allocdesc )
|
||||
{
|
||||
AllocDescription = allocdesc;
|
||||
m_message_user = _("Virtual memory mapping failure! Your system may have conflicting device drivers, services, or may simply have insufficient memory or resources to meet PCSX2's lofty needs.");
|
||||
}
|
||||
|
||||
wxString Exception::VirtualMemoryMapConflict::FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retmsg;
|
||||
retmsg.Write(L"Virtual memory map failed");
|
||||
if (!AllocDescription.IsEmpty())
|
||||
retmsg.Write(L" while reserving '%s'", AllocDescription.c_str());
|
||||
|
||||
if (!m_message_diag.IsEmpty())
|
||||
retmsg.Write(L":\n%s", m_message_diag.c_str());
|
||||
|
||||
return retmsg;
|
||||
}
|
||||
|
||||
wxString Exception::VirtualMemoryMapConflict::FormatDisplayMessage() const
|
||||
{
|
||||
FastFormatUnicode retmsg;
|
||||
retmsg.Write( L"%s",
|
||||
pxE( ".Error:VirtualMemoryMap",
|
||||
L"There is not enough virtual memory available, or necessary virtual memory "
|
||||
L"mappings have already been reserved by other processes, services, or DLLs."
|
||||
)
|
||||
);
|
||||
|
||||
if (!m_message_diag.IsEmpty())
|
||||
retmsg.Write(L"\n\n%s", m_message_diag.c_str());
|
||||
|
||||
return retmsg;
|
||||
}
|
||||
|
||||
|
||||
|
@ -218,20 +275,120 @@ wxString Exception::CancelEvent::FormatDisplayMessage() const
|
|||
return L"Action canceled: " + m_message_diag;
|
||||
}
|
||||
|
||||
wxString Exception::Stream::FormatDiagnosticMessage() const
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::BadStream (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
wxString Exception::BadStream::FormatDiagnosticMessage() const
|
||||
{
|
||||
return pxsFmt(
|
||||
L"%s\n\tFile/Object: %s",
|
||||
m_message_diag.c_str(), StreamName.c_str()
|
||||
);
|
||||
FastFormatUnicode retval;
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
wxString Exception::Stream::FormatDisplayMessage() const
|
||||
wxString Exception::BadStream::FormatDisplayMessage() const
|
||||
{
|
||||
wxString retval( m_message_user );
|
||||
if (!StreamName.IsEmpty())
|
||||
retval += L"\n\n" + pxsFmt( _("Path: %s"), StreamName.c_str() );
|
||||
FastFormatUnicode retval;
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void Exception::BadStream::_formatDiagMsg( FastFormatUnicode& dest ) const
|
||||
{
|
||||
dest.Write( L"Path: " );
|
||||
if (!StreamName.IsEmpty())
|
||||
dest.Write( L"%s", StreamName.c_str() );
|
||||
else
|
||||
dest.Write( L"[Unnamed or unknown]" );
|
||||
|
||||
if (!m_message_diag.IsEmpty())
|
||||
dest.Write(L"\n%s", m_message_diag.c_str());
|
||||
}
|
||||
|
||||
void Exception::BadStream::_formatUserMsg( FastFormatUnicode& dest ) const
|
||||
{
|
||||
dest.Write( _("Path: ") );
|
||||
if (!StreamName.IsEmpty())
|
||||
dest.Write( L"%s", StreamName.c_str() );
|
||||
else
|
||||
dest.Write( _("[Unnamed or unknown]") );
|
||||
|
||||
if (!m_message_user.IsEmpty())
|
||||
dest.Write(L"\n%s", m_message_user.c_str());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::CannotCreateStream (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
wxString Exception::CannotCreateStream::FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("File could not be created.");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
wxString Exception::CannotCreateStream::FormatDisplayMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write(_("A file could not be created."));
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::FileNotFound (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
wxString Exception::FileNotFound::FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("File not found.");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
wxString Exception::FileNotFound::FormatDisplayMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write(_("File not found."));
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::AccessDenied (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
wxString Exception::AccessDenied::FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("Permission denied to file.");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
wxString Exception::AccessDenied::FormatDisplayMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write(_("Permission denied while trying to open file, likely due to insufficient user account rights."));
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::EndOfStream (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
wxString Exception::EndOfStream::FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("Unexpected end of file or stream.");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
wxString Exception::EndOfStream::FormatDisplayMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write(_("Unexpected end of file or stream encountered. File is probably truncated or corrupted."));
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -249,7 +406,7 @@ BaseException* Exception::FromErrno( const wxString& streamname, int errcode )
|
|||
{
|
||||
case EINVAL:
|
||||
pxFailDev( L"Invalid argument" );
|
||||
return &(new Exception::Stream( streamname ))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)" );
|
||||
return &(new Exception::BadStream( streamname ))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)" );
|
||||
|
||||
case EACCES: // Access denied!
|
||||
return new Exception::AccessDenied( streamname );
|
||||
|
@ -270,6 +427,6 @@ BaseException* Exception::FromErrno( const wxString& streamname, int errcode )
|
|||
return &(new Exception::BadStream( streamname ))->SetDiagMsg(L"Bad file number");
|
||||
|
||||
default:
|
||||
return &(new Exception::Stream( streamname ))->SetDiagMsg(pxsFmt( L"General file/stream error [errno: %d]", errcode ));
|
||||
return &(new Exception::BadStream( streamname ))->SetDiagMsg(pxsFmt( L"General file/stream error [errno: %d]", errcode ));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ protected:
|
|||
typedef char CharType;
|
||||
typedef CharBufferType BufferType;
|
||||
|
||||
static const uint BufferCount = 4;
|
||||
static const uint BufferCount = 6;
|
||||
|
||||
BufferType m_buffers[BufferCount];
|
||||
uint m_curslot;
|
||||
|
@ -69,7 +69,7 @@ public:
|
|||
|
||||
for (uint i=0; i<BufferCount; ++i)
|
||||
{
|
||||
m_buffers[i].Alloc(1024);
|
||||
m_buffers[i].Alloc(512);
|
||||
}
|
||||
|
||||
m_curslot = 0;
|
||||
|
@ -174,7 +174,7 @@ static __ri void format_that_ascii_mess( CharBufferType& buffer, uint writepos,
|
|||
|
||||
len += writepos;
|
||||
if (len < size) break;
|
||||
buffer.Alloc( len + 128 );
|
||||
buffer.Resize( len + 128 );
|
||||
};
|
||||
|
||||
// performing an assertion or log of a truncated string is unsafe, so let's not; even
|
||||
|
@ -205,7 +205,7 @@ static __ri uint format_that_unicode_mess( CharBufferType& buffer, uint writepos
|
|||
|
||||
len += writepos;
|
||||
if (len < size) return len;
|
||||
buffer.Alloc( (len + 128) * sizeof(wxChar) );
|
||||
buffer.Resize( (len + 128) * sizeof(wxChar) );
|
||||
};
|
||||
|
||||
// performing an assertion or log of a truncated string is unsafe, so let's not; even
|
||||
|
|
|
@ -15,50 +15,204 @@
|
|||
|
||||
|
||||
#include "../PrecompiledHeader.h"
|
||||
#include "PageFaultSource.h"
|
||||
|
||||
#include <wx/thread.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
namespace HostSys
|
||||
extern void SignalExit(int sig);
|
||||
|
||||
static const uptr m_pagemask = getpagesize()-1;
|
||||
|
||||
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
|
||||
static void SysPageFaultSignalFilter( int signal, siginfo_t *siginfo, void * )
|
||||
{
|
||||
static const uptr m_pagemask = getpagesize()-1;
|
||||
// [TODO] : Add a thread ID filter to the Linux Signal handler here.
|
||||
// Rationale: On windows, the __try/__except model allows per-thread specific behavior
|
||||
// for page fault handling. On linux, there is a single signal handler for the whole
|
||||
// process, but the handler is executed by the thread that caused the exception.
|
||||
|
||||
void *Mmap(uptr base, u32 size)
|
||||
|
||||
// Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done
|
||||
// from the context of the current thread and stackframe. So long as the thread is not
|
||||
// the main/ui thread, use of the px assertion system should be safe. Use of stdio should
|
||||
// be safe even on the main thread.
|
||||
// (in other words, stdio limitations only really apply to process-level asynchronous
|
||||
// signals)
|
||||
|
||||
// Note: Use of stdio functions isn't safe here. Avoid console logs,
|
||||
// assertions, file logs, or just about anything else useful.
|
||||
|
||||
Source_PageFault->Dispatch( PageFaultInfo( (uptr)siginfo->si_addr & ~m_pagemask ) );
|
||||
|
||||
// resumes execution right where we left off (re-executes instruction that
|
||||
// caused the SIGSEGV).
|
||||
if (Source_PageFault->WasHandled()) return;
|
||||
|
||||
if (!wxThread::IsMain())
|
||||
{
|
||||
u8 *Mem;
|
||||
Mem = (u8*)mmap((uptr*)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
|
||||
if (Mem == MAP_FAILED) Console.Warning("Mmap Failed!");
|
||||
|
||||
return Mem;
|
||||
pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr));
|
||||
}
|
||||
|
||||
void Munmap(uptr base, u32 size)
|
||||
{
|
||||
munmap((uptr*)base, size);
|
||||
}
|
||||
// Bad mojo! Completely invalid address.
|
||||
// Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
|
||||
|
||||
void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution )
|
||||
wxTrap();
|
||||
if (!IsDebugBuild) raise( SIGKILL );
|
||||
}
|
||||
|
||||
void _platform_InstallSignalHandler()
|
||||
{
|
||||
Console.WriteLn("Installing POSIX SIGSEGV handler...");
|
||||
struct sigaction sa;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = SysPageFaultSignalFilter;
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
}
|
||||
|
||||
static __ri void PageSizeAssertionTest( size_t size )
|
||||
{
|
||||
pxAssertMsg( (__pagesize == getpagesize()), pxsFmt(
|
||||
"Internal system error: Operating system pagesize does not match compiled pagesize.\n\t"
|
||||
L"\tOS Page Size: 0x%x (%d), Compiled Page Size: 0x%x (%u)",
|
||||
getpagesize(), getpagesize(), __pagesize, __pagesize )
|
||||
);
|
||||
|
||||
pxAssertDev( (size & (__pagesize-1)) == 0, pxsFmt(
|
||||
L"Memory block size must be a multiple of the target platform's page size.\n"
|
||||
L"\tPage Size: 0x%x (%u), Block Size: 0x%x (%u)",
|
||||
__pagesize, __pagesize, size, size )
|
||||
);
|
||||
}
|
||||
|
||||
// returns FALSE if the mprotect call fails with an ENOMEM.
|
||||
// Raises assertions on other types of POSIX errors (since those typically reflect invalid object
|
||||
// or memory states).
|
||||
static bool _memprotect( void* baseaddr, size_t size, const PageProtectionMode& mode )
|
||||
{
|
||||
PageSizeAssertionTest(size);
|
||||
|
||||
uint lnxmode = 0;
|
||||
|
||||
if (mode.CanWrite()) lnxmode |= PROT_WRITE;
|
||||
if (mode.CanRead()) lnxmode |= PROT_READ;
|
||||
if (mode.CanExecute()) lnxmode |= PROT_EXEC | PROT_READ;
|
||||
|
||||
const int result = mprotect( baseaddr, size, lnxmode );
|
||||
|
||||
if (result == 0) return true;
|
||||
|
||||
switch(errno)
|
||||
{
|
||||
pxAssertDev( (size & (__pagesize-1)) == 0, wxsFormat(
|
||||
L"Memory block size must be a multiple of the target platform's page size.\n"
|
||||
L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)",
|
||||
__pagesize, __pagesize, size, size )
|
||||
case EINVAL:
|
||||
pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)",
|
||||
baseaddr, (uptr)baseaddr+size, mode.ToString().c_str())
|
||||
);
|
||||
break;
|
||||
|
||||
case EACCES:
|
||||
pxFailDev(pxsFmt(L"mprotect returned EACCES @ 0x%08X -> 0x%08X (mode=%s)",
|
||||
baseaddr, (uptr)baseaddr+size, mode.ToString().c_str())
|
||||
);
|
||||
break;
|
||||
|
||||
case ENOMEM:
|
||||
// caller handles assertion or exception, or whatever.
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void* HostSys::MmapReservePtr(void* base, size_t size)
|
||||
{
|
||||
PageSizeAssertionTest(size);
|
||||
|
||||
// On linux a reserve-without-commit is performed by using mmap on a read-only
|
||||
// or anonymous source, with PROT_NONE (no-access) permission. Since the mapping
|
||||
// is completely inaccessible, the OS will simply reserve it and will not put it
|
||||
// against the commit table.
|
||||
return mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
|
||||
bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode)
|
||||
{
|
||||
// In linux, reserved memory is automatically committed when its permissions are
|
||||
// changed to something other than PROT_NONE. If the user is committing memory
|
||||
// as PROT_NONE, then just ignore this call (memory will be committed automatically
|
||||
// later when the user changes permissions to something useful via calls to MemProtect).
|
||||
|
||||
if (mode.IsNone()) return false;
|
||||
|
||||
if (_memprotect( base, size, mode )) return true;
|
||||
|
||||
if (!pxDoOutOfMemory) return false;
|
||||
pxDoOutOfMemory(size);
|
||||
return _memprotect( base, size, mode );
|
||||
}
|
||||
|
||||
void HostSys::MmapResetPtr(void* base, size_t size)
|
||||
{
|
||||
// On linux the only way to reset the memory is to unmap and remap it as PROT_NONE.
|
||||
// That forces linux to unload all committed pages and start from scratch.
|
||||
|
||||
// FIXME: Ideally this code would have some threading lock on it to prevent any other
|
||||
// malloc/free code in the current process from interfering with the operation, but I
|
||||
// can't think of any good way to do that. (generally it shouldn't be a problem in
|
||||
// PCSX2 anyway, since MmapReset is only called when the ps2vm is suspended; so that
|
||||
// pretty well stops all PCSX2 threads anyway).
|
||||
|
||||
Munmap(base, size);
|
||||
void* result = Mmap((uptr)base, size);
|
||||
|
||||
pxAssertRel ((uptr)result != (uptr)base, pxsFmt(
|
||||
"Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped. "
|
||||
"This is likely caused by multi-thread memory contention.", base, (uptr)base+size
|
||||
));
|
||||
}
|
||||
|
||||
void* HostSys::MmapReserve(uptr base, size_t size)
|
||||
{
|
||||
return MmapReservePtr((void*)base, size);
|
||||
}
|
||||
|
||||
bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode)
|
||||
{
|
||||
return MmapCommitPtr( (void*)base, size, mode );
|
||||
}
|
||||
|
||||
void HostSys::MmapReset(uptr base, size_t size)
|
||||
{
|
||||
MmapResetPtr((void*)base, size);
|
||||
}
|
||||
|
||||
void* HostSys::Mmap(uptr base, size_t size)
|
||||
{
|
||||
PageSizeAssertionTest(size);
|
||||
|
||||
// MAP_ANONYMOUS - means we have no associated file handle (or device).
|
||||
|
||||
return mmap((void*)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
|
||||
void HostSys::Munmap(uptr base, size_t size)
|
||||
{
|
||||
if (!base) return;
|
||||
munmap((void*)base, size);
|
||||
}
|
||||
|
||||
void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode )
|
||||
{
|
||||
if (!_memprotect(baseaddr, size, mode))
|
||||
{
|
||||
throw Exception::OutOfMemory( L"MemProtect" )
|
||||
.SetDiagMsg(pxsFmt( L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)",
|
||||
baseaddr, (uptr)baseaddr+size, mode.ToString().c_str()
|
||||
)
|
||||
);
|
||||
|
||||
int lnxmode = 0;
|
||||
|
||||
// make sure size is aligned to the system page size:
|
||||
// Check is redundant against the assertion above, but might as well...
|
||||
size = (size + m_pagemask) & ~m_pagemask;
|
||||
|
||||
switch( mode )
|
||||
{
|
||||
case Protect_NoAccess: break;
|
||||
case Protect_ReadOnly: lnxmode = PROT_READ; break;
|
||||
case Protect_ReadWrite: lnxmode = PROT_READ | PROT_WRITE; break;
|
||||
}
|
||||
|
||||
if( allowExecution ) lnxmode |= PROT_EXEC;
|
||||
mprotect( baseaddr, size, lnxmode );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ wxString Path::Combine( const wxDirName& srcPath, const wxFileName& srcFile )
|
|||
|
||||
wxString Path::Combine( const wxString& srcPath, const wxDirName& srcFile )
|
||||
{
|
||||
return ((wxDirName)srcPath + srcFile).ToString();
|
||||
return (wxDirName( srcPath ) + srcFile).ToString();
|
||||
}
|
||||
|
||||
// Replaces the extension of the file with the one given.
|
||||
|
|
|
@ -118,6 +118,7 @@ wxString JoinString( const wxChar** src, const wxString& separator )
|
|||
return dest;
|
||||
}
|
||||
|
||||
|
||||
// Attempts to parse and return a value for the given template type, and throws a ParseError
|
||||
// exception if the parse fails. The template type can be anything that is supported/
|
||||
// implemented via one of the TryParse() method overloads.
|
||||
|
|
|
@ -0,0 +1,470 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "PageFaultSource.h"
|
||||
|
||||
#ifndef __WXMSW__
|
||||
#include <wx/thread.h>
|
||||
#endif
|
||||
|
||||
#include "EventSource.inl"
|
||||
#include "MemsetFast.inl"
|
||||
|
||||
template class EventSource< IEventListener_PageFault >;
|
||||
|
||||
SrcType_PageFault* Source_PageFault = NULL;
|
||||
|
||||
void pxInstallSignalHandler()
|
||||
{
|
||||
if (!Source_PageFault)
|
||||
{
|
||||
Source_PageFault = new SrcType_PageFault();
|
||||
}
|
||||
|
||||
_platform_InstallSignalHandler();
|
||||
|
||||
// NOP on Win32 systems -- we use __try{} __except{} instead.
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EventListener_PageFault (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
EventListener_PageFault::EventListener_PageFault()
|
||||
{
|
||||
pxAssume(Source_PageFault);
|
||||
Source_PageFault->Add( *this );
|
||||
}
|
||||
|
||||
EventListener_PageFault::~EventListener_PageFault() throw()
|
||||
{
|
||||
if (Source_PageFault)
|
||||
Source_PageFault->Remove( *this );
|
||||
}
|
||||
|
||||
void SrcType_PageFault::Dispatch( const PageFaultInfo& params )
|
||||
{
|
||||
m_handled = false;
|
||||
_parent::Dispatch( params );
|
||||
}
|
||||
|
||||
void SrcType_PageFault::_DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt )
|
||||
{
|
||||
do {
|
||||
(*iter)->DispatchEvent( evt, m_handled );
|
||||
} while( (++iter != iend) && !m_handled );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VirtualMemoryReserve (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
VirtualMemoryReserve::VirtualMemoryReserve( const wxString& name, size_t size )
|
||||
: m_name( name )
|
||||
{
|
||||
m_defsize = size;
|
||||
|
||||
m_pages_commited = 0;
|
||||
m_pages_reserved = 0;
|
||||
m_baseptr = NULL;
|
||||
m_prot_mode = PageAccess_None();
|
||||
}
|
||||
|
||||
VirtualMemoryReserve& VirtualMemoryReserve::SetName( const wxString& newname )
|
||||
{
|
||||
m_name = newname;
|
||||
return *this;
|
||||
}
|
||||
|
||||
VirtualMemoryReserve& VirtualMemoryReserve::SetBaseAddr( uptr newaddr )
|
||||
{
|
||||
if (!pxAssertDev(!m_pages_reserved, "Invalid object state: you must release the virtual memory reserve prior to changing its base address!")) return *this;
|
||||
|
||||
m_baseptr = (void*)newaddr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
VirtualMemoryReserve& VirtualMemoryReserve::SetPageAccessOnCommit( const PageProtectionMode& mode )
|
||||
{
|
||||
m_prot_mode = mode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Notes:
|
||||
// * This method should be called if the object is already in an released (unreserved) state.
|
||||
// Subsequent calls will be ignored, and the existing reserve will be returned.
|
||||
//
|
||||
// Parameters:
|
||||
// size - size of the reserve, in bytes. (optional)
|
||||
// If not specified (or zero), then the default size specified in the constructor for the
|
||||
// object instance is used.
|
||||
//
|
||||
// upper_bounds - criteria that must be met for the allocation to be valid.
|
||||
// If the OS refuses to allocate the memory below the specified address, the
|
||||
// object will fail to initialize and an exception will be thrown.
|
||||
void* VirtualMemoryReserve::Reserve( size_t size, uptr base, uptr upper_bounds )
|
||||
{
|
||||
if (!pxAssertDev( m_baseptr == NULL, "(VirtualMemoryReserve) Invalid object state; object has already been reserved." ))
|
||||
return m_baseptr;
|
||||
|
||||
if (!size) size = m_defsize;
|
||||
if (!size) return NULL;
|
||||
|
||||
m_pages_reserved = (size + __pagesize-4) / __pagesize;
|
||||
uptr reserved_bytes = m_pages_reserved * __pagesize;
|
||||
|
||||
m_baseptr = (void*)HostSys::MmapReserve(base, reserved_bytes);
|
||||
|
||||
if (!m_baseptr || (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)))
|
||||
{
|
||||
DevCon.Warning( L"%s: host memory @ %s -> %s is unavailable; attempting to map elsewhere...",
|
||||
m_name.c_str(), pxsPtr(base), pxsPtr(base + size) );
|
||||
|
||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||
|
||||
if (base)
|
||||
{
|
||||
// Let's try again at an OS-picked memory area, and then hope it meets needed
|
||||
// boundschecking criteria below.
|
||||
m_baseptr = HostSys::MmapReserve( 0, reserved_bytes );
|
||||
}
|
||||
}
|
||||
|
||||
if ((upper_bounds != 0) && (((uptr)m_baseptr + reserved_bytes) > upper_bounds))
|
||||
{
|
||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||
// returns null, caller should throw an exception or handle appropriately.
|
||||
}
|
||||
|
||||
if (!m_baseptr) return NULL;
|
||||
|
||||
FastFormatUnicode mbkb;
|
||||
uint mbytes = reserved_bytes / _1mb;
|
||||
if (mbytes)
|
||||
mbkb.Write( "[%umb]", mbytes );
|
||||
else
|
||||
mbkb.Write( "[%ukb]", reserved_bytes / 1024 );
|
||||
|
||||
DevCon.WriteLn( Color_Gray, L"%-32s @ %s -> %s %s", m_name.c_str(),
|
||||
pxsPtr(m_baseptr), pxsPtr((uptr)m_baseptr+reserved_bytes), mbkb.c_str());
|
||||
|
||||
return m_baseptr;
|
||||
}
|
||||
|
||||
// Clears all committed blocks, restoring the allocation to a reserve only.
|
||||
void VirtualMemoryReserve::Reset()
|
||||
{
|
||||
if (!m_pages_commited) return;
|
||||
|
||||
HostSys::MemProtect(m_baseptr, m_pages_commited*__pagesize, PageAccess_None());
|
||||
HostSys::MmapResetPtr(m_baseptr, m_pages_commited*__pagesize);
|
||||
m_pages_commited = 0;
|
||||
}
|
||||
|
||||
void VirtualMemoryReserve::Release()
|
||||
{
|
||||
SafeSysMunmap(m_baseptr, m_pages_reserved*__pagesize);
|
||||
}
|
||||
|
||||
bool VirtualMemoryReserve::Commit()
|
||||
{
|
||||
if (!m_pages_reserved) return false;
|
||||
if (!pxAssert(!m_pages_commited)) return true;
|
||||
|
||||
m_pages_commited = m_pages_reserved;
|
||||
return HostSys::MmapCommitPtr(m_baseptr, m_pages_reserved*__pagesize, m_prot_mode);
|
||||
}
|
||||
|
||||
|
||||
// If growing the array, or if shrinking the array to some point that's still *greater* than the
|
||||
// committed memory range, then attempt a passive "on-the-fly" resize that maps/unmaps some portion
|
||||
// of the reserve.
|
||||
//
|
||||
// If the above conditions are not met, or if the map/unmap fails, this method returns false.
|
||||
// The caller will be responsible for manually resetting the reserve.
|
||||
//
|
||||
// Parameters:
|
||||
// newsize - new size of the reserved buffer, in bytes.
|
||||
bool VirtualMemoryReserve::TryResize( uint newsize )
|
||||
{
|
||||
uint newPages = (newsize + __pagesize - 1) / __pagesize;
|
||||
|
||||
if (newPages > m_pages_reserved)
|
||||
{
|
||||
uint toReservePages = newPages - m_pages_reserved;
|
||||
uint toReserveBytes = toReservePages * __pagesize;
|
||||
|
||||
DevCon.WriteLn( L"%-32s is being expanded by %u pages.", m_name.c_str(), toReservePages);
|
||||
|
||||
m_baseptr = (void*)HostSys::MmapReserve((uptr)GetPtrEnd(), toReserveBytes);
|
||||
|
||||
if (!m_baseptr)
|
||||
{
|
||||
Console.Warning("%-32s could not be passively resized due to virtual memory conflict!");
|
||||
Console.Indent().Warning("(attempted to map memory @ %08p -> %08p)", m_baseptr, (uptr)m_baseptr+toReserveBytes);
|
||||
}
|
||||
|
||||
DevCon.WriteLn( Color_Gray, L"%-32s @ %08p -> %08p [%umb]", m_name.c_str(),
|
||||
m_baseptr, (uptr)m_baseptr+toReserveBytes, toReserveBytes / _1mb);
|
||||
}
|
||||
else if (newPages < m_pages_reserved)
|
||||
{
|
||||
if (m_pages_commited > newsize) return false;
|
||||
|
||||
uint toRemovePages = m_pages_reserved - newPages;
|
||||
uint toRemoveBytes = toRemovePages * __pagesize;
|
||||
|
||||
DevCon.WriteLn( L"%-32s is being shrunk by %u pages.", m_name.c_str(), toRemovePages);
|
||||
|
||||
HostSys::MmapResetPtr(GetPtrEnd(), toRemoveBytes);
|
||||
|
||||
DevCon.WriteLn( Color_Gray, L"%-32s @ %08p -> %08p [%umb]", m_name.c_str(),
|
||||
m_baseptr, (uptr)m_baseptr+toRemoveBytes, toRemoveBytes / _1mb);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseVmReserveListener (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
BaseVmReserveListener::BaseVmReserveListener( const wxString& name, size_t size )
|
||||
: VirtualMemoryReserve( name, size )
|
||||
, m_pagefault_listener( this )
|
||||
{
|
||||
m_blocksize = __pagesize;
|
||||
}
|
||||
|
||||
void BaseVmReserveListener::CommitBlocks( uptr page, uint blocks )
|
||||
{
|
||||
const uptr blocksbytes = blocks * m_blocksize * __pagesize;
|
||||
void* blockptr = (u8*)m_baseptr + (page * __pagesize);
|
||||
|
||||
// Depending on the operating system, this call could fail if the system is low on either
|
||||
// physical ram or virtual memory.
|
||||
if (!HostSys::MmapCommitPtr(blockptr, blocksbytes, m_prot_mode))
|
||||
{
|
||||
throw Exception::OutOfMemory(m_name)
|
||||
.SetDiagMsg(pxsFmt("An additional %u blocks @ 0x%08x were requested, but could not be committed!", blocks, blockptr));
|
||||
}
|
||||
|
||||
u8* init = (u8*)blockptr;
|
||||
u8* endpos = init + blocksbytes;
|
||||
for( ; init<endpos; init += m_blocksize*__pagesize )
|
||||
OnCommittedBlock(init);
|
||||
|
||||
m_pages_commited += m_blocksize * blocks;
|
||||
}
|
||||
|
||||
void BaseVmReserveListener::OnPageFaultEvent(const PageFaultInfo& info, bool& handled)
|
||||
{
|
||||
sptr offset = (info.addr - (uptr)m_baseptr) / __pagesize;
|
||||
if ((offset < 0) || ((uptr)offset >= m_pages_reserved)) return;
|
||||
|
||||
// Linux Note! the SIGNAL handler is very limited in what it can do, and not only can't
|
||||
// we let the C++ exception try to unwind the stack, we may not be able to log it either.
|
||||
// (but we might as well try -- kernel/posix rules says not to do it, but Linux kernel
|
||||
// implementations seem to support it).
|
||||
// Note also that logging the exception and/or issuing an assertion dialog are always
|
||||
// possible if the thread handling the signal is not the main thread.
|
||||
|
||||
// In windows we can let exceptions bubble out of the page fault handler. SEH will more
|
||||
// or less handle them in a semi-expected way, and might even avoid a GPF long enough
|
||||
// for the system to log the error or something.
|
||||
|
||||
#ifndef __WXMSW__
|
||||
try {
|
||||
#endif
|
||||
DoCommitAndProtect( offset );
|
||||
handled = true;
|
||||
|
||||
#ifndef __WXMSW__
|
||||
}
|
||||
catch (Exception::BaseException& ex)
|
||||
{
|
||||
handled = false;
|
||||
if (!wxThread::IsMain())
|
||||
{
|
||||
pxFailRel( ex.FormatDiagnosticMessage() );
|
||||
}
|
||||
else
|
||||
{
|
||||
wxTrap();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SpatialArrayReserve (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
SpatialArrayReserve::SpatialArrayReserve( const wxString& name ) :
|
||||
_parent( name )
|
||||
{
|
||||
m_prot_mode = PageAccess_ReadWrite();
|
||||
}
|
||||
|
||||
uint SpatialArrayReserve::_calcBlockBitArrayLength() const
|
||||
{
|
||||
// divide by 8 (rounded up) to compress 8 bits into each byte.
|
||||
// mask off lower bits (rounded up) to allow for 128-bit alignment and SSE operations.
|
||||
return (((m_numblocks + 7) / 8) + 15) & ~15;
|
||||
}
|
||||
|
||||
void* SpatialArrayReserve::Reserve( size_t size, uptr base, uptr upper_bounds )
|
||||
{
|
||||
void* addr = _parent::Reserve( size, base, upper_bounds );
|
||||
if (!addr) return NULL;
|
||||
|
||||
if (m_blocksize) SetBlockSizeInPages( m_blocksize );
|
||||
m_blockbits.Alloc( _calcBlockBitArrayLength() );
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
// Resets/clears the spatial array, reducing the memory commit pool overhead to zero (0).
|
||||
void SpatialArrayReserve::Reset()
|
||||
{
|
||||
if (m_pages_commited)
|
||||
{
|
||||
u8* curptr = GetPtr();
|
||||
const uint blockBytes = m_blocksize * __pagesize;
|
||||
for (uint i=0; i<m_numblocks; ++i, curptr+=blockBytes)
|
||||
{
|
||||
uint thisbit = 1 << (i & 7);
|
||||
if (!(m_blockbits[i/8] & thisbit)) continue;
|
||||
|
||||
HostSys::MemProtect(curptr, blockBytes, PageAccess_None());
|
||||
HostSys::MmapResetPtr(curptr, blockBytes);
|
||||
}
|
||||
}
|
||||
|
||||
memzero_sse_a(m_blockbits.GetPtr(), _calcBlockBitArrayLength());
|
||||
}
|
||||
|
||||
// Important! The number of blocks of the array will be altered when using this method.
|
||||
//
|
||||
bool SpatialArrayReserve::TryResize( uint newsize )
|
||||
{
|
||||
uint newpages = (newsize + __pagesize - 1) / __pagesize;
|
||||
|
||||
// find the last allocated block -- we cannot be allowed to resize any smaller than that:
|
||||
|
||||
uint i;
|
||||
for (i=m_numblocks-1; i; --i)
|
||||
{
|
||||
uint bit = i & 7;
|
||||
if (m_blockbits[i / 8] & bit) break;
|
||||
}
|
||||
|
||||
uint pages_in_use = i * m_blocksize;
|
||||
if (newpages < pages_in_use) return false;
|
||||
|
||||
if (!_parent::TryResize( newsize )) return false;
|
||||
|
||||
// On success, we must re-calibrate the internal blockbits array.
|
||||
|
||||
m_blockbits.Resize( (m_numblocks + 7) / 8 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This method allows the programmer to specify the block size of the array as a function
|
||||
// of its reserved size. This function *must* be called *after* the reserve has been made,
|
||||
// and *before* the array contents have been accessed.
|
||||
//
|
||||
// Calls to this function prior to initializing the reserve or after the reserve has been
|
||||
// accessed (resulting in committed blocks) will be ignored -- and will generate an assertion
|
||||
// in debug builds.
|
||||
SpatialArrayReserve& SpatialArrayReserve::SetBlockCount( uint blocks )
|
||||
{
|
||||
pxAssumeDev( !m_pages_commited, "Invalid object state: SetBlockCount must be called prior to reserved memory accesses." );
|
||||
|
||||
// Calculate such that the last block extends past the end of the array, if necessary.
|
||||
|
||||
m_numblocks = blocks;
|
||||
m_blocksize = (m_pages_reserved + m_numblocks-1) / m_numblocks;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Sets the block size via pages (pages are defined by the __pagesize global, which is
|
||||
// typically 4096).
|
||||
//
|
||||
// This method must be called prior to accessing or modifying the array contents. Calls to
|
||||
// a modified buffer will be ignored (and generate an assertion in dev/debug modes).
|
||||
SpatialArrayReserve& SpatialArrayReserve::SetBlockSizeInPages( uint pages )
|
||||
{
|
||||
if (pxAssertDev(!m_pages_commited, "Invalid object state: Block size can only be changed prior to accessing or modifying the reserved buffer contents."))
|
||||
{
|
||||
m_blocksize = pages;
|
||||
m_numblocks = (m_pages_reserved + m_blocksize - 1) / m_blocksize;
|
||||
m_blockbits.Alloc( _calcBlockBitArrayLength() );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// SetBlockSize assigns the block size of the spatial array, in bytes. The actual size of
|
||||
// each block will be rounded up to the nearest page size. The resulting size is returned.
|
||||
//
|
||||
// This method must be called prior to accessing or modifying the array contents. Calls to
|
||||
// a modified buffer will be ignored (and generate an assertion in dev/debug modes).
|
||||
uint SpatialArrayReserve::SetBlockSize( uint bytes )
|
||||
{
|
||||
SetBlockSizeInPages((bytes + __pagesize - 1) / __pagesize);
|
||||
return m_blocksize * __pagesize;
|
||||
}
|
||||
|
||||
void SpatialArrayReserve::DoCommitAndProtect( uptr page )
|
||||
{
|
||||
// Spatial Arrays work on block granularity only:
|
||||
// Round the page into a block, and commit the whole block that the page belongs to.
|
||||
|
||||
uint block = page / m_blocksize;
|
||||
CommitBlocks(block*m_blocksize, 1);
|
||||
}
|
||||
|
||||
void SpatialArrayReserve::OnCommittedBlock( void* block )
|
||||
{
|
||||
// Determine the block position in the blockbits array, flag it, and be done!
|
||||
|
||||
uptr relative = (uptr)block - (uptr)m_baseptr;
|
||||
relative /= m_blocksize * __pagesize;
|
||||
|
||||
//DbgCon.WriteLn("Check me out @ 0x%08x", block);
|
||||
|
||||
pxAssert( (m_blockbits[relative/8] & (1 << (relative & 7))) == 0 );
|
||||
m_blockbits[relative/8] |= 1 << (relative & 7);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PageProtectionMode (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
wxString PageProtectionMode::ToString() const
|
||||
{
|
||||
wxString modeStr;
|
||||
|
||||
if (m_read) modeStr += L"Read";
|
||||
if (m_write) modeStr += L"Write";
|
||||
if (m_exec) modeStr += L"Exec";
|
||||
|
||||
if (modeStr.IsEmpty()) return L"NoAccess";
|
||||
if (modeStr.Length() <= 5) modeStr += L"Only";
|
||||
|
||||
return modeStr;
|
||||
}
|
|
@ -15,48 +15,124 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "Utilities/RedtapeWindows.h"
|
||||
#include "PageFaultSource.h"
|
||||
|
||||
#include <winnt.h>
|
||||
|
||||
namespace HostSys
|
||||
int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
|
||||
{
|
||||
void *Mmap(uptr base, u32 size)
|
||||
if( eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION )
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
Source_PageFault->Dispatch( PageFaultInfo( (uptr)eps->ExceptionRecord->ExceptionInformation[1] ) );
|
||||
return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
void _platform_InstallSignalHandler()
|
||||
{
|
||||
// NOP on Win32 systems -- we use __try{} __except{} instead.
|
||||
}
|
||||
|
||||
|
||||
static DWORD ConvertToWinApi( const PageProtectionMode& mode )
|
||||
{
|
||||
DWORD winmode = PAGE_NOACCESS;
|
||||
|
||||
// Windows has some really bizarre memory protection enumeration that uses bitwise
|
||||
// numbering (like flags) but is in fact not a flag value. *Someone* from the early
|
||||
// microsoft days wasn't a very good coder, me thinks. --air
|
||||
|
||||
if (mode.CanExecute())
|
||||
{
|
||||
return VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
|
||||
}
|
||||
else if (mode.CanRead())
|
||||
{
|
||||
winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY;
|
||||
}
|
||||
|
||||
void Munmap(uptr base, u32 size)
|
||||
return winmode;
|
||||
}
|
||||
|
||||
void* HostSys::MmapReservePtr(void* base, size_t size)
|
||||
{
|
||||
return VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
}
|
||||
|
||||
bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode)
|
||||
{
|
||||
void* result = VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode));
|
||||
if (result) return true;
|
||||
|
||||
const DWORD errcode = GetLastError();
|
||||
if (errcode == ERROR_COMMITMENT_MINIMUM)
|
||||
{
|
||||
if( base == NULL ) return;
|
||||
VirtualFree((void*)base, size, MEM_DECOMMIT);
|
||||
VirtualFree((void*)base, 0, MEM_RELEASE);
|
||||
Console.Warning("(MmapCommit) Received windows error %u {Virtual Memory Minimum Too Low}.", ERROR_COMMITMENT_MINIMUM);
|
||||
Sleep(1000); // Cut windows some time to rework its memory...
|
||||
}
|
||||
else if (errcode != ERROR_NOT_ENOUGH_MEMORY && errcode != ERROR_OUTOFMEMORY)
|
||||
{
|
||||
pxFailDev(L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows());
|
||||
return false;
|
||||
}
|
||||
|
||||
void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution )
|
||||
if (!pxDoOutOfMemory) return false;
|
||||
pxDoOutOfMemory(size);
|
||||
return VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)) != NULL;
|
||||
}
|
||||
|
||||
void HostSys::MmapResetPtr(void* base, size_t size)
|
||||
{
|
||||
VirtualFree(base, size, MEM_DECOMMIT);
|
||||
}
|
||||
|
||||
|
||||
void* HostSys::MmapReserve(uptr base, size_t size)
|
||||
{
|
||||
return MmapReservePtr((void*)base, size);
|
||||
}
|
||||
|
||||
bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode)
|
||||
{
|
||||
return MmapCommitPtr( (void*)base, size, mode );
|
||||
}
|
||||
|
||||
void HostSys::MmapReset(uptr base, size_t size)
|
||||
{
|
||||
MmapResetPtr((void*)base, size);
|
||||
}
|
||||
|
||||
|
||||
void* HostSys::Mmap(uptr base, size_t size)
|
||||
{
|
||||
return VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
|
||||
void HostSys::Munmap(uptr base, size_t size)
|
||||
{
|
||||
if (!base) return;
|
||||
//VirtualFree((void*)base, size, MEM_DECOMMIT);
|
||||
VirtualFree((void*)base, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode )
|
||||
{
|
||||
pxAssertDev( ((size & (__pagesize-1)) == 0), pxsFmt(
|
||||
L"Memory block size must be a multiple of the target platform's page size.\n"
|
||||
L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)",
|
||||
__pagesize, __pagesize, size, size )
|
||||
);
|
||||
|
||||
DWORD OldProtect; // enjoy my uselessness, yo!
|
||||
if (!VirtualProtect( baseaddr, size, ConvertToWinApi(mode), &OldProtect ))
|
||||
{
|
||||
pxAssertDev( ((size & (__pagesize-1)) == 0), wxsFormat(
|
||||
L"Memory block size must be a multiple of the target platform's page size.\n"
|
||||
L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)",
|
||||
__pagesize, __pagesize, size, size )
|
||||
);
|
||||
Exception::WinApiError apiError;
|
||||
|
||||
apiError.SetDiagMsg(
|
||||
pxsFmt(L"VirtualProtect failed @ 0x%08X -> 0x%08X (mode=%s)",
|
||||
baseaddr, (uptr)baseaddr + size, mode.ToString().c_str()
|
||||
));
|
||||
|
||||
DWORD winmode = 0;
|
||||
|
||||
switch( mode )
|
||||
{
|
||||
case Protect_NoAccess:
|
||||
winmode = ( allowExecution ) ? PAGE_EXECUTE : PAGE_NOACCESS;
|
||||
break;
|
||||
|
||||
case Protect_ReadOnly:
|
||||
winmode = ( allowExecution ) ? PAGE_EXECUTE_READ : PAGE_READONLY;
|
||||
break;
|
||||
|
||||
case Protect_ReadWrite:
|
||||
winmode = ( allowExecution ) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD OldProtect; // enjoy my uselessness, yo!
|
||||
VirtualProtect( baseaddr, size, winmode, &OldProtect );
|
||||
pxFailDev( apiError.FormatDiagnosticMessage() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -675,7 +675,7 @@ void wxAppWithHelpers::OnDeleteThread( wxCommandEvent& evt )
|
|||
return;
|
||||
}
|
||||
|
||||
pxThreadLog.Write(thr->GetName(), (wxString)L"Thread object deleted successfully" + (thr->HasPendingException() ? wxEmptyString : L"[exception pending!]"));
|
||||
pxThreadLog.Write(thr->GetName(), (wxString)L"Thread object deleted successfully" + (thr->HasPendingException() ? L" [exception pending!]" : wxEmptyString));
|
||||
thr->RethrowException();
|
||||
}
|
||||
|
||||
|
|
|
@ -59,13 +59,13 @@ void x86capabilities::SIMD_EstablishMXCSRmask()
|
|||
// the fxsave buffer must be 16-byte aligned to avoid GPF. I just save it to an
|
||||
// unused portion of recSSE, since it has plenty of room to spare.
|
||||
|
||||
HostSys::MemProtectStatic( recSSE, Protect_ReadWrite, true );
|
||||
HostSys::MemProtectStatic( recSSE, PageAccess_ReadWrite() );
|
||||
|
||||
xSetPtr( recSSE );
|
||||
xFXSAVE( ptr[&targetFXSAVE] );
|
||||
xRET();
|
||||
|
||||
HostSys::MemProtectStatic( recSSE, Protect_ReadOnly, true );
|
||||
HostSys::MemProtectStatic( recSSE, PageAccess_ExecOnly() );
|
||||
|
||||
CallAddress( recSSE );
|
||||
|
||||
|
@ -310,7 +310,7 @@ u32 x86capabilities::CalculateMHz() const
|
|||
// Results of CPU
|
||||
void x86capabilities::SIMD_ExceptionTest()
|
||||
{
|
||||
HostSys::MemProtectStatic( recSSE, Protect_ReadWrite, true );
|
||||
HostSys::MemProtectStatic( recSSE, PageAccess_ReadWrite() );
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SIMD Instruction Support Detection (Second Pass)
|
||||
|
@ -336,7 +336,7 @@ void x86capabilities::SIMD_ExceptionTest()
|
|||
xMOVDQU( xmm1, ptr[ecx] );
|
||||
xRET();
|
||||
|
||||
HostSys::MemProtectStatic( recSSE, Protect_ReadOnly, true );
|
||||
HostSys::MemProtectStatic( recSSE, PageAccess_ExecOnly() );
|
||||
|
||||
bool sse3_result = _test_instruction( recSSE ); // sse3
|
||||
bool ssse3_result = _test_instruction( funcSSSE3 );
|
||||
|
|
|
@ -78,7 +78,6 @@ bool isoFile::tryIsoType(u32 _size, s32 _offset, s32 _blockofs)
|
|||
bool isoFile::Detect( bool readType )
|
||||
{
|
||||
char buf[32];
|
||||
int len = m_filename.Length();
|
||||
|
||||
m_type = ISOTYPE_ILLEGAL;
|
||||
|
||||
|
@ -245,7 +244,7 @@ void isoFile::_WriteBlock(const u8* src, uint lsn)
|
|||
void isoFile::_WriteBlockD(const u8* src, uint lsn)
|
||||
{
|
||||
// Find and ignore blocks that have already been dumped:
|
||||
for (uint i=0; i<m_dtablesize; ++i)
|
||||
for (int i=0; i<m_dtablesize; ++i)
|
||||
{
|
||||
if (m_dtable[i] == lsn) return;
|
||||
}
|
||||
|
|
|
@ -383,7 +383,6 @@ set(pcsx2IPUHeaders
|
|||
|
||||
# Linux sources
|
||||
set(pcsx2LinuxSources
|
||||
Linux/LnxHostSys.cpp
|
||||
Linux/LnxKeyCodes.cpp)
|
||||
|
||||
# Linux headers
|
||||
|
@ -432,7 +431,7 @@ set(pcsx2SystemSources
|
|||
|
||||
# System headers
|
||||
set(pcsx2SystemHeaders
|
||||
System/PageFaultSource.h
|
||||
System/RecTypes.h
|
||||
System/SysThreads.h)
|
||||
|
||||
# Utilities sources
|
||||
|
@ -542,7 +541,6 @@ set(pcsx2x86Headers
|
|||
x86/microVU_Tables.inl
|
||||
x86/microVU_Upper.inl
|
||||
x86/newVif.h
|
||||
x86/newVif_BlockBuffer.h
|
||||
x86/newVif_HashBucket.h
|
||||
x86/newVif_UnpackSSE.h
|
||||
x86/sVU_Compare.h
|
||||
|
|
|
@ -472,16 +472,16 @@ int GetPS2ElfName( wxString& name )
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
catch (Exception::BadStream& ex)
|
||||
{
|
||||
Console.Error(ex.FormatDiagnosticMessage());
|
||||
return 0; // ISO error
|
||||
}
|
||||
catch( Exception::FileNotFound& )
|
||||
{
|
||||
//Console.Warning(ex.FormatDiagnosticMessage());
|
||||
return 0; // no SYSTEM.CNF, not a PS1/PS2 disc.
|
||||
}
|
||||
catch (Exception::BadStream& ex)
|
||||
{
|
||||
Console.Error(ex.FormatDiagnosticMessage());
|
||||
return 0; // ISO error
|
||||
}
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
FILE *fp;
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "Vif_Dma.h"
|
||||
#include <limits.h>
|
||||
|
||||
#include "Utilities/MemsetFast.inl"
|
||||
|
||||
// the BP doesn't advance and returns -1 if there is no data to be read
|
||||
__aligned16 tIPU_cmd ipu_cmd;
|
||||
__aligned16 tIPU_BP g_BP;
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include "Mpeg.h"
|
||||
#include "Vlc.h"
|
||||
|
||||
#include "Utilities/MemsetFast.inl"
|
||||
|
||||
const int non_linear_quantizer_scale [] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
|
|
|
@ -24,48 +24,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
template< typename T >
|
||||
__noinline void memzero_sse_a( T& dest )
|
||||
{
|
||||
#define MZFqwc (sizeof(dest)/16)
|
||||
|
||||
C_ASSERT( (sizeof(dest) & 0xf) == 0 );
|
||||
|
||||
__m128 zeroreg = _mm_setzero_ps();
|
||||
|
||||
float (*destxmm)[4] = (float(*)[4])&dest;
|
||||
|
||||
#define StoreDestIdx(idx) case idx: _mm_store_ps(&destxmm[idx-1][0], zeroreg)
|
||||
|
||||
switch( MZFqwc & 0x07 )
|
||||
{
|
||||
StoreDestIdx(0x07);
|
||||
StoreDestIdx(0x06);
|
||||
StoreDestIdx(0x05);
|
||||
StoreDestIdx(0x04);
|
||||
StoreDestIdx(0x03);
|
||||
StoreDestIdx(0x02);
|
||||
StoreDestIdx(0x01);
|
||||
}
|
||||
|
||||
destxmm += (MZFqwc & 0x07);
|
||||
for( uint i=0; i<MZFqwc / 8; ++i, destxmm+=8 )
|
||||
{
|
||||
_mm_store_ps(&destxmm[0][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[1][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[2][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[3][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[4][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[5][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[6][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[7][0], zeroreg);
|
||||
}
|
||||
|
||||
#undef MZFqwc
|
||||
};
|
||||
|
||||
// the IPU is fixed to 16 byte strides (128-bit / QWC resolution):
|
||||
static const uint decoder_stride = 16;
|
||||
|
||||
|
|
|
@ -359,11 +359,19 @@ void JALR()
|
|||
|
||||
} } } // end namespace R5900::Interpreter::OpcodeImpl
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// R5900cpu/intCpu interface (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
static void intReserve()
|
||||
{
|
||||
// fixme : detect cpu for use the optimize asm code
|
||||
}
|
||||
|
||||
static void intAlloc()
|
||||
{
|
||||
// fixme : detect cpu for use the optimize asm code
|
||||
// Nothing to do!
|
||||
}
|
||||
|
||||
static void intReset()
|
||||
|
@ -419,19 +427,28 @@ static void intShutdown() {
|
|||
|
||||
static void intThrowException( const BaseR5900Exception& ex )
|
||||
{
|
||||
// No tricks needed; C++ stack unwnding shoud suffice for MSW and GCC alike.
|
||||
// No tricks needed; C++ stack unwnding should suffice for MSW and GCC alike.
|
||||
ex.Rethrow();
|
||||
}
|
||||
|
||||
static void intThrowException( const BaseException& ex )
|
||||
{
|
||||
// No tricks needed; C++ stack unwnding shoud suffice for MSW and GCC alike.
|
||||
// No tricks needed; C++ stack unwnding should suffice for MSW and GCC alike.
|
||||
ex.Rethrow();
|
||||
}
|
||||
|
||||
static void intSetCacheReserve( uint reserveInMegs )
|
||||
{
|
||||
}
|
||||
|
||||
static uint intGetCacheReserve()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
R5900cpu intCpu =
|
||||
{
|
||||
intAlloc,
|
||||
intReserve,
|
||||
intShutdown,
|
||||
|
||||
intReset,
|
||||
|
@ -442,4 +459,7 @@ R5900cpu intCpu =
|
|||
intThrowException,
|
||||
intThrowException,
|
||||
intClear,
|
||||
|
||||
intGetCacheReserve,
|
||||
intSetCacheReserve,
|
||||
};
|
||||
|
|
|
@ -24,26 +24,43 @@ IopVM_MemoryAllocMess* iopMem = NULL;
|
|||
|
||||
__pagealigned u8 iopHw[Ps2MemSize::IopHardware];
|
||||
|
||||
void psxMemAlloc()
|
||||
// --------------------------------------------------------------------------------------
|
||||
// iopMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
iopMemoryReserve::iopMemoryReserve()
|
||||
: _parent( L"IOP Main Memory (2mb)", sizeof(*iopMem) )
|
||||
{
|
||||
if( iopMem == NULL )
|
||||
iopMem = (IopVM_MemoryAllocMess*)vtlb_malloc( sizeof(*iopMem), 4096 );
|
||||
}
|
||||
|
||||
psxMemWLUT = (uptr*)_aligned_malloc(0x2000 * sizeof(uptr) * 2, 16);
|
||||
psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
|
||||
void iopMemoryReserve::Reserve()
|
||||
{
|
||||
_parent::Reserve(HostMemoryMap::IOPmem);
|
||||
//_parent::Reserve(EmuConfig.HostMap.IOP);
|
||||
}
|
||||
|
||||
void iopMemoryReserve::Commit()
|
||||
{
|
||||
_parent::Commit();
|
||||
iopMem = (IopVM_MemoryAllocMess*)m_reserve.GetPtr();
|
||||
}
|
||||
|
||||
// Note! Resetting the IOP's memory state is dependent on having *all* psx memory allocated,
|
||||
// which is performed by MemInit and PsxMemInit()
|
||||
void psxMemReset()
|
||||
void iopMemoryReserve::Reset()
|
||||
{
|
||||
pxAssume( psxMemWLUT != NULL );
|
||||
pxAssume( iopMem != NULL );
|
||||
_parent::Reset();
|
||||
|
||||
DbgCon.WriteLn( "IOP Resetting physical ram..." );
|
||||
pxAssume( iopMem );
|
||||
|
||||
if (!psxMemWLUT)
|
||||
{
|
||||
psxMemWLUT = (uptr*)_aligned_malloc(0x2000 * sizeof(uptr) * 2, 16);
|
||||
psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
|
||||
}
|
||||
|
||||
DbgCon.WriteLn("IOP resetting main memory...");
|
||||
|
||||
memzero_ptr<0x2000 * sizeof(uptr) * 2>( psxMemWLUT ); // clears both allocations, RLUT and WLUT
|
||||
memzero( *iopMem );
|
||||
|
||||
// Trick! We're accessing RLUT here through WLUT, since it's the non-const pointer.
|
||||
// So the ones with a 0x2000 prefixed are RLUT tables.
|
||||
|
@ -87,15 +104,22 @@ void psxMemReset()
|
|||
//for (i=0; i<0x0008; i++) psxMemWLUT[i + 0xbfc0] = (uptr)&psR[i << 16];
|
||||
}
|
||||
|
||||
void psxMemShutdown()
|
||||
void iopMemoryReserve::Decommit()
|
||||
{
|
||||
vtlb_free( iopMem, sizeof(*iopMem) );
|
||||
iopMem = NULL;
|
||||
_parent::Decommit();
|
||||
|
||||
safe_aligned_free(psxMemWLUT);
|
||||
psxMemRLUT = NULL;
|
||||
iopMem = NULL;
|
||||
}
|
||||
|
||||
void iopMemoryReserve::Release()
|
||||
{
|
||||
_parent::Release();
|
||||
iopMem = NULL;
|
||||
}
|
||||
|
||||
|
||||
u8 __fastcall iopMemRead8(u32 mem)
|
||||
{
|
||||
mem &= 0x1fffffff;
|
||||
|
|
|
@ -71,6 +71,7 @@ static __fi u8* iopPhysMem( u32 addr )
|
|||
#define psxHu16(mem) (*(u16*)&iopHw[(mem) & 0xffff])
|
||||
#define psxHu32(mem) (*(u32*)&iopHw[(mem) & 0xffff])
|
||||
|
||||
extern void psxMemReserve();
|
||||
extern void psxMemAlloc();
|
||||
extern void psxMemReset();
|
||||
extern void psxMemShutdown();
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <signal.h>
|
||||
#include "Common.h"
|
||||
#include "System/PageFaultSource.h"
|
||||
|
||||
extern void SignalExit(int sig);
|
||||
|
||||
static const uptr m_pagemask = getpagesize()-1;
|
||||
|
||||
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
|
||||
static void SysPageFaultSignalFilter( int signal, siginfo_t *siginfo, void * )
|
||||
{
|
||||
// Note: Use of most stdio functions isn't safe here. Avoid console logs,
|
||||
// assertions, file logs, or just about anything else useful.
|
||||
|
||||
Source_PageFault.Dispatch( PageFaultInfo( (uptr)siginfo->si_addr & ~m_pagemask ) );
|
||||
|
||||
// resumes execution right where we left off (re-executes instruction that
|
||||
// caused the SIGSEGV).
|
||||
if( Source_PageFault.WasHandled() ) return;
|
||||
|
||||
// Bad mojo! Completely invalid address.
|
||||
// Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
|
||||
|
||||
wxTrap();
|
||||
if( !IsDebugBuild ) raise( SIGKILL );
|
||||
}
|
||||
|
||||
void InstallSignalHandler()
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = SysPageFaultSignalFilter;
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
}
|
||||
|
||||
void NTFS_CompressFile( const wxString& file, bool compressStatus ) {}
|
|
@ -20,6 +20,8 @@
|
|||
#include <gdk/gdkkeysyms.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
void NTFS_CompressFile( const wxString& file, bool compressStatus ) {}
|
||||
|
||||
// Returns a WXK_* keycode, given some kinda GDK input mess!
|
||||
int TranslateGDKtoWXK( u32 keysym )
|
||||
{
|
||||
|
|
|
@ -268,9 +268,7 @@
|
|||
<Unit filename="../DebugTools/DisVUmicro.h" />
|
||||
<Unit filename="../DebugTools/DisVUops.h" />
|
||||
<Unit filename="../Dmac.h" />
|
||||
<Unit filename="../Docs/ChangeLog.txt" />
|
||||
<Unit filename="../Docs/License.txt" />
|
||||
<Unit filename="../Docs/devblog.txt" />
|
||||
<Unit filename="../Dump.cpp" />
|
||||
<Unit filename="../Dump.h" />
|
||||
<Unit filename="../Elfheader.cpp" />
|
||||
|
@ -316,8 +314,6 @@
|
|||
<Unit filename="../IopMem.h" />
|
||||
<Unit filename="../IopSio2.cpp" />
|
||||
<Unit filename="../IopSio2.h" />
|
||||
<Unit filename="../Ipu_fifo.h" />
|
||||
<Unit filename="LnxHostSys.cpp" />
|
||||
<Unit filename="LnxKeyCodes.cpp">
|
||||
<Option compiler="gcc" use="1" buildCommand="$compiler $options $includes `pkg-config gtk+-2.0 --cflags` -c $file -o $object" />
|
||||
</Unit>
|
||||
|
@ -363,11 +359,10 @@
|
|||
<Unit filename="../SourceLog.cpp" />
|
||||
<Unit filename="../Stats.cpp" />
|
||||
<Unit filename="../Stats.h" />
|
||||
<Unit filename="../StringUtils.h" />
|
||||
<Unit filename="../SysForwardDefs.h" />
|
||||
<Unit filename="../System.cpp" />
|
||||
<Unit filename="../System.h" />
|
||||
<Unit filename="../System/PageFaultSource.h" />
|
||||
<Unit filename="../System/RecTypes.h" />
|
||||
<Unit filename="../System/SysCoreThread.cpp" />
|
||||
<Unit filename="../System/SysThreadBase.cpp" />
|
||||
<Unit filename="../System/SysThreads.h" />
|
||||
|
@ -421,7 +416,6 @@
|
|||
<Unit filename="../gui/AppRes.cpp" />
|
||||
<Unit filename="../gui/AppSaveStates.h" />
|
||||
<Unit filename="../gui/ApplyState.h" />
|
||||
<Unit filename="../gui/CheckedStaticBox.h" />
|
||||
<Unit filename="../gui/ConsoleLogger.cpp" />
|
||||
<Unit filename="../gui/ConsoleLogger.h" />
|
||||
<Unit filename="../gui/CpuUsageProvider.cpp" />
|
||||
|
@ -449,7 +443,6 @@
|
|||
<Unit filename="../gui/Dialogs/StuckThreadDialog.cpp" />
|
||||
<Unit filename="../gui/Dialogs/SysConfigDialog.cpp" />
|
||||
<Unit filename="../gui/ExecutorThread.cpp" />
|
||||
<Unit filename="../gui/ExecutorThread.h" />
|
||||
<Unit filename="../gui/FrameForGS.cpp" />
|
||||
<Unit filename="../gui/GlobalCommands.cpp" />
|
||||
<Unit filename="../gui/IsoDropTarget.cpp" />
|
||||
|
@ -466,7 +459,6 @@
|
|||
<Unit filename="../gui/MessageBoxes.cpp" />
|
||||
<Unit filename="../gui/Panels/AudioPanel.cpp" />
|
||||
<Unit filename="../gui/Panels/BaseApplicableConfigPanel.cpp" />
|
||||
<Unit filename="../gui/Panels/BaseConfigPanel.h" />
|
||||
<Unit filename="../gui/Panels/BiosSelectorPanel.cpp" />
|
||||
<Unit filename="../gui/Panels/ConfigurationPanels.h" />
|
||||
<Unit filename="../gui/Panels/CpuPanel.cpp" />
|
||||
|
@ -572,10 +564,8 @@
|
|||
<Unit filename="../gui/Saveslots.cpp" />
|
||||
<Unit filename="../gui/SysState.cpp" />
|
||||
<Unit filename="../gui/UpdateUI.cpp" />
|
||||
<Unit filename="../gui/gsFrame.h" />
|
||||
<Unit filename="../gui/i18n.cpp" />
|
||||
<Unit filename="../gui/i18n.h" />
|
||||
<Unit filename="../gui/pxEvtThread.h" />
|
||||
<Unit filename="../gui/pxLogTextCtrl.cpp" />
|
||||
<Unit filename="../ps2/BiosTools.cpp" />
|
||||
<Unit filename="../ps2/BiosTools.h" />
|
||||
|
@ -647,7 +637,6 @@
|
|||
<Unit filename="../x86/microVU_Tables.inl" />
|
||||
<Unit filename="../x86/microVU_Upper.inl" />
|
||||
<Unit filename="../x86/newVif.h" />
|
||||
<Unit filename="../x86/newVif_BlockBuffer.h" />
|
||||
<Unit filename="../x86/newVif_Dynarec.cpp" />
|
||||
<Unit filename="../x86/newVif_HashBucket.h" />
|
||||
<Unit filename="../x86/newVif_Unpack.cpp" />
|
||||
|
|
145
pcsx2/Memory.cpp
145
pcsx2/Memory.cpp
|
@ -40,11 +40,12 @@ BIOS
|
|||
#include "IopCommon.h"
|
||||
#include "VUmicro.h"
|
||||
#include "GS.h"
|
||||
#include "System/PageFaultSource.h"
|
||||
|
||||
#include "ps2/HwInternal.h"
|
||||
#include "ps2/BiosTools.h"
|
||||
|
||||
#include "Utilities/PageFaultSource.h"
|
||||
|
||||
#ifdef ENABLECACHE
|
||||
#include "Cache.h"
|
||||
#endif
|
||||
|
@ -91,7 +92,6 @@ static vtlbHandler
|
|||
null_handler,
|
||||
|
||||
tlb_fallback_0,
|
||||
tlb_fallback_1,
|
||||
tlb_fallback_2,
|
||||
tlb_fallback_3,
|
||||
tlb_fallback_4,
|
||||
|
@ -137,9 +137,9 @@ void memMapVUmicro()
|
|||
void memMapPhy()
|
||||
{
|
||||
// Main memory
|
||||
vtlb_MapBlock(eeMem->Main, 0x00000000,Ps2MemSize::Base);//mirrored on first 256 mb ?
|
||||
vtlb_MapBlock(eeMem->Main, 0x00000000,Ps2MemSize::MainRam);//mirrored on first 256 mb ?
|
||||
// High memory, uninstalled on the configuration we emulate
|
||||
vtlb_MapHandler(null_handler, Ps2MemSize::Base, 0x10000000 - Ps2MemSize::Base);
|
||||
vtlb_MapHandler(null_handler, Ps2MemSize::MainRam, 0x10000000 - Ps2MemSize::MainRam);
|
||||
|
||||
// Various ROMs (all read-only)
|
||||
vtlb_MapBlock(eeMem->ROM, 0x1fc00000,Ps2MemSize::Rom);
|
||||
|
@ -153,14 +153,14 @@ void memMapPhy()
|
|||
vtlb_MapBlock(iopMem->Main,0x1c000000,0x00800000);
|
||||
|
||||
// Generic Handlers; These fallback to mem* stuff...
|
||||
vtlb_MapHandler(tlb_fallback_7,0x14000000,0x10000);
|
||||
vtlb_MapHandler(tlb_fallback_4,0x18000000,0x10000);
|
||||
vtlb_MapHandler(tlb_fallback_5,0x1a000000,0x10000);
|
||||
vtlb_MapHandler(tlb_fallback_6,0x12000000,0x10000);
|
||||
vtlb_MapHandler(tlb_fallback_8,0x1f000000,0x10000);
|
||||
vtlb_MapHandler(tlb_fallback_3,0x1f400000,0x10000);
|
||||
vtlb_MapHandler(tlb_fallback_2,0x1f800000,0x10000);
|
||||
vtlb_MapHandler(tlb_fallback_8,0x1f900000,0x10000);
|
||||
vtlb_MapHandler(tlb_fallback_7,0x14000000, _64kb);
|
||||
vtlb_MapHandler(tlb_fallback_4,0x18000000, _64kb);
|
||||
vtlb_MapHandler(tlb_fallback_5,0x1a000000, _64kb);
|
||||
vtlb_MapHandler(tlb_fallback_6,0x12000000, _64kb);
|
||||
vtlb_MapHandler(tlb_fallback_8,0x1f000000, _64kb);
|
||||
vtlb_MapHandler(tlb_fallback_3,0x1f400000, _64kb);
|
||||
vtlb_MapHandler(tlb_fallback_2,0x1f800000, _64kb);
|
||||
vtlb_MapHandler(tlb_fallback_8,0x1f900000, _64kb);
|
||||
|
||||
// Hardware Register Handlers : specialized/optimized per-page handling of HW register accesses
|
||||
// (note that hw_by_page handles are assigned in memReset prior to calling this function)
|
||||
|
@ -186,9 +186,9 @@ void memMapKernelMem()
|
|||
//lower 512 mb: direct map
|
||||
//vtlb_VMap(0x00000000,0x00000000,0x20000000);
|
||||
//0x8* mirror
|
||||
vtlb_VMap(0x80000000,0x00000000,0x20000000);
|
||||
vtlb_VMap(0x80000000, 0x00000000, _1mb*512);
|
||||
//0xa* mirror
|
||||
vtlb_VMap(0xA0000000,0x00000000,0x20000000);
|
||||
vtlb_VMap(0xA0000000, 0x00000000, _1mb*512);
|
||||
}
|
||||
|
||||
//what do do with these ?
|
||||
|
@ -578,35 +578,15 @@ void memClearPageAddr(u32 vaddr)
|
|||
|
||||
class mmap_PageFaultHandler : public EventListener_PageFault
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
void OnPageFaultEvent( const PageFaultInfo& info, bool& handled );
|
||||
};
|
||||
|
||||
static mmap_PageFaultHandler mmap_faultHandler;
|
||||
static mmap_PageFaultHandler* mmap_faultHandler = NULL;
|
||||
|
||||
EEVM_MemoryAllocMess* eeMem = NULL;
|
||||
|
||||
__pagealigned u8 eeHw[Ps2MemSize::Hardware];
|
||||
|
||||
void memAlloc()
|
||||
{
|
||||
if( eeMem == NULL )
|
||||
eeMem = (EEVM_MemoryAllocMess*)vtlb_malloc( sizeof(*eeMem), 4096 );
|
||||
|
||||
if( eeMem == NULL)
|
||||
throw Exception::OutOfMemory( L"memAlloc > failed to allocate PS2's base ram/rom/scratchpad." );
|
||||
|
||||
Source_PageFault.Add( mmap_faultHandler );
|
||||
}
|
||||
|
||||
void memShutdown()
|
||||
{
|
||||
Source_PageFault.Remove( mmap_faultHandler );
|
||||
|
||||
vtlb_free( eeMem, sizeof(*eeMem) );
|
||||
eeMem = NULL;
|
||||
vtlb_Term();
|
||||
}
|
||||
|
||||
void memBindConditionalHandlers()
|
||||
{
|
||||
|
@ -636,19 +616,44 @@ void memBindConditionalHandlers()
|
|||
}
|
||||
}
|
||||
|
||||
// Resets memory mappings, unmaps TLBs, reloads bios roms, etc.
|
||||
void memReset()
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// eeMemoryReserve (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
eeMemoryReserve::eeMemoryReserve()
|
||||
: _parent( L"EE Main Memory", sizeof(*eeMem) )
|
||||
{
|
||||
// VTLB Protection Preparations.
|
||||
//HostSys::MemProtect( m_psAllMem, m_allMemSize, Protect_ReadWrite );
|
||||
}
|
||||
|
||||
void eeMemoryReserve::Reserve()
|
||||
{
|
||||
_parent::Reserve(HostMemoryMap::EEmem);
|
||||
//_parent::Reserve(EmuConfig.HostMap.IOP);
|
||||
}
|
||||
|
||||
void eeMemoryReserve::Commit()
|
||||
{
|
||||
_parent::Commit();
|
||||
eeMem = (EEVM_MemoryAllocMess*)m_reserve.GetPtr();
|
||||
}
|
||||
|
||||
// Resets memory mappings, unmaps TLBs, reloads bios roms, etc.
|
||||
void eeMemoryReserve::Reset()
|
||||
{
|
||||
if (!mmap_faultHandler)
|
||||
{
|
||||
pxAssume(Source_PageFault);
|
||||
mmap_faultHandler = new mmap_PageFaultHandler();
|
||||
}
|
||||
|
||||
_parent::Reset();
|
||||
|
||||
// Note!! Ideally the vtlb should only be initialized once, and then subsequent
|
||||
// resets of the system hardware would only clear vtlb mappings, but since the
|
||||
// rest of the emu is not really set up to support a "soft" reset of that sort
|
||||
// we opt for the hard/safe version.
|
||||
|
||||
pxAssume( eeMem != NULL );
|
||||
memzero( *eeMem );
|
||||
pxAssume( eeMem );
|
||||
|
||||
#ifdef ENABLECACHE
|
||||
memset(pCache,0,sizeof(_cacheS)*64);
|
||||
|
@ -761,9 +766,24 @@ void memReset()
|
|||
LoadBIOS();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory Protection and Block Checking, vtlb Style!
|
||||
//
|
||||
void eeMemoryReserve::Decommit()
|
||||
{
|
||||
_parent::Decommit();
|
||||
eeMem = NULL;
|
||||
}
|
||||
|
||||
void eeMemoryReserve::Release()
|
||||
{
|
||||
safe_delete(mmap_faultHandler);
|
||||
_parent::Release();
|
||||
eeMem = NULL;
|
||||
vtlb_Term();
|
||||
}
|
||||
|
||||
|
||||
// ===========================================================================================
|
||||
// Memory Protection and Block Checking, vtlb Style!
|
||||
// ===========================================================================================
|
||||
// For the first time code is recompiled (executed), the PS2 ram page for that code is
|
||||
// protected using Virtual Memory (mprotect). If the game modifies its own code then this
|
||||
// protection causes an *exception* to be raised (signal in Linux), which is handled by
|
||||
|
@ -796,15 +816,17 @@ enum vtlb_ProtectionMode
|
|||
|
||||
struct vtlb_PageProtectionInfo
|
||||
{
|
||||
// Ram De-mapping -- used to convert fully translated/mapped offsets into psM back
|
||||
// into their originating ps2 physical ram address. Values are assigned when pages
|
||||
// are marked for protection.
|
||||
// Ram De-mapping -- used to convert fully translated/mapped offsets (which reside with
|
||||
// in the eeMem->Main block) back into their originating ps2 physical ram address.
|
||||
// Values are assigned when pages are marked for protection. since pages are automatically
|
||||
// cleared and reset when TLB-remapped, stale values in this table (due to on-the-fly TLB
|
||||
// changes) will be re-assigned the next time the page is accessed.
|
||||
u32 ReverseRamMap;
|
||||
|
||||
vtlb_ProtectionMode Mode;
|
||||
};
|
||||
|
||||
static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::Base >> 12];
|
||||
static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::MainRam >> 12];
|
||||
|
||||
|
||||
// returns:
|
||||
|
@ -815,28 +837,33 @@ static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::Base >>
|
|||
//
|
||||
int mmap_GetRamPageInfo( u32 paddr )
|
||||
{
|
||||
pxAssume( eeMem );
|
||||
|
||||
paddr &= ~0xfff;
|
||||
|
||||
uptr ptr = (uptr)PSM( paddr );
|
||||
uptr rampage = ptr - (uptr)eeMem->Main;
|
||||
|
||||
if (rampage >= Ps2MemSize::Base)
|
||||
if (rampage >= Ps2MemSize::MainRam)
|
||||
return -1; //not in ram, no tracking done ...
|
||||
|
||||
rampage >>= 12;
|
||||
return ( m_PageProtectInfo[rampage].Mode == ProtMode_Manual ) ? 1 : 0;
|
||||
}
|
||||
|
||||
// paddr - physically mapped address
|
||||
// paddr - physically mapped PS2 address
|
||||
void mmap_MarkCountedRamPage( u32 paddr )
|
||||
{
|
||||
pxAssume( eeMem );
|
||||
|
||||
paddr &= ~0xfff;
|
||||
|
||||
uptr ptr = (uptr)PSM( paddr );
|
||||
int rampage = (ptr - (uptr)eeMem->Main) >> 12;
|
||||
|
||||
// Important: reassign paddr here, since TLB changes could alter the paddr->psM mapping
|
||||
// (and clear blocks accordingly), but don't necessarily clear the protection status.
|
||||
// Important: Update the ReverseRamMap here because TLB changes could alter the paddr
|
||||
// mapping into eeMem->Main.
|
||||
|
||||
m_PageProtectInfo[rampage].ReverseRamMap = paddr;
|
||||
|
||||
if( m_PageProtectInfo[rampage].Mode == ProtMode_Write )
|
||||
|
@ -848,7 +875,7 @@ void mmap_MarkCountedRamPage( u32 paddr )
|
|||
);
|
||||
|
||||
m_PageProtectInfo[rampage].Mode = ProtMode_Write;
|
||||
HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, Protect_ReadOnly );
|
||||
HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, PageAccess_ReadOnly() );
|
||||
}
|
||||
|
||||
// offset - offset of address relative to psM.
|
||||
|
@ -856,6 +883,8 @@ void mmap_MarkCountedRamPage( u32 paddr )
|
|||
// from code residing in this page will use manual protection.
|
||||
static __fi void mmap_ClearCpuBlock( uint offset )
|
||||
{
|
||||
pxAssume( eeMem );
|
||||
|
||||
int rampage = offset >> 12;
|
||||
|
||||
// Assertion: This function should never be run on a block that's already under
|
||||
|
@ -863,16 +892,18 @@ static __fi void mmap_ClearCpuBlock( uint offset )
|
|||
pxAssertMsg( m_PageProtectInfo[rampage].Mode != ProtMode_Manual,
|
||||
"Attempted to clear a block that is already under manual protection." );
|
||||
|
||||
HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, Protect_ReadWrite );
|
||||
HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, PageAccess_ReadWrite() );
|
||||
m_PageProtectInfo[rampage].Mode = ProtMode_Manual;
|
||||
Cpu->Clear( m_PageProtectInfo[rampage].ReverseRamMap, 0x400 );
|
||||
}
|
||||
|
||||
void mmap_PageFaultHandler::OnPageFaultEvent( const PageFaultInfo& info, bool& handled )
|
||||
{
|
||||
pxAssume( eeMem );
|
||||
|
||||
// get bad virtual address
|
||||
uptr offset = info.addr - (uptr)eeMem->Main;
|
||||
if( offset >= Ps2MemSize::Base ) return;
|
||||
if( offset >= Ps2MemSize::MainRam ) return;
|
||||
|
||||
mmap_ClearCpuBlock( offset );
|
||||
handled = true;
|
||||
|
@ -886,5 +917,5 @@ void mmap_ResetBlockTracking()
|
|||
{
|
||||
//DbgCon.WriteLn( "vtlb/mmap: Block Tracking reset..." );
|
||||
memzero( m_PageProtectInfo );
|
||||
HostSys::MemProtect( eeMem->Main, Ps2MemSize::Base, Protect_ReadWrite );
|
||||
if (eeMem) HostSys::MemProtect( eeMem->Main, Ps2MemSize::MainRam, PageAccess_ReadWrite() );
|
||||
}
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
// [TODO] This *could* be replaced with an assignment operator on u128 that implicitly
|
||||
// uses _mm_store and _mm_load internally. However, there are alignment concerns --
|
||||
// u128 is not alignment strict. (we would need a u128 and u128a for types known to
|
||||
// be strictly 128-bit aligned).
|
||||
static __fi void CopyQWC( void* dest, const void* src )
|
||||
{
|
||||
_mm_store_ps( (float*)dest, _mm_load_ps((const float*)src) );
|
||||
|
@ -103,9 +107,7 @@ static __fi void ZeroQWC( u128& dest )
|
|||
#define psSu64(mem) (*(u64 *)&eeMem->Scratch[(mem) & 0x3fff])
|
||||
#define psSu128(mem) (*(u128*)&eeMem->Scratch[(mem) & 0x3fff])
|
||||
|
||||
extern void memAlloc();
|
||||
extern void memReset(); // clears PS2 ram and loads the bios. Throws Exception::FileNotFound on error.
|
||||
extern void memShutdown();
|
||||
|
||||
extern void memSetKernelMode();
|
||||
//extern void memSetSupervisorMode();
|
||||
extern void memSetUserMode();
|
||||
|
|
|
@ -17,18 +17,18 @@
|
|||
|
||||
namespace Ps2MemSize
|
||||
{
|
||||
static const uint Base = 0x02000000; // 32 MB main memory!
|
||||
static const uint Rom = 0x00400000; // 4 MB main rom
|
||||
static const uint Rom1 = 0x00040000; // DVD player
|
||||
static const uint Rom2 = 0x00080000; // Chinese rom extension (?)
|
||||
static const uint ERom = 0x001C0000; // DVD player extensions (?)
|
||||
static const uint Hardware = 0x00010000;
|
||||
static const uint Scratch = 0x00004000;
|
||||
static const uint MainRam = _32mb; // 32 MB main memory!
|
||||
static const uint Rom = _1mb * 4; // 4 MB main rom
|
||||
static const uint Rom1 = 0x00040000; // DVD player
|
||||
static const uint Rom2 = 0x00080000; // Chinese rom extension (?)
|
||||
static const uint ERom = 0x001C0000; // DVD player extensions (?)
|
||||
static const uint Hardware = _64kb;
|
||||
static const uint Scratch = _16kb;
|
||||
|
||||
static const uint IopRam = 0x00200000; // 2MB main ram on the IOP.
|
||||
static const uint IopHardware = 0x00010000;
|
||||
static const uint IopRam = _1mb * 2; // 2MB main ram on the IOP.
|
||||
static const uint IopHardware = _64kb;
|
||||
|
||||
static const uint GSregs = 0x00002000; // 8k for the GS registers and stuff.
|
||||
static const uint GSregs = 0x00002000; // 8k for the GS registers and stuff.
|
||||
}
|
||||
|
||||
typedef u8 mem8_t;
|
||||
|
@ -53,6 +53,9 @@ typedef u128 mem128_t;
|
|||
// memory, such as hardware registers or scratchpad, the access will generate a page fault, the
|
||||
// compiled block will be cleared and re-compiled using "full" VTLB translation logic.
|
||||
//
|
||||
// Note that support for this feature may not be doable under x86/32 platforms, due to the
|
||||
// 2gb/3gb limit of Windows XP (the 3gb feature will make it slightly more feasible at least).
|
||||
//
|
||||
#define VTLB_UsePageFaulting 0
|
||||
|
||||
#if VTLB_UsePageFaulting
|
||||
|
@ -61,9 +64,9 @@ typedef u128 mem128_t;
|
|||
// full breadth of PS2 RAM and ROM mappings are directly supported.
|
||||
struct EEVM_MemoryAllocMess
|
||||
{
|
||||
u8 (&Main)[Ps2MemSize::Base]; // Main memory (hard-wired to 32MB)
|
||||
u8 (&Main)[Ps2MemSize::MainRam]; // Main memory (hard-wired to 32MB)
|
||||
|
||||
u8 _padding1[0x1e000000-Ps2MemSize::Base]
|
||||
u8 _padding1[0x1e000000-Ps2MemSize::MainRam]
|
||||
u8 (&ROM1)[Ps2MemSize::Rom1]; // DVD player
|
||||
|
||||
u8 _padding2[0x1e040000-(0x1e000000+Ps2MemSize::Rom1)]
|
||||
|
@ -80,8 +83,8 @@ struct EEVM_MemoryAllocMess
|
|||
|
||||
struct EEVM_MemoryAllocMess
|
||||
{
|
||||
u8 Main[Ps2MemSize::MainRam]; // Main memory (hard-wired to 32MB)
|
||||
u8 Scratch[Ps2MemSize::Scratch]; // Scratchpad!
|
||||
u8 Main[Ps2MemSize::Base]; // Main memory (hard-wired to 32MB)
|
||||
u8 ROM[Ps2MemSize::Rom]; // Boot rom (4MB)
|
||||
u8 ROM1[Ps2MemSize::Rom1]; // DVD player
|
||||
u8 ROM2[Ps2MemSize::Rom2]; // Chinese extensions
|
||||
|
@ -101,7 +104,7 @@ struct EEVM_MemoryAllocMess
|
|||
struct IopVM_MemoryAllocMess
|
||||
{
|
||||
u8 Main[Ps2MemSize::IopRam]; // Main memory (hard-wired to 2MB)
|
||||
u8 P[0x00010000]; // I really have no idea what this is... --air
|
||||
u8 P[_64kb]; // I really have no idea what this is... --air
|
||||
u8 Sif[0x100]; // a few special SIF/SBUS registers (likely not needed)
|
||||
};
|
||||
|
||||
|
|
|
@ -674,18 +674,34 @@ SysCorePlugins *g_plugins = NULL;
|
|||
// Plugin-related Exception Implementations
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
wxString Exception::SaveStateLoadError::FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("Savestate is corrupt or incomplete!");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
wxString Exception::SaveStateLoadError::FormatDisplayMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write(_("The savestate cannot be loaded, as it appears to be corrupt or incomplete."));
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
Exception::PluginOpenError::PluginOpenError( PluginsEnum_t pid )
|
||||
{
|
||||
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.";
|
||||
m_message_user = _("%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers.");
|
||||
}
|
||||
|
||||
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.";
|
||||
m_message_user = _("%s plugin failed to initialize. Your system may have insufficient memory or resources needed.");
|
||||
}
|
||||
|
||||
Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid )
|
||||
|
@ -695,29 +711,29 @@ Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid )
|
|||
|
||||
wxString Exception::PluginLoadError::FormatDiagnosticMessage() const
|
||||
{
|
||||
return wxsFormat( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() ) +
|
||||
return pxsFmt( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() ) +
|
||||
L"\n\n" + StreamName;
|
||||
}
|
||||
|
||||
wxString Exception::PluginLoadError::FormatDisplayMessage() const
|
||||
{
|
||||
return wxsFormat( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() ) +
|
||||
return pxsFmt( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() ) +
|
||||
L"\n\n" + StreamName;
|
||||
}
|
||||
|
||||
wxString Exception::PluginError::FormatDiagnosticMessage() const
|
||||
{
|
||||
return wxsFormat( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() );
|
||||
return pxsFmt( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() );
|
||||
}
|
||||
|
||||
wxString Exception::PluginError::FormatDisplayMessage() const
|
||||
{
|
||||
return wxsFormat( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() );
|
||||
return pxsFmt( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() );
|
||||
}
|
||||
|
||||
wxString Exception::FreezePluginFailure::FormatDiagnosticMessage() const
|
||||
{
|
||||
return wxsFormat(
|
||||
return pxsFmt(
|
||||
L"%s plugin returned an error while saving the state.\n\n",
|
||||
tbl_PluginInfo[PluginId].shortname
|
||||
);
|
||||
|
@ -731,7 +747,7 @@ wxString Exception::FreezePluginFailure::FormatDisplayMessage() const
|
|||
|
||||
wxString Exception::ThawPluginFailure::FormatDiagnosticMessage() const
|
||||
{
|
||||
return wxsFormat(
|
||||
return pxsFmt(
|
||||
L"%s plugin returned an error while loading the state.\n\n",
|
||||
tbl_PluginInfo[PluginId].shortname
|
||||
);
|
||||
|
@ -1262,7 +1278,7 @@ void SysCorePlugins::Init( PluginsEnum_t pid )
|
|||
if( !m_info[pid] || m_info[pid]->IsInitialized ) return;
|
||||
|
||||
Console.Indent().WriteLn( "Init %s", tbl_PluginInfo[pid].shortname );
|
||||
if( NULL != m_info[pid]->CommonBindings.Init() )
|
||||
if( 0 != m_info[pid]->CommonBindings.Init() )
|
||||
throw Exception::PluginInitError( pid );
|
||||
|
||||
m_info[pid]->IsInitialized = true;
|
||||
|
|
|
@ -57,12 +57,15 @@ namespace Exception
|
|||
// Exception thrown when a corrupted or truncated savestate is encountered.
|
||||
class SaveStateLoadError : public BadStream
|
||||
{
|
||||
DEFINE_STREAM_EXCEPTION( SaveStateLoadError, BadStream, wxLt("The savestate appears to be corrupt or incomplete.") )
|
||||
DEFINE_STREAM_EXCEPTION( SaveStateLoadError, BadStream )
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
class PluginError : public RuntimeError
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION( PluginError, RuntimeError, L"Generic plugin error")
|
||||
DEFINE_RUNTIME_EXCEPTION( PluginError, RuntimeError, L"Generic plugin error!" )
|
||||
|
||||
public:
|
||||
PluginsEnum_t PluginId;
|
||||
|
|
|
@ -102,14 +102,9 @@ typedef int BOOL;
|
|||
typedef void FnType_Void();
|
||||
typedef FnType_Void* Fnptr_Void;
|
||||
|
||||
static const s64 _1mb = 0x100000;
|
||||
static const s64 _8mb = _1mb * 8;
|
||||
static const s64 _16mb = _1mb * 16;
|
||||
static const s64 _256mb = _1mb * 256;
|
||||
static const s64 _1gb = _256mb * 4;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Compiler/OS specific macros and defines -- Begin Section
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Compiler/OS specific macros and defines
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
// Linux isn't set up for svn version numbers yet.
|
||||
#ifdef __LINUX__
|
||||
|
|
|
@ -178,16 +178,20 @@ extern bool iopEventTestIsActive;
|
|||
// Branching status used when throwing exceptions.
|
||||
extern bool iopIsDelaySlot;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// R3000A Public Interface / API
|
||||
// --------------------------------------------------------------------------------------
|
||||
// R3000Acpu
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
struct R3000Acpu {
|
||||
void (*Allocate)();
|
||||
void (*Reserve)();
|
||||
void (*Reset)();
|
||||
void (*Execute)();
|
||||
s32 (*ExecuteBlock)( s32 eeCycles ); // executes the given number of EE cycles.
|
||||
void (*Clear)(u32 Addr, u32 Size);
|
||||
void (*Shutdown)();
|
||||
|
||||
uint (*GetCacheReserve)();
|
||||
void (*SetCacheReserve)( uint reserveInMegs );
|
||||
};
|
||||
|
||||
extern R3000Acpu *psxCpu;
|
||||
|
|
|
@ -150,10 +150,14 @@ static void doBranch(s32 tar) {
|
|||
iopEventTest();
|
||||
}
|
||||
|
||||
static void intReserve() {
|
||||
}
|
||||
|
||||
static void intAlloc() {
|
||||
}
|
||||
|
||||
static void intReset() {
|
||||
intAlloc();
|
||||
}
|
||||
|
||||
static void intExecute() {
|
||||
|
@ -180,11 +184,23 @@ static void intClear(u32 Addr, u32 Size) {
|
|||
static void intShutdown() {
|
||||
}
|
||||
|
||||
static void intSetCacheReserve( uint reserveInMegs )
|
||||
{
|
||||
}
|
||||
|
||||
static uint intGetCacheReserve()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
R3000Acpu psxInt = {
|
||||
intAlloc,
|
||||
intReserve,
|
||||
intReset,
|
||||
intExecute,
|
||||
intExecuteBlock,
|
||||
intClear,
|
||||
intShutdown
|
||||
intShutdown,
|
||||
|
||||
intGetCacheReserve,
|
||||
intSetCacheReserve
|
||||
};
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "CDVD/CDVD.h"
|
||||
#include "Patch.h"
|
||||
#include "GameDatabase.h"
|
||||
#include "SamplProf.h"
|
||||
|
||||
using namespace R5900; // for R5900 disasm tools
|
||||
|
||||
|
@ -51,14 +50,14 @@ static const uint eeWaitCycles = 3072;
|
|||
|
||||
bool eeEventTestIsActive = false;
|
||||
|
||||
extern SysMainMemory& GetVmMemory();
|
||||
|
||||
void cpuReset()
|
||||
{
|
||||
if( GetMTGS().IsOpen() )
|
||||
if (GetMTGS().IsOpen())
|
||||
GetMTGS().WaitGS(); // GS better be done processing before we reset the EE, just in case.
|
||||
|
||||
memReset();
|
||||
psxMemReset();
|
||||
vuMicroMemReset();
|
||||
GetVmMemory().ResetAll();
|
||||
|
||||
memzero(cpuRegs);
|
||||
memzero(fpuRegs);
|
||||
|
|
|
@ -273,25 +273,25 @@ extern void __fastcall eeloadReplaceOSDSYS();
|
|||
struct R5900cpu
|
||||
{
|
||||
// Memory allocation function, for allocating virtual memory spaces needed by
|
||||
// the emulator. (ints/recs are free to allocate additional memory while running
|
||||
// code, however any virtual mapped memory should always be allocated as soon
|
||||
// as possible, to claim the memory before some plugin does..)
|
||||
//
|
||||
// the virtual cpu provider. Allocating additional heap memory from this method is
|
||||
// NOT recommended. Heap allocations should be performed by Reset only. This
|
||||
// maximizes the likeliness of reservations claiming addresses they prefer.
|
||||
//
|
||||
// Thread Affinity:
|
||||
// Can be called from any thread. Execute status must be suspended or stopped
|
||||
// to prevent multi-thread race conditions.
|
||||
// Called from the main/UI thread only. Cpu execution status is guaranteed to
|
||||
// be inactive. No locking is necessary.
|
||||
//
|
||||
// Exception Throws:
|
||||
// HardwareDeficiency - The host machine's hardware does not support this CPU provider.
|
||||
// OutOfMemory - Not enough memory, or the memory areas required were already
|
||||
// reserved.
|
||||
//
|
||||
void (*Allocate)();
|
||||
void (*Reserve)();
|
||||
|
||||
// Deallocates ram allocated by Allocate and/or by runtime code execution.
|
||||
// Deallocates ram allocated by Allocate, Reserve, and/or by runtime code execution.
|
||||
//
|
||||
// Thread Affinity:
|
||||
// Can be called from any thread. Execute status must be suspended or stopped
|
||||
// to prevent multi-thread race conditions.
|
||||
// Called from the main/UI thread only. Cpu execution status is guaranteed to
|
||||
// be inactive. No locking is necessary.
|
||||
//
|
||||
// Exception Throws: None. This function is a destructor, and should not throw.
|
||||
//
|
||||
|
@ -302,8 +302,10 @@ struct R5900cpu
|
|||
// rely on the CPU/VM states almost entirely.
|
||||
//
|
||||
// Thread Affinity:
|
||||
// Can be called from any thread. Execute status must be suspended or stopped
|
||||
// to prevent multi-thread race conditions.
|
||||
// Can be called from any thread. CPU execution status is indeterminate and may
|
||||
// already be in progress. Implementations should be sure to queue and execute
|
||||
// resets at the earliest safe convenience (typically right before recompiling a
|
||||
// new block of code, or after a vsync event).
|
||||
//
|
||||
// Exception Throws: Emulator-defined. Common exception types to expect are
|
||||
// OutOfMemory, Stream Exceptions
|
||||
|
@ -365,7 +367,7 @@ struct R5900cpu
|
|||
// better off replaced with some generic API callbacks from VTLB block protection.
|
||||
// Also: the calls from COP0's TLB remap code should be replaced with full recompiler
|
||||
// resets, since TLB remaps affect more than just the code they contain (code that
|
||||
// may reference the remaped blocks via memory loads/stores, for example).
|
||||
// may reference the remapped blocks via memory loads/stores, for example).
|
||||
//
|
||||
// Thread Affinity Rule:
|
||||
// Can be called from any thread (namely for being called from debugging threads)
|
||||
|
@ -374,6 +376,9 @@ struct R5900cpu
|
|||
// doesn't matter if we're stripping it out soon. ;)
|
||||
//
|
||||
void (*Clear)(u32 Addr, u32 Size);
|
||||
|
||||
uint (*GetCacheReserve)();
|
||||
void (*SetCacheReserve)( uint reserveInMegs );
|
||||
};
|
||||
|
||||
extern R5900cpu *Cpu;
|
||||
|
|
|
@ -30,6 +30,10 @@ void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz);
|
|||
void ProfilerRegisterSource(const char* Name, const void* function);
|
||||
void ProfilerTerminateSource( const char* Name );
|
||||
|
||||
void ProfilerRegisterSource(const wxString& Name, const void* buff, u32 sz);
|
||||
void ProfilerRegisterSource(const wxString& Name, const void* function);
|
||||
void ProfilerTerminateSource( const wxString& Name );
|
||||
|
||||
#else
|
||||
|
||||
// Disables the profiler in Debug & Linux builds.
|
||||
|
|
|
@ -48,7 +48,7 @@ static void PostLoadPrep()
|
|||
wxString SaveStateBase::GetFilename( int slot )
|
||||
{
|
||||
return (g_Conf->Folders.Savestates +
|
||||
wxsFormat( L"%8.8X.%3.3d", ElfCRC, slot )).GetFullPath();
|
||||
pxsFmt( L"%08X.%03d", ElfCRC, slot )).GetFullPath();
|
||||
}
|
||||
|
||||
SaveStateBase::SaveStateBase( SafeArray<u8>& memblock )
|
||||
|
@ -142,7 +142,7 @@ void SaveStateBase::FreezeBios()
|
|||
}
|
||||
|
||||
static const int MainMemorySizeInBytes =
|
||||
Ps2MemSize::Base + Ps2MemSize::Scratch + Ps2MemSize::Hardware +
|
||||
Ps2MemSize::MainRam + Ps2MemSize::Scratch + Ps2MemSize::Hardware +
|
||||
Ps2MemSize::IopRam + Ps2MemSize::IopHardware + 0x0100;
|
||||
|
||||
void SaveStateBase::FreezeMainMemory()
|
||||
|
@ -152,7 +152,7 @@ void SaveStateBase::FreezeMainMemory()
|
|||
|
||||
// First Block - Memory Dumps
|
||||
// ---------------------------
|
||||
FreezeMem(eeMem->Main, Ps2MemSize::Base); // 32 MB main memory
|
||||
FreezeMem(eeMem->Main, Ps2MemSize::MainRam); // 32 MB main memory
|
||||
FreezeMem(eeMem->Scratch, Ps2MemSize::Scratch); // scratch pad
|
||||
FreezeMem(eeHw, Ps2MemSize::Hardware); // hardware memory
|
||||
|
||||
|
|
310
pcsx2/System.cpp
310
pcsx2/System.cpp
|
@ -16,44 +16,144 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
#include "Common.h"
|
||||
#include "IopCommon.h"
|
||||
#include "VUmicro.h"
|
||||
#include "newVif.h"
|
||||
|
||||
#include "System/PageFaultSource.h"
|
||||
#include "Utilities/EventSource.inl"
|
||||
#include "SamplProf.h"
|
||||
|
||||
// Includes needed for cleanup, since we don't have a good system (yet) for
|
||||
// cleaning up these things.
|
||||
#include "sVU_zerorec.h"
|
||||
#include "GameDatabase.h"
|
||||
#include "Elfheader.h"
|
||||
|
||||
extern void closeNewVif(int idx);
|
||||
extern void resetNewVif(int idx);
|
||||
#include "System/RecTypes.h"
|
||||
|
||||
template class EventSource< IEventListener_PageFault >;
|
||||
#include "Utilities/MemsetFast.inl"
|
||||
|
||||
SrcType_PageFault Source_PageFault;
|
||||
|
||||
EventListener_PageFault::EventListener_PageFault()
|
||||
// --------------------------------------------------------------------------------------
|
||||
// RecompiledCodeReserve (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
// Constructor!
|
||||
// Parameters:
|
||||
// name - a nice long name that accurately describes the contents of this reserve.
|
||||
RecompiledCodeReserve::RecompiledCodeReserve( const wxString& name, uint defCommit )
|
||||
: BaseVmReserveListener( name )
|
||||
{
|
||||
Source_PageFault.Add( *this );
|
||||
m_blocksize = (1024 * 128) / __pagesize;
|
||||
m_prot_mode = PageAccess_Any();
|
||||
m_def_commit = defCommit / __pagesize;
|
||||
|
||||
m_profiler_registered = false;
|
||||
}
|
||||
|
||||
EventListener_PageFault::~EventListener_PageFault() throw()
|
||||
RecompiledCodeReserve::~RecompiledCodeReserve() throw()
|
||||
{
|
||||
Source_PageFault.Remove( *this );
|
||||
_termProfiler();
|
||||
}
|
||||
|
||||
void SrcType_PageFault::Dispatch( const PageFaultInfo& params )
|
||||
void RecompiledCodeReserve::_registerProfiler()
|
||||
{
|
||||
m_handled = false;
|
||||
_parent::Dispatch( params );
|
||||
if (m_profiler_name.IsEmpty() || !IsOk()) return;
|
||||
ProfilerRegisterSource( m_profiler_name, m_baseptr, GetReserveSizeInBytes() );
|
||||
m_profiler_registered = true;
|
||||
}
|
||||
|
||||
void SrcType_PageFault::_DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt )
|
||||
void RecompiledCodeReserve::_termProfiler()
|
||||
{
|
||||
do {
|
||||
(*iter)->DispatchEvent( evt, m_handled );
|
||||
} while( (++iter != iend) && !m_handled );
|
||||
if (m_profiler_registered)
|
||||
ProfilerTerminateSource( m_profiler_name );
|
||||
}
|
||||
|
||||
uint RecompiledCodeReserve::_calcDefaultCommitInBlocks() const
|
||||
{
|
||||
return (m_def_commit + m_blocksize - 1) / m_blocksize;
|
||||
}
|
||||
|
||||
void* RecompiledCodeReserve::Reserve( size_t size, uptr base, uptr upper_bounds )
|
||||
{
|
||||
if (!_parent::Reserve(size, base, upper_bounds)) return NULL;
|
||||
_registerProfiler();
|
||||
return m_baseptr;
|
||||
}
|
||||
|
||||
|
||||
// Sets the abbreviated name used by the profiler. Name should be under 10 characters long.
|
||||
// After a name has been set, a profiler source will be automatically registered and cleared
|
||||
// in accordance with changes in the reserve area.
|
||||
RecompiledCodeReserve& RecompiledCodeReserve::SetProfilerName( const wxString& shortname )
|
||||
{
|
||||
m_profiler_name = shortname;
|
||||
_registerProfiler();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void RecompiledCodeReserve::DoCommitAndProtect( uptr page )
|
||||
{
|
||||
CommitBlocks(page, (m_pages_commited || !m_def_commit) ? 1 : _calcDefaultCommitInBlocks() );
|
||||
}
|
||||
|
||||
void RecompiledCodeReserve::OnCommittedBlock( void* block )
|
||||
{
|
||||
if (IsDevBuild)
|
||||
{
|
||||
// Clear the recompiled code block to 0xcc (INT3) -- this helps disasm tools show
|
||||
// the assembly dump more cleanly. We don't clear the block on Release builds since
|
||||
// it can add a noticeable amount of overhead to large block recompilations.
|
||||
|
||||
memset_sse_a<0xcc>( block, m_blocksize * __pagesize );
|
||||
}
|
||||
}
|
||||
|
||||
// This error message is shared by R5900, R3000, and microVU recompilers. It is not used by the
|
||||
// SuperVU recompiler, since it has its own customized message.
|
||||
void RecompiledCodeReserve::ThrowIfNotOk() const
|
||||
{
|
||||
if (IsOk()) return;
|
||||
|
||||
throw Exception::OutOfMemory(m_name)
|
||||
.SetDiagMsg(pxsFmt( L"Recompiled code cache could not be mapped." ))
|
||||
.SetUserMsg( pxE( ".Error:Recompiler:VirtualMemoryAlloc",
|
||||
L"This recompiler was unable to reserve contiguous memory required for internal caches. "
|
||||
L"This error can be caused by low virtual memory resources, such as a small or disabled swapfile, "
|
||||
L"or by another program that is hogging a lot of memory. You can also try reducing the default "
|
||||
L"cache sizes for all PCSX2 recompilers, found under Host Settings."
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
void SysOutOfMemory_EmergencyResponse(uptr blocksize)
|
||||
{
|
||||
// An out of memory error occurred. All we can try to do in response is reset the various
|
||||
// recompiler caches (which can sometimes total over 120megs, so it can be quite helpful).
|
||||
// If the user is using interpreters, or if the memory allocation failure was on a very small
|
||||
// allocation, then this code could fail; but that's fine. We're already trying harder than
|
||||
// 99.995% of all programs ever written. -- air
|
||||
|
||||
if (Cpu)
|
||||
{
|
||||
Cpu->SetCacheReserve( (Cpu->GetCacheReserve() * 3) / 2 );
|
||||
Cpu->Reset();
|
||||
}
|
||||
|
||||
if (CpuVU0)
|
||||
{
|
||||
CpuVU0->SetCacheReserve( (CpuVU0->GetCacheReserve() * 3) / 2 );
|
||||
CpuVU0->Reset();
|
||||
}
|
||||
|
||||
if (CpuVU1)
|
||||
{
|
||||
CpuVU1->SetCacheReserve( (CpuVU1->GetCacheReserve() * 3) / 2 );
|
||||
CpuVU1->Reset();
|
||||
}
|
||||
|
||||
if (psxCpu)
|
||||
{
|
||||
psxCpu->SetCacheReserve( (psxCpu->GetCacheReserve() * 3) / 2 );
|
||||
psxCpu->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -190,7 +290,7 @@ CpuInitializer< CpuType >::CpuInitializer()
|
|||
{
|
||||
try {
|
||||
MyCpu = new CpuType();
|
||||
MyCpu->Allocate();
|
||||
MyCpu->Reserve();
|
||||
}
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
|
@ -209,7 +309,7 @@ CpuInitializer< CpuType >::CpuInitializer()
|
|||
template< typename CpuType >
|
||||
CpuInitializer< CpuType >::~CpuInitializer() throw()
|
||||
{
|
||||
if( MyCpu )
|
||||
if (MyCpu)
|
||||
MyCpu->Shutdown();
|
||||
}
|
||||
|
||||
|
@ -246,96 +346,128 @@ static wxString GetMemoryErrorVM()
|
|||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysAllocVM (implementations)
|
||||
// SysReserveVM (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
SysAllocVM::SysAllocVM()
|
||||
SysMainMemory::SysMainMemory()
|
||||
{
|
||||
InstallSignalHandler();
|
||||
|
||||
Console.WriteLn( "Allocating memory for the PS2 virtual machine..." );
|
||||
|
||||
try
|
||||
{
|
||||
vtlb_Core_Alloc();
|
||||
memAlloc();
|
||||
psxMemAlloc();
|
||||
vuMicroMemAlloc();
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::OutOfMemory& ex )
|
||||
{
|
||||
ex.UserMsg() += L"\n\n" + GetMemoryErrorVM();
|
||||
CleanupMess();
|
||||
throw;
|
||||
}
|
||||
catch( std::bad_alloc& ex )
|
||||
{
|
||||
CleanupMess();
|
||||
|
||||
// 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()
|
||||
.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
|
||||
}
|
||||
}
|
||||
|
||||
void SysAllocVM::CleanupMess() throw()
|
||||
SysMainMemory::~SysMainMemory() throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
vuMicroMemShutdown();
|
||||
psxMemShutdown();
|
||||
memShutdown();
|
||||
vtlb_Core_Shutdown();
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
ReleaseAll();
|
||||
}
|
||||
|
||||
SysAllocVM::~SysAllocVM() throw()
|
||||
void SysMainMemory::ReserveAll()
|
||||
{
|
||||
CleanupMess();
|
||||
pxInstallSignalHandler();
|
||||
|
||||
DevCon.WriteLn( Color_StrongBlue, "Mapping host memory for virtual systems..." );
|
||||
ConsoleIndentScope indent(1);
|
||||
|
||||
m_ee.Reserve();
|
||||
m_iop.Reserve();
|
||||
m_vu.Reserve();
|
||||
|
||||
reserveNewVif(0);
|
||||
reserveNewVif(1);
|
||||
}
|
||||
|
||||
void SysMainMemory::CommitAll()
|
||||
{
|
||||
vtlb_Core_Alloc();
|
||||
if (m_ee.IsCommitted() && m_iop.IsCommitted() && m_vu.IsCommitted()) return;
|
||||
|
||||
DevCon.WriteLn( Color_StrongBlue, "Allocating host memory for virtual systems..." );
|
||||
ConsoleIndentScope indent(1);
|
||||
|
||||
m_ee.Commit();
|
||||
m_iop.Commit();
|
||||
m_vu.Commit();
|
||||
}
|
||||
|
||||
|
||||
void SysMainMemory::ResetAll()
|
||||
{
|
||||
CommitAll();
|
||||
|
||||
DevCon.WriteLn( Color_StrongBlue, "Resetting host memory for virtual systems..." );
|
||||
ConsoleIndentScope indent(1);
|
||||
|
||||
m_ee.Reset();
|
||||
m_iop.Reset();
|
||||
m_vu.Reset();
|
||||
|
||||
// Note: newVif is reset as part of other VIF structures.
|
||||
}
|
||||
|
||||
void SysMainMemory::DecommitAll()
|
||||
{
|
||||
if (!m_ee.IsCommitted() && !m_iop.IsCommitted() && !m_vu.IsCommitted()) return;
|
||||
|
||||
Console.WriteLn( Color_Blue, "Decommitting host memory for virtual systems..." );
|
||||
ConsoleIndentScope indent(1);
|
||||
|
||||
m_ee.Decommit();
|
||||
m_iop.Decommit();
|
||||
m_vu.Decommit();
|
||||
|
||||
closeNewVif(0);
|
||||
closeNewVif(1);
|
||||
|
||||
vtlb_Core_Free();
|
||||
}
|
||||
|
||||
void SysMainMemory::ReleaseAll()
|
||||
{
|
||||
DecommitAll();
|
||||
|
||||
Console.WriteLn( Color_Blue, "Releasing host memory maps for virtual systems..." );
|
||||
ConsoleIndentScope indent(1);
|
||||
|
||||
vtlb_Core_Free(); // Just to be sure... (calling order could result in it getting missed during Decommit).
|
||||
|
||||
releaseNewVif(0);
|
||||
releaseNewVif(1);
|
||||
|
||||
m_ee.Decommit();
|
||||
m_iop.Decommit();
|
||||
m_vu.Decommit();
|
||||
|
||||
safe_delete(Source_PageFault);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysCpuProviderPack (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
SysCpuProviderPack::SysCpuProviderPack()
|
||||
{
|
||||
Console.WriteLn( "Allocating memory for recompilers..." );
|
||||
Console.WriteLn( Color_StrongBlue, "Reserving memory for recompilers..." );
|
||||
ConsoleIndentScope indent(1);
|
||||
|
||||
CpuProviders = new CpuInitializerSet();
|
||||
|
||||
try {
|
||||
recCpu.Allocate();
|
||||
recCpu.Reserve();
|
||||
}
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
m_RecExceptionEE = ex.Clone();
|
||||
Console.Error( L"EE Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
|
||||
Console.Error( L"EE Recompiler Reservation Failed:\n" + ex.FormatDiagnosticMessage() );
|
||||
recCpu.Shutdown();
|
||||
}
|
||||
|
||||
try {
|
||||
psxRec.Allocate();
|
||||
psxRec.Reserve();
|
||||
}
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
m_RecExceptionIOP = ex.Clone();
|
||||
Console.Error( L"IOP Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
|
||||
Console.Error( L"IOP Recompiler Reservation Failed:\n" + ex.FormatDiagnosticMessage() );
|
||||
psxRec.Shutdown();
|
||||
}
|
||||
|
||||
// hmm! : VU0 and VU1 pre-allocations should do sVU and mVU separately? Sounds complicated. :(
|
||||
|
||||
// If both VUrecs failed, then make sure the SuperVU is totally closed out, because it
|
||||
// actually initializes everything once and then shares it between both VU recs.
|
||||
if( !IsRecAvailable_SuperVU0() && !IsRecAvailable_SuperVU1() )
|
||||
SuperVUDestroy( -1 );
|
||||
}
|
||||
|
||||
bool SysCpuProviderPack::IsRecAvailable_MicroVU0() const { return CpuProviders->microVU0.IsAvailable(); }
|
||||
|
@ -353,12 +485,6 @@ void SysCpuProviderPack::CleanupMess() throw()
|
|||
{
|
||||
try
|
||||
{
|
||||
closeNewVif(0);
|
||||
closeNewVif(1);
|
||||
|
||||
// Special SuperVU "complete" terminator (stupid hacky recompiler)
|
||||
SuperVUDestroy( -1 );
|
||||
|
||||
psxRec.Shutdown();
|
||||
recCpu.Shutdown();
|
||||
}
|
||||
|
@ -418,15 +544,13 @@ void SysClearExecutionCache()
|
|||
{
|
||||
GetCpuProviders().ApplyConfig();
|
||||
|
||||
// SuperVUreset will do nothing is none of the recs are initialized.
|
||||
// But it's needed if one or the other is initialized.
|
||||
SuperVUReset(-1);
|
||||
|
||||
Cpu->Reset();
|
||||
psxCpu->Reset();
|
||||
// mVU's VU0 needs to be properly initialised for macro mode even if it's not used for micro mode!
|
||||
|
||||
// mVU's VU0 needs to be properly initialized for macro mode even if it's not used for micro mode!
|
||||
if (CHECK_EEREC)
|
||||
((BaseVUmicroCPU*)GetCpuProviders().CpuProviders->microVU0)->Reset();
|
||||
|
||||
CpuVU0->Reset();
|
||||
CpuVU1->Reset();
|
||||
|
||||
|
@ -444,19 +568,17 @@ u8* SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller)
|
|||
|
||||
if( (Mem == NULL) || (bounds != 0 && (((uptr)Mem + size) > bounds)) )
|
||||
{
|
||||
if( base != NULL )
|
||||
if( base )
|
||||
{
|
||||
DbgCon.Warning( "First try failed allocating %s at address 0x%x", caller, base );
|
||||
|
||||
// memory allocation *must* have the top bit clear, so let's try again
|
||||
// with NULL (let the OS pick something for us).
|
||||
|
||||
// Let's try again at an OS-picked memory area, and then hope it meets needed
|
||||
// boundschecking criteria below.
|
||||
SafeSysMunmap( Mem, size );
|
||||
|
||||
Mem = (u8*)HostSys::Mmap( NULL, size );
|
||||
Mem = (u8*)HostSys::Mmap( 0, size );
|
||||
}
|
||||
|
||||
if( bounds != 0 && (((uptr)Mem + size) > bounds) )
|
||||
if( (bounds != 0) && (((uptr)Mem + size) > bounds) )
|
||||
{
|
||||
DevCon.Warning( "Second try failed allocating %s, block ptr 0x%x does not meet required criteria.", caller, Mem );
|
||||
SafeSysMunmap( Mem, size );
|
||||
|
@ -481,5 +603,5 @@ wxString SysGetDiscID()
|
|||
// region and revision).
|
||||
}
|
||||
|
||||
return wxsFormat( L"%8.8x", ElfCRC );
|
||||
return pxsFmt( L"%08x", ElfCRC );
|
||||
}
|
||||
|
|
|
@ -21,8 +21,81 @@
|
|||
#include "Utilities/Threading.h" // to use threading stuff, include the Threading namespace in your file.
|
||||
#include "CDVD/CDVDaccess.h"
|
||||
|
||||
#include "vtlb.h"
|
||||
|
||||
typedef SafeArray<u8> VmStateBuffer;
|
||||
|
||||
class BaseVUmicroCPU;
|
||||
class RecompiledCodeReserve;
|
||||
|
||||
// This is a table of default virtual map addresses for ps2vm components. These locations
|
||||
// are provided and used to assist in debugging and possibly hacking; as it makes it possible
|
||||
// for a programmer to know exactly where to look (consistently!) for the base address of
|
||||
// the various virtual machine components. These addresses can be keyed directly into the
|
||||
// debugger's disasm window to get disassembly of recompiled code, and they can be used to help
|
||||
// identify recompiled code addresses in the callstack.
|
||||
|
||||
// All of these areas should be reserved as soon as possible during program startup, and its
|
||||
// important that none of the areas overlap. In all but superVU's case, failure due to overlap
|
||||
// or other conflict will result in the operating system picking a preferred address for the mapping.
|
||||
|
||||
namespace HostMemoryMap
|
||||
{
|
||||
// superVU is OLD SCHOOL, and it requires its allocation to be in the lower 256mb
|
||||
// of the virtual memory space. (8mb each)
|
||||
static const uptr sVU0rec = _256mb - (_8mb*3);
|
||||
static const uptr sVU1rec = _256mb - (_8mb*2);
|
||||
|
||||
// PS2 main memory, SPR, and ROMs
|
||||
static const uptr EEmem = 0x20000000;
|
||||
|
||||
// IOP main memory and ROMs
|
||||
static const uptr IOPmem = 0x24000000;
|
||||
|
||||
// VU0 and VU1 memory.
|
||||
static const uptr VUmem = 0x28000000;
|
||||
|
||||
// EE recompiler code cache area (64mb)
|
||||
static const uptr EErec = 0x30000000;
|
||||
|
||||
// IOP recompiler code cache area (16 or 32mb)
|
||||
static const uptr IOPrec = 0x34000000;
|
||||
|
||||
// newVif0 recompiler code cache area (16mb)
|
||||
static const uptr VIF0rec = 0x36000000;
|
||||
|
||||
// newVif1 recompiler code cache area (32mb)
|
||||
static const uptr VIF1rec = 0x38000000;
|
||||
|
||||
// microVU1 recompiler code cache area (32 or 64mb)
|
||||
static const uptr mVU0rec = 0x3C000000;
|
||||
|
||||
// microVU0 recompiler code cache area (64mb)
|
||||
static const uptr mVU1rec = 0x40000000;
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysMainMemory
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class provides the main memory for the virtual machines.
|
||||
class SysMainMemory
|
||||
{
|
||||
protected:
|
||||
eeMemoryReserve m_ee;
|
||||
iopMemoryReserve m_iop;
|
||||
vuMemoryReserve m_vu;
|
||||
|
||||
public:
|
||||
SysMainMemory();
|
||||
virtual ~SysMainMemory() throw();
|
||||
|
||||
virtual void ReserveAll();
|
||||
virtual void CommitAll();
|
||||
virtual void ResetAll();
|
||||
virtual void DecommitAll();
|
||||
virtual void ReleaseAll();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysAllocVM
|
||||
|
@ -83,6 +156,7 @@ extern SysCpuProviderPack& GetCpuProviders();
|
|||
|
||||
extern void SysLogMachineCaps(); // Detects cpu type and fills cpuInfo structs.
|
||||
extern void SysClearExecutionCache(); // clears recompiled execution caches!
|
||||
extern void SysOutOfMemory_EmergencyResponse(uptr blocksize);
|
||||
|
||||
extern u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed");
|
||||
extern void vSyncDebugStuff( uint frame );
|
||||
|
@ -90,6 +164,8 @@ extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true );
|
|||
|
||||
extern wxString SysGetDiscID();
|
||||
|
||||
extern SysMainMemory& GetVmMemory();
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PCSX2_SEH - Defines existence of "built in" Structured Exception Handling support.
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// =====================================================================================================
|
||||
// Cross-Platform Memory Protection (Used by VTLB, Recompilers and Texture caches)
|
||||
// =====================================================================================================
|
||||
// Win32 platforms use the SEH model: __try {} __except {}
|
||||
// Linux platforms use the POSIX Signals model: sigaction()
|
||||
|
||||
#include "Utilities/EventSource.h"
|
||||
|
||||
struct PageFaultInfo
|
||||
{
|
||||
uptr addr;
|
||||
|
||||
PageFaultInfo( uptr address )
|
||||
{
|
||||
addr = address;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IEventListener_PageFault
|
||||
// --------------------------------------------------------------------------------------
|
||||
class IEventListener_PageFault : public IEventDispatcher<PageFaultInfo>
|
||||
{
|
||||
public:
|
||||
typedef PageFaultInfo EvtParams;
|
||||
|
||||
public:
|
||||
virtual ~IEventListener_PageFault() throw() {}
|
||||
|
||||
virtual void DispatchEvent( const PageFaultInfo& evtinfo, bool& handled )
|
||||
{
|
||||
OnPageFaultEvent( evtinfo, handled );
|
||||
}
|
||||
|
||||
virtual void DispatchEvent( const PageFaultInfo& evtinfo )
|
||||
{
|
||||
pxFailRel( "Don't call me, damnit. Use DispatchException instead." );
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void OnPageFaultEvent( const PageFaultInfo& evtinfo, bool& handled ) {}
|
||||
};
|
||||
|
||||
class EventListener_PageFault : public IEventListener_PageFault
|
||||
{
|
||||
public:
|
||||
EventListener_PageFault();
|
||||
virtual ~EventListener_PageFault() throw();
|
||||
};
|
||||
|
||||
class SrcType_PageFault : public EventSource<IEventListener_PageFault>
|
||||
{
|
||||
protected:
|
||||
typedef EventSource<IEventListener_PageFault> _parent;
|
||||
|
||||
protected:
|
||||
bool m_handled;
|
||||
|
||||
public:
|
||||
SrcType_PageFault() {}
|
||||
virtual ~SrcType_PageFault() throw() { }
|
||||
|
||||
bool WasHandled() const { return m_handled; }
|
||||
virtual void Dispatch( const PageFaultInfo& params );
|
||||
|
||||
protected:
|
||||
virtual void _DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt );
|
||||
};
|
||||
|
||||
#ifdef __LINUX__
|
||||
|
||||
# define PCSX2_PAGEFAULT_PROTECT
|
||||
# define PCSX2_PAGEFAULT_EXCEPT
|
||||
|
||||
#elif defined( _WIN32 )
|
||||
|
||||
struct _EXCEPTION_POINTERS;
|
||||
extern int SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps);
|
||||
|
||||
# define PCSX2_PAGEFAULT_PROTECT __try
|
||||
# define PCSX2_PAGEFAULT_EXCEPT __except(SysPageFaultExceptionFilter(GetExceptionInformation())) {}
|
||||
|
||||
#else
|
||||
# error PCSX2 - Unsupported operating system platform.
|
||||
#endif
|
||||
|
||||
|
||||
extern void InstallSignalHandler();
|
||||
|
||||
extern SrcType_PageFault Source_PageFault;
|
|
@ -0,0 +1,68 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/PageFaultSource.h"
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// RecompiledCodeReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
// A recompiled code reserve is a simple sequential-growth block of memory which is auto-
|
||||
// cleared to INT 3 (0xcc) as needed.
|
||||
//
|
||||
class RecompiledCodeReserve : public BaseVmReserveListener
|
||||
{
|
||||
typedef BaseVmReserveListener _parent;
|
||||
|
||||
protected:
|
||||
// Specifies the number of blocks that should be committed automatically when the
|
||||
// reserve is created. Typically this chunk is larger than the block size, and
|
||||
// should be based on whatever typical overhead is needed for basic block use.
|
||||
uint m_def_commit;
|
||||
|
||||
wxString m_profiler_name;
|
||||
bool m_profiler_registered;
|
||||
|
||||
public:
|
||||
RecompiledCodeReserve( const wxString& name=wxEmptyString, uint defCommit = 0 );
|
||||
virtual ~RecompiledCodeReserve() throw();
|
||||
|
||||
virtual void* Reserve( size_t size, uptr base=0, uptr upper_bounds=0 );
|
||||
virtual void OnCommittedBlock( void* block );
|
||||
|
||||
virtual RecompiledCodeReserve& SetProfilerName( const wxString& shortname );
|
||||
virtual RecompiledCodeReserve& SetProfilerName( const char* shortname )
|
||||
{
|
||||
return SetProfilerName( fromUTF8(shortname) );
|
||||
}
|
||||
|
||||
void ThrowIfNotOk() const;
|
||||
|
||||
operator void*() { return m_baseptr; }
|
||||
operator const void*() const { return m_baseptr; }
|
||||
|
||||
operator u8*() { return (u8*)m_baseptr; }
|
||||
operator const u8*() const { return (u8*)m_baseptr; }
|
||||
|
||||
protected:
|
||||
void ResetProcessReserves() const;
|
||||
void DoCommitAndProtect( uptr page );
|
||||
|
||||
void _registerProfiler();
|
||||
void _termProfiler();
|
||||
|
||||
uint _calcDefaultCommitInBlocks() const;
|
||||
};
|
|
@ -22,9 +22,9 @@
|
|||
#include "GS.h"
|
||||
#include "Elfheader.h"
|
||||
#include "Patch.h"
|
||||
#include "PageFaultSource.h"
|
||||
#include "SysThreads.h"
|
||||
|
||||
#include "Utilities/PageFaultSource.h"
|
||||
#include "Utilities/TlsVariable.inl"
|
||||
|
||||
#ifdef __WXMSW__
|
||||
|
@ -111,13 +111,24 @@ void SysCoreThread::SetElfOverride( const wxString& elf )
|
|||
Hle_SetElfPath(elf.ToUTF8());
|
||||
}
|
||||
|
||||
void SysCoreThread::Reset()
|
||||
// Performs a quicker reset that does not deallocate memory associated with PS2 virtual machines
|
||||
// or cpu providers (recompilers).
|
||||
void SysCoreThread::ResetQuick()
|
||||
{
|
||||
Suspend();
|
||||
|
||||
m_resetVirtualMachine = true;
|
||||
m_hasActiveMachine = false;
|
||||
}
|
||||
|
||||
void SysCoreThread::Reset()
|
||||
{
|
||||
ResetQuick();
|
||||
GetVmMemory().DecommitAll();
|
||||
SysClearExecutionCache();
|
||||
}
|
||||
|
||||
|
||||
// Applies a full suite of new settings, which will automatically facilitate the necessary
|
||||
// resets of the core and components (including plugins, if needed). The scope of resetting
|
||||
// is determined by comparing the current settings against the new settings, so that only
|
||||
|
@ -159,6 +170,8 @@ void SysCoreThread::_reset_stuff_as_needed()
|
|||
// because of changes to the TLB. We don't actually support the TLB, however, so rec
|
||||
// resets aren't in fact *needed* ... yet. But might as well, no harm. --air
|
||||
|
||||
GetVmMemory().CommitAll();
|
||||
|
||||
if( m_resetVirtualMachine || m_resetRecompilers || m_resetProfilers )
|
||||
{
|
||||
SysClearExecutionCache();
|
||||
|
|
|
@ -184,6 +184,7 @@ public:
|
|||
|
||||
virtual void OnResumeReady();
|
||||
virtual void Reset();
|
||||
virtual void ResetQuick();
|
||||
virtual void Cancel( bool isBlocking=true );
|
||||
virtual bool Cancel( const wxTimeSpan& timeout );
|
||||
|
||||
|
|
|
@ -19,15 +19,15 @@
|
|||
#include "VUops.h"
|
||||
#include "R5900.h"
|
||||
|
||||
static const uint VU0_MEMSIZE = 0x1000;
|
||||
static const uint VU0_PROGSIZE = 0x1000;
|
||||
static const uint VU1_MEMSIZE = 0x4000;
|
||||
static const uint VU1_PROGSIZE = 0x4000;
|
||||
static const uint VU0_MEMSIZE = 0x1000; // 4kb
|
||||
static const uint VU0_PROGSIZE = 0x1000; // 4kb
|
||||
static const uint VU1_MEMSIZE = 0x4000; // 16kb
|
||||
static const uint VU1_PROGSIZE = 0x4000; // 16kb
|
||||
|
||||
static const uint VU0_MEMMASK = VU0_MEMSIZE-1;
|
||||
static const uint VU0_PROGMASK = VU0_PROGSIZE-1;
|
||||
static const uint VU1_MEMMASK = VU1_MEMSIZE-1;
|
||||
static const uint VU1_PROGMASK = VU1_PROGSIZE-1;
|
||||
static const uint VU0_MEMMASK = VU0_MEMSIZE-1;
|
||||
static const uint VU0_PROGMASK = VU0_PROGSIZE-1;
|
||||
static const uint VU1_MEMMASK = VU1_MEMSIZE-1;
|
||||
static const uint VU1_PROGMASK = VU1_PROGSIZE-1;
|
||||
|
||||
#define vuRunCycles (512*12) // Cycles to run ExecuteBlockJIT() for (called from within recs)
|
||||
#define vu0RunCycles (512*12) // Cycles to run vu0 for whenever ExecuteBlock() is called
|
||||
|
@ -47,9 +47,9 @@ static const uint VU1_PROGMASK = VU1_PROGSIZE-1;
|
|||
class BaseCpuProvider
|
||||
{
|
||||
protected:
|
||||
// allocation counter for multiple init/shutdown calls
|
||||
// (most or all implementations will need this!)
|
||||
int m_AllocCount;
|
||||
// allocation counter for multiple calls to Reserve. Most implementations should utilize
|
||||
// this variable for sake of robustness.
|
||||
u32 m_Reserved;
|
||||
|
||||
public:
|
||||
// this boolean indicates to some generic logging facilities if the VU's registers
|
||||
|
@ -60,19 +60,27 @@ public:
|
|||
public:
|
||||
BaseCpuProvider()
|
||||
{
|
||||
m_AllocCount = 0;
|
||||
m_Reserved = 0;
|
||||
}
|
||||
|
||||
virtual ~BaseCpuProvider() throw()
|
||||
{
|
||||
if( m_AllocCount != 0 )
|
||||
Console.Warning( "Cleanup miscount detected on CPU provider. Count=%d", m_AllocCount );
|
||||
if( m_Reserved != 0 )
|
||||
Console.Warning( "Cleanup miscount detected on CPU provider. Count=%d", m_Reserved );
|
||||
}
|
||||
|
||||
virtual const char* GetShortName() const=0;
|
||||
virtual wxString GetLongName() const=0;
|
||||
|
||||
virtual void Allocate()=0;
|
||||
// returns the number of bytes committed to the working caches for this CPU
|
||||
// provider (typically this refers to recompiled code caches, but could also refer
|
||||
// to other optional growable allocations).
|
||||
virtual size_t GetCommittedCache() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void Reserve()=0;
|
||||
virtual void Shutdown()=0;
|
||||
virtual void Reset()=0;
|
||||
virtual void Execute(u32 cycles)=0;
|
||||
|
@ -88,6 +96,15 @@ public:
|
|||
{
|
||||
cpu->Execute(1024);
|
||||
}
|
||||
|
||||
// Gets the current cache reserve allocated to this CPU (value returned in megabytes)
|
||||
virtual uint GetCacheReserve() const=0;
|
||||
|
||||
// Specifies the maximum cache reserve amount for this CPU (value in megabytes).
|
||||
// CPU providers are allowed to reset their reserves (recompiler resets, etc) if such is
|
||||
// needed to conform to the new amount requested.
|
||||
virtual void SetCacheReserve( uint reserveInMegs ) const=0;
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -149,13 +166,16 @@ public:
|
|||
const char* GetShortName() const { return "intVU0"; }
|
||||
wxString GetLongName() const { return L"VU0 Interpreter"; }
|
||||
|
||||
void Allocate() { }
|
||||
void Reserve() { }
|
||||
void Shutdown() throw() { }
|
||||
void Reset() { }
|
||||
|
||||
void Step();
|
||||
void Execute(u32 cycles);
|
||||
void Clear(u32 addr, u32 size) {}
|
||||
|
||||
uint GetCacheReserve() const { return 0; }
|
||||
void SetCacheReserve( uint reserveInMegs ) const {}
|
||||
};
|
||||
|
||||
class InterpVU1 : public BaseVUmicroCPU
|
||||
|
@ -167,13 +187,16 @@ public:
|
|||
const char* GetShortName() const { return "intVU1"; }
|
||||
wxString GetLongName() const { return L"VU1 Interpreter"; }
|
||||
|
||||
void Allocate() { }
|
||||
void Reserve() { }
|
||||
void Shutdown() throw() { }
|
||||
void Reset() { }
|
||||
|
||||
void Step();
|
||||
void Execute(u32 cycles);
|
||||
void Clear(u32 addr, u32 size) {}
|
||||
|
||||
uint GetCacheReserve() const { return 0; }
|
||||
void SetCacheReserve( uint reserveInMegs ) const {}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -188,13 +211,16 @@ public:
|
|||
const char* GetShortName() const { return "mVU0"; }
|
||||
wxString GetLongName() const { return L"microVU0 Recompiler"; }
|
||||
|
||||
void Allocate();
|
||||
void Reserve();
|
||||
void Shutdown() throw();
|
||||
|
||||
void Reset();
|
||||
void Execute(u32 cycles);
|
||||
void Clear(u32 addr, u32 size);
|
||||
void Vsync() throw();
|
||||
|
||||
uint GetCacheReserve() const;
|
||||
void SetCacheReserve( uint reserveInMegs ) const;
|
||||
};
|
||||
|
||||
class recMicroVU1 : public BaseVUmicroCPU
|
||||
|
@ -206,12 +232,15 @@ public:
|
|||
const char* GetShortName() const { return "mVU1"; }
|
||||
wxString GetLongName() const { return L"microVU1 Recompiler"; }
|
||||
|
||||
void Allocate();
|
||||
void Reserve();
|
||||
void Shutdown() throw();
|
||||
void Reset();
|
||||
void Execute(u32 cycles);
|
||||
void Clear(u32 addr, u32 size);
|
||||
void Vsync() throw();
|
||||
|
||||
uint GetCacheReserve() const;
|
||||
void SetCacheReserve( uint reserveInMegs ) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -226,11 +255,14 @@ public:
|
|||
const char* GetShortName() const { return "sVU0"; }
|
||||
wxString GetLongName() const { return L"SuperVU0 Recompiler"; }
|
||||
|
||||
void Allocate();
|
||||
void Reserve();
|
||||
void Shutdown() throw();
|
||||
void Reset();
|
||||
void Execute(u32 cycles);
|
||||
void Clear(u32 Addr, u32 Size);
|
||||
|
||||
uint GetCacheReserve() const;
|
||||
void SetCacheReserve( uint reserveInMegs ) const;
|
||||
};
|
||||
|
||||
class recSuperVU1 : public BaseVUmicroCPU
|
||||
|
@ -241,21 +273,20 @@ public:
|
|||
const char* GetShortName() const { return "sVU1"; }
|
||||
wxString GetLongName() const { return L"SuperVU1 Recompiler"; }
|
||||
|
||||
void Allocate();
|
||||
void Reserve();
|
||||
void Shutdown() throw();
|
||||
void Reset();
|
||||
void Execute(u32 cycles);
|
||||
void Clear(u32 Addr, u32 Size);
|
||||
|
||||
uint GetCacheReserve() const;
|
||||
void SetCacheReserve( uint reserveInMegs ) const;
|
||||
};
|
||||
|
||||
extern BaseVUmicroCPU* CpuVU0;
|
||||
extern BaseVUmicroCPU* CpuVU1;
|
||||
|
||||
|
||||
extern void vuMicroMemAlloc();
|
||||
extern void vuMicroMemShutdown();
|
||||
extern void vuMicroMemReset();
|
||||
|
||||
// VU0
|
||||
extern void vu0ResetRegs();
|
||||
extern void __fastcall vu0ExecMicro(u32 addr);
|
||||
|
|
|
@ -18,43 +18,41 @@
|
|||
#include "Common.h"
|
||||
#include "VUmicro.h"
|
||||
|
||||
|
||||
__aligned16 VURegs vuRegs[2];
|
||||
|
||||
static u8* m_vuAllMem = NULL;
|
||||
static const uint m_vuMemSize =
|
||||
0x1000 + // VU0micro memory
|
||||
0x4000 + // VU0 memory
|
||||
0x4000 + // VU1 memory
|
||||
0x4000;
|
||||
|
||||
void vuMicroMemAlloc()
|
||||
vuMemoryReserve::vuMemoryReserve()
|
||||
: _parent( L"VU0/1 on-chip memory", VU1_PROGSIZE + VU1_MEMSIZE + VU0_PROGSIZE + VU0_MEMSIZE )
|
||||
{
|
||||
if( m_vuAllMem == NULL )
|
||||
m_vuAllMem = vtlb_malloc( m_vuMemSize, 16 );
|
||||
|
||||
if( m_vuAllMem == NULL )
|
||||
throw Exception::OutOfMemory( L"VU0 and VU1 on-chip memory" );
|
||||
|
||||
u8* curpos = m_vuAllMem;
|
||||
VU0.Micro = curpos; curpos += 0x1000;
|
||||
VU0.Mem = curpos; curpos += 0x4000;
|
||||
VU1.Micro = curpos; curpos += 0x4000;
|
||||
VU1.Mem = curpos;
|
||||
//curpos += 0x4000;
|
||||
}
|
||||
|
||||
void vuMicroMemShutdown()
|
||||
void vuMemoryReserve::Reserve()
|
||||
{
|
||||
// -- VTLB Memory Allocation --
|
||||
_parent::Reserve(HostMemoryMap::VUmem);
|
||||
//_parent::Reserve(EmuConfig.HostMemMap.VUmem);
|
||||
|
||||
vtlb_free( m_vuAllMem, m_vuMemSize );
|
||||
m_vuAllMem = NULL;
|
||||
u8* curpos = m_reserve.GetPtr();
|
||||
VU0.Micro = curpos; curpos += VU0_PROGSIZE;
|
||||
VU0.Mem = curpos; curpos += VU0_MEMSIZE;
|
||||
VU1.Micro = curpos; curpos += VU1_PROGSIZE;
|
||||
VU1.Mem = curpos; curpos += VU1_MEMSIZE;
|
||||
}
|
||||
|
||||
void vuMicroMemReset()
|
||||
void vuMemoryReserve::Release()
|
||||
{
|
||||
pxAssume( VU0.Mem != NULL );
|
||||
pxAssume( VU1.Mem != NULL );
|
||||
_parent::Release();
|
||||
|
||||
VU0.Micro = VU0.Mem = NULL;
|
||||
VU1.Micro = VU1.Mem = NULL;
|
||||
}
|
||||
|
||||
void vuMemoryReserve::Reset()
|
||||
{
|
||||
_parent::Reset();
|
||||
|
||||
pxAssume( VU0.Mem );
|
||||
pxAssume( VU1.Mem );
|
||||
|
||||
memMapVUmicro();
|
||||
|
||||
|
@ -67,8 +65,6 @@ void vuMicroMemReset()
|
|||
VU0.VF[0].f.z = 0.0f;
|
||||
VU0.VF[0].f.w = 1.0f;
|
||||
VU0.VI[0].UL = 0;
|
||||
memzero_ptr<4*1024>(VU0.Mem);
|
||||
memzero_ptr<4*1024>(VU0.Micro);
|
||||
|
||||
// === VU1 Initialization ===
|
||||
memzero(VU1.ACC);
|
||||
|
@ -79,8 +75,6 @@ void vuMicroMemReset()
|
|||
VU1.VF[0].f.z = 0.0f;
|
||||
VU1.VF[0].f.w = 1.0f;
|
||||
VU1.VI[0].UL = 0;
|
||||
memzero_ptr<16*1024>(VU1.Mem);
|
||||
memzero_ptr<16*1024>(VU1.Micro);
|
||||
}
|
||||
|
||||
void SaveStateBase::vuMicroFreeze()
|
||||
|
|
|
@ -107,6 +107,7 @@ enum MenuIdentifiers
|
|||
MenuId_Config_SysSettings,
|
||||
MenuId_Config_McdSettings,
|
||||
MenuId_Config_AppSettings,
|
||||
MenuId_Config_GameDatabase,
|
||||
MenuId_Config_BIOS,
|
||||
|
||||
// Plugin ID order is important. Must match the order in tbl_PluginInfo.
|
||||
|
@ -475,7 +476,7 @@ public:
|
|||
// blocked threads stalling the GUI.
|
||||
ExecutorThread SysExecutorThread;
|
||||
ScopedPtr<SysCpuProviderPack> m_CpuProviders;
|
||||
ScopedPtr<SysAllocVM> m_VmAllocs;
|
||||
ScopedPtr<SysMainMemory> m_VmReserve;
|
||||
|
||||
protected:
|
||||
wxWindowID m_id_MainFrame;
|
||||
|
@ -497,6 +498,8 @@ public:
|
|||
void SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override=wxEmptyString );
|
||||
void LogicalVsync();
|
||||
|
||||
SysMainMemory& GetVmReserve();
|
||||
|
||||
GSFrame& GetGsFrame() const;
|
||||
MainEmuFrame& GetMainFrame() const;
|
||||
|
||||
|
@ -526,8 +529,6 @@ public:
|
|||
void StartPendingSave();
|
||||
void ClearPendingSave();
|
||||
|
||||
void AllocateVM();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// App-wide Resources
|
||||
// --------------------------------------------------------------------------
|
||||
|
|
|
@ -19,89 +19,80 @@
|
|||
|
||||
#include <wx/stackwalk.h>
|
||||
|
||||
class StackDump : public wxStackWalker
|
||||
{
|
||||
protected:
|
||||
FastFormatUnicode m_stackTrace;
|
||||
wxString m_srcFuncName;
|
||||
bool m_ignoreDone;
|
||||
int m_skipped;
|
||||
|
||||
public:
|
||||
StackDump( const FnChar_t* src_function_name )
|
||||
{
|
||||
if( src_function_name != NULL )
|
||||
m_srcFuncName = fromUTF8(src_function_name);
|
||||
|
||||
m_ignoreDone = false;
|
||||
m_skipped = 0;
|
||||
}
|
||||
|
||||
const wxChar* GetStackTrace() const { return m_stackTrace.c_str(); }
|
||||
|
||||
protected:
|
||||
virtual void OnStackFrame(const wxStackFrame& frame)
|
||||
{
|
||||
/*if( m_srcFuncName.IsEmpty() || m_srcFuncName == name )
|
||||
{
|
||||
// FIXME: This logic isn't reliable yet.
|
||||
// It's possible for our debug information to not match the function names returned by
|
||||
// __pxFUNCTION__ (might happen in linux a lot, and could happen in win32 due to
|
||||
// inlining on Dev aserts). The better approach is a system the queues up all the
|
||||
// stacktrace info in individual wxStrings, and does a two-pass check -- first pass
|
||||
// for the function name and, if not found, a second pass that just skips the first
|
||||
// few stack entries.
|
||||
|
||||
// It's important we only walk the stack once because Linux (argh, always linux!) has
|
||||
// a really god aweful slow stack walker.
|
||||
|
||||
// I'm not doing it right now because I've worked on this mess enough for one week. --air
|
||||
|
||||
m_ignoreDone = true;
|
||||
}
|
||||
|
||||
if( !m_ignoreDone )
|
||||
{
|
||||
m_skipped++;
|
||||
return;
|
||||
}*/
|
||||
|
||||
m_stackTrace.Write(pxsFmt( L"[%02d]", frame.GetLevel()-m_skipped));
|
||||
|
||||
if (!frame.GetName().IsEmpty())
|
||||
m_stackTrace.Write(pxsFmt( L" %-44s", frame.GetName().c_str() ));
|
||||
else
|
||||
m_stackTrace.Write(pxsFmt( L" 0x%-42p", frame.GetAddress() ));
|
||||
|
||||
if( frame.HasSourceLocation() )
|
||||
{
|
||||
wxFileName wxfn(frame.GetFileName());
|
||||
|
||||
wxfn.SetVolume( wxEmptyString );
|
||||
for( int i=0; i<2; ++i )
|
||||
wxfn.RemoveDir(0);
|
||||
|
||||
m_stackTrace.Write( L" %s:%d", wxfn.GetFullPath().c_str(), frame.GetLine() );
|
||||
}
|
||||
|
||||
m_stackTrace.Write(L"\n");
|
||||
}
|
||||
};
|
||||
|
||||
static wxString pxGetStackTrace( const FnChar_t* calledFrom )
|
||||
{
|
||||
wxString stackTrace;
|
||||
|
||||
class StackDump : public wxStackWalker
|
||||
{
|
||||
protected:
|
||||
wxString m_stackTrace;
|
||||
wxString m_srcFuncName;
|
||||
bool m_ignoreDone;
|
||||
int m_skipped;
|
||||
|
||||
public:
|
||||
StackDump( const FnChar_t* src_function_name )
|
||||
{
|
||||
if( src_function_name != NULL )
|
||||
m_srcFuncName = fromUTF8(src_function_name);
|
||||
|
||||
m_ignoreDone = false;
|
||||
m_skipped = 0;
|
||||
}
|
||||
|
||||
const wxString& GetStackTrace() const { return m_stackTrace; }
|
||||
|
||||
protected:
|
||||
virtual void OnStackFrame(const wxStackFrame& frame)
|
||||
{
|
||||
wxString name( frame.GetName() );
|
||||
if( name.IsEmpty() )
|
||||
{
|
||||
name = wxsFormat( L"%p ", frame.GetAddress() );
|
||||
}
|
||||
/*else if( m_srcFuncName.IsEmpty() || m_srcFuncName == name )
|
||||
{
|
||||
// FIXME: This logic isn't reliable yet.
|
||||
// It's possible for our debug information to not match the function names returned by
|
||||
// __pxFUNCTION__ (might happen in linux a lot, and could happen in win32 due to
|
||||
// inlining on Dev aserts). The better approach is a system the queues up all the
|
||||
// stacktrace info in individual wxStrings, and does a two-pass check -- first pass
|
||||
// for the function name and, if not found, a second pass that just skips the first
|
||||
// few stack entries.
|
||||
|
||||
// It's important we only walk the stack once because Linux (argh, always linux!) has
|
||||
// a really god aweful slow stack walker.
|
||||
|
||||
// I'm not doing it right now because I've worked on this mess enough for one week. --air
|
||||
|
||||
m_ignoreDone = true;
|
||||
}
|
||||
|
||||
if( !m_ignoreDone )
|
||||
{
|
||||
m_skipped++;
|
||||
return;
|
||||
}*/
|
||||
|
||||
//wxString briefName;
|
||||
wxString essenName;
|
||||
|
||||
if( frame.HasSourceLocation() )
|
||||
{
|
||||
wxFileName wxfn(frame.GetFileName());
|
||||
//briefName.Printf( L"(%s:%d)", wxfn.GetFullName().c_str(), frame.GetLine() );
|
||||
|
||||
wxfn.SetVolume( wxEmptyString );
|
||||
int count = wxfn.GetDirCount();
|
||||
for( int i=0; i<2; ++i )
|
||||
wxfn.RemoveDir(0);
|
||||
|
||||
essenName.Printf( L"%s:%d", wxfn.GetFullPath().c_str(), frame.GetLine() );
|
||||
}
|
||||
|
||||
m_stackTrace += wxString::Format( L"[%02d] %-44s %s\n",
|
||||
frame.GetLevel()-m_skipped,
|
||||
name.c_str(),
|
||||
essenName.c_str()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
StackDump dump( calledFrom );
|
||||
dump.Walk( 3 );
|
||||
return dump.GetStackTrace();
|
||||
StackDump dump( calledFrom );
|
||||
dump.Walk( 3 );
|
||||
return dump.GetStackTrace();
|
||||
}
|
||||
|
||||
#ifdef __WXDEBUG__
|
||||
|
|
|
@ -109,6 +109,17 @@ void AppCoreThread::Reset()
|
|||
_parent::Reset();
|
||||
}
|
||||
|
||||
void AppCoreThread::ResetQuick()
|
||||
{
|
||||
if( !GetSysExecutorThread().IsSelf() )
|
||||
{
|
||||
GetSysExecutorThread().PostEvent( SysExecEvent_InvokeCoreThreadMethod(&AppCoreThread::ResetQuick) );
|
||||
return;
|
||||
}
|
||||
|
||||
_parent::ResetQuick();
|
||||
}
|
||||
|
||||
ExecutorThread& GetSysExecutorThread()
|
||||
{
|
||||
return wxGetApp().SysExecutorThread;
|
||||
|
@ -183,7 +194,6 @@ void Pcsx2App::SysApplySettings()
|
|||
void AppCoreThread::OnResumeReady()
|
||||
{
|
||||
wxGetApp().SysApplySettings();
|
||||
wxGetApp().AllocateVM();
|
||||
wxGetApp().PostMethod( AppSaveSettings );
|
||||
_parent::OnResumeReady();
|
||||
}
|
||||
|
|
|
@ -134,6 +134,7 @@ public:
|
|||
virtual void Suspend( bool isBlocking=false );
|
||||
virtual void Resume();
|
||||
virtual void Reset();
|
||||
virtual void ResetQuick();
|
||||
virtual void Cancel( bool isBlocking=true );
|
||||
virtual bool StateCheckInThread();
|
||||
virtual void ChangeCdvdSource();
|
||||
|
|
|
@ -163,6 +163,12 @@ public:
|
|||
// this second layer class to act as a bridge between the event system and the class's
|
||||
// handler implementations.
|
||||
//
|
||||
// Explained in detail: The class that wants to listen to shit will implement its expected
|
||||
// virtual overrides from the listener classes (OnCoreThread_Started, for example), and then
|
||||
// it adds an instance of the EventListenerHelper_CoreThread class to itself, instead of
|
||||
// *inheriting* from it. Thusly, the Helper gets initialized when the class is created,
|
||||
// and when events are dispatched to the listener, it forwards the event to the main class.
|
||||
// --air
|
||||
|
||||
template< typename TypeToDispatchTo >
|
||||
class EventListenerHelper_CoreThread : public EventListener_CoreThread
|
||||
|
@ -212,9 +218,9 @@ public:
|
|||
protected:
|
||||
void CorePlugins_OnLoaded() { Owner.OnCorePlugins_Loaded(); }
|
||||
void CorePlugins_OnInit() { Owner.OnCorePlugins_Init(); }
|
||||
void CorePlugins_OnOpening() { Owner.OnCorePlugins_Opening(); }
|
||||
void CorePlugins_OnOpening() { Owner.OnCorePlugins_Opening(); }
|
||||
void CorePlugins_OnOpened() { Owner.OnCorePlugins_Opened(); }
|
||||
void CorePlugins_OnClosing() { Owner.OnCorePlugins_Closing(); }
|
||||
void CorePlugins_OnClosing() { Owner.OnCorePlugins_Closing(); }
|
||||
void CorePlugins_OnClosed() { Owner.OnCorePlugins_Closed(); }
|
||||
void CorePlugins_OnShutdown() { Owner.OnCorePlugins_Shutdown(); }
|
||||
void CorePlugins_OnUnloaded() { Owner.OnCorePlugins_Unloaded(); }
|
||||
|
|
|
@ -238,12 +238,6 @@ void Pcsx2App::OpenProgramLog()
|
|||
if( m_current_focus ) m_current_focus->SetFocus();
|
||||
}
|
||||
|
||||
void Pcsx2App::AllocateVM()
|
||||
{
|
||||
if (m_VmAllocs) return;
|
||||
m_VmAllocs = new SysAllocVM();
|
||||
}
|
||||
|
||||
void Pcsx2App::AllocateCoreStuffs()
|
||||
{
|
||||
if( AppRpc_TryInvokeAsync( &Pcsx2App::AllocateCoreStuffs ) ) return;
|
||||
|
@ -252,6 +246,8 @@ void Pcsx2App::AllocateCoreStuffs()
|
|||
SysLogMachineCaps();
|
||||
AppApplySettings();
|
||||
|
||||
GetVmReserve().ReserveAll();
|
||||
|
||||
if( !m_CpuProviders )
|
||||
{
|
||||
// FIXME : Some or all of SysCpuProviderPack should be run from the SysExecutor thread,
|
||||
|
@ -284,40 +280,40 @@ void Pcsx2App::AllocateCoreStuffs()
|
|||
|
||||
if( BaseException* ex = m_CpuProviders->GetException_EE() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* R5900 (EE)\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
|
||||
scrollableTextArea->AppendText( L"* R5900 (EE)\n\t" + ex->FormatDisplayMessage() + L"\n\n" );
|
||||
recOps.EnableEE = false;
|
||||
}
|
||||
|
||||
if( BaseException* ex = m_CpuProviders->GetException_IOP() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* R3000A (IOP)\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
|
||||
scrollableTextArea->AppendText( L"* R3000A (IOP)\n\t" + ex->FormatDisplayMessage() + L"\n\n" );
|
||||
recOps.EnableIOP = false;
|
||||
}
|
||||
|
||||
if( BaseException* ex = m_CpuProviders->GetException_MicroVU0() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* microVU0\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
|
||||
scrollableTextArea->AppendText( L"* microVU0\n\t" + ex->FormatDisplayMessage() + L"\n\n" );
|
||||
recOps.UseMicroVU0 = false;
|
||||
recOps.EnableVU0 = recOps.EnableVU0 && m_CpuProviders->IsRecAvailable_SuperVU0();
|
||||
}
|
||||
|
||||
if( BaseException* ex = m_CpuProviders->GetException_MicroVU1() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* microVU1\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
|
||||
scrollableTextArea->AppendText( L"* microVU1\n\t" + ex->FormatDisplayMessage() + L"\n\n" );
|
||||
recOps.UseMicroVU1 = false;
|
||||
recOps.EnableVU1 = recOps.EnableVU1 && m_CpuProviders->IsRecAvailable_SuperVU1();
|
||||
}
|
||||
|
||||
if( BaseException* ex = m_CpuProviders->GetException_SuperVU0() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* SuperVU0\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
|
||||
scrollableTextArea->AppendText( L"* SuperVU0\n\t" + ex->FormatDisplayMessage() + L"\n\n" );
|
||||
recOps.UseMicroVU0 = m_CpuProviders->IsRecAvailable_MicroVU0();
|
||||
recOps.EnableVU0 = recOps.EnableVU0 && recOps.UseMicroVU0;
|
||||
}
|
||||
|
||||
if( BaseException* ex = m_CpuProviders->GetException_SuperVU1() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* SuperVU1\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" );
|
||||
scrollableTextArea->AppendText( L"* SuperVU1\n\t" + ex->FormatDisplayMessage() + L"\n\n" );
|
||||
recOps.UseMicroVU1 = m_CpuProviders->IsRecAvailable_MicroVU1();
|
||||
recOps.EnableVU1 = recOps.EnableVU1 && recOps.UseMicroVU1;
|
||||
}
|
||||
|
@ -525,12 +521,15 @@ bool Pcsx2App::OnInit()
|
|||
|
||||
InitCPUTicks();
|
||||
|
||||
pxDoAssert = AppDoAssert;
|
||||
pxDoAssert = AppDoAssert;
|
||||
pxDoOutOfMemory = SysOutOfMemory_EmergencyResponse;
|
||||
|
||||
g_Conf = new AppConfig();
|
||||
wxInitAllImageHandlers();
|
||||
|
||||
Console.WriteLn("Begin parsing commandline...");
|
||||
Console.WriteLn("Command line parsing...");
|
||||
if( !_parent::OnInit() ) return false;
|
||||
Console.WriteLn("Command line parsed!");
|
||||
|
||||
wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
|
||||
|
||||
|
@ -815,12 +814,12 @@ void Pcsx2App::CleanUp()
|
|||
|
||||
__fi wxString AddAppName( const wxChar* fmt )
|
||||
{
|
||||
return wxsFormat( fmt, pxGetAppName().c_str() );
|
||||
return pxsFmt( fmt, pxGetAppName().c_str() );
|
||||
}
|
||||
|
||||
__fi wxString AddAppName( const char* fmt )
|
||||
{
|
||||
return wxsFormat( fromUTF8(fmt), pxGetAppName().c_str() );
|
||||
return pxsFmt( fromUTF8(fmt), pxGetAppName().c_str() );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -702,6 +702,12 @@ void Pcsx2App::PostIdleAppMethod( FnPtr_Pcsx2App method )
|
|||
AddIdleEvent( evt );
|
||||
}
|
||||
|
||||
SysMainMemory& Pcsx2App::GetVmReserve()
|
||||
{
|
||||
if (!m_VmReserve) m_VmReserve = new SysMainMemory();
|
||||
return *m_VmReserve;
|
||||
}
|
||||
|
||||
void Pcsx2App::OpenGsPanel()
|
||||
{
|
||||
if( AppRpc_TryInvoke( &Pcsx2App::OpenGsPanel ) ) return;
|
||||
|
@ -851,7 +857,7 @@ protected:
|
|||
|
||||
DbgCon.WriteLn( Color_Gray, "(SysExecute) received." );
|
||||
|
||||
CoreThread.Reset();
|
||||
CoreThread.ResetQuick();
|
||||
|
||||
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
|
||||
if( m_UseCDVDsrc )
|
||||
|
@ -930,6 +936,11 @@ MainEmuFrame* GetMainFramePtr()
|
|||
return wxTheApp ? wxGetApp().GetMainFramePtr() : NULL;
|
||||
}
|
||||
|
||||
SysMainMemory& GetVmMemory()
|
||||
{
|
||||
return wxGetApp().GetVmReserve();
|
||||
}
|
||||
|
||||
SysCoreThread& GetCoreThread()
|
||||
{
|
||||
return CoreThread;
|
||||
|
|
|
@ -193,7 +193,7 @@ void ConsoleLogFrame::ColorArray::Create( int fontsize )
|
|||
new (&m_table[Color_StrongCyan]) wxTextAttr( wxNullColour, wxNullColour, fixedB );
|
||||
new (&m_table[Color_StrongYellow]) wxTextAttr( wxNullColour, wxNullColour, fixedB );
|
||||
new (&m_table[Color_StrongWhite]) wxTextAttr( wxNullColour, wxNullColour, fixedB );
|
||||
|
||||
|
||||
SetColorScheme_Light();
|
||||
}
|
||||
|
||||
|
@ -281,10 +281,10 @@ enum MenuIDs_t
|
|||
MenuId_FontSize_Normal,
|
||||
MenuId_FontSize_Large,
|
||||
MenuId_FontSize_Huge,
|
||||
|
||||
|
||||
MenuId_ColorScheme_Light = 0x20,
|
||||
MenuId_ColorScheme_Dark,
|
||||
|
||||
|
||||
MenuId_LogSource_EnableAll = 0x30,
|
||||
MenuId_LogSource_DisableAll,
|
||||
MenuId_LogSource_Devel,
|
||||
|
@ -322,7 +322,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
static ConsoleLogSource* const ConLogSources[] =
|
||||
static ConsoleLogSource* const ConLogSources[] =
|
||||
{
|
||||
(ConsoleLogSource*)&SysConsole.eeConsole,
|
||||
(ConsoleLogSource*)&SysConsole.iopConsole,
|
||||
|
@ -334,7 +334,7 @@ static ConsoleLogSource* const ConLogSources[] =
|
|||
(ConsoleLogSource*)&pxConLog_Thread,
|
||||
};
|
||||
|
||||
static const bool ConLogDefaults[] =
|
||||
static const bool ConLogDefaults[] =
|
||||
{
|
||||
true,
|
||||
true,
|
||||
|
@ -437,7 +437,7 @@ ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, A
|
|||
|
||||
menuSources.Append( MenuId_LogSource_Devel, _("Dev/Verbose"), _("Shows PCSX2 developer logs"), wxITEM_CHECK );
|
||||
menuSources.AppendSeparator();
|
||||
|
||||
|
||||
uint srcnt = ArraySize(ConLogSources);
|
||||
for (uint i=0; i<srcnt; ++i)
|
||||
{
|
||||
|
@ -609,7 +609,7 @@ bool ConsoleLogFrame::Write( ConsoleColors color, const wxString& text )
|
|||
{
|
||||
// Too many color changes causes huge slowdowns when decorating the rich textview, so
|
||||
// include a secondary check to avoid having a colorful log spam killing gui responsiveness.
|
||||
|
||||
|
||||
if( m_CurQueuePos > 0x100000 || m_QueueColorSection.GetLength() > 256 )
|
||||
{
|
||||
++m_WaitingThreadsForFlush;
|
||||
|
@ -629,7 +629,7 @@ bool ConsoleLogFrame::Write( ConsoleColors color, const wxString& text )
|
|||
if( m_WaitingThreadsForFlush != 0 ) --m_WaitingThreadsForFlush;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -790,7 +790,7 @@ void ConsoleLogFrame::OnToggleSource( wxCommandEvent& evt )
|
|||
|
||||
if (!pxAssertDev( ArraySize(ConLogSources) > srcid, "Invalid source log index (out of bounds)" )) return;
|
||||
if (!pxAssertDev( ConLogSources[srcid] != NULL, "Invalid source log index (NULL pointer [separator])" )) return;
|
||||
|
||||
|
||||
if( wxMenuItem* item = GetMenuBar()->FindItem(evt.GetId()) )
|
||||
{
|
||||
pxAssertDev( item->IsCheckable(), "Uncheckable log source menu item? Seems fishy!" );
|
||||
|
@ -926,7 +926,7 @@ void ConsoleLogFrame::DoFlushQueue()
|
|||
// cap at 512k for now...
|
||||
// fixme - 512k runs well on win32 but appears to be very sluggish on linux (but that could
|
||||
// be a result of my using Xming + CoLinux). Might need platform dependent defaults here. --air
|
||||
|
||||
|
||||
static const int BufferSize = 0x80000;
|
||||
if( (insertPoint + m_CurQueuePos) > BufferSize )
|
||||
{
|
||||
|
@ -1040,6 +1040,8 @@ const IConsoleWriter ConsoleWriter_File =
|
|||
ConsoleToFile_DoWrite,
|
||||
ConsoleToFile_Newline,
|
||||
ConsoleToFile_SetTitle,
|
||||
|
||||
0
|
||||
};
|
||||
|
||||
Mutex& Pcsx2App::GetProgramLogLock()
|
||||
|
@ -1111,6 +1113,8 @@ static const IConsoleWriter ConsoleWriter_Window =
|
|||
ConsoleToWindow_DoWrite<ConsoleWriter_Stdout>,
|
||||
ConsoleToWindow_Newline<ConsoleWriter_Stdout>,
|
||||
ConsoleToWindow_SetTitle<ConsoleWriter_Stdout>,
|
||||
|
||||
0
|
||||
};
|
||||
|
||||
static const IConsoleWriter ConsoleWriter_WindowAndFile =
|
||||
|
@ -1122,6 +1126,8 @@ static const IConsoleWriter ConsoleWriter_WindowAndFile =
|
|||
ConsoleToWindow_DoWrite<ConsoleWriter_File>,
|
||||
ConsoleToWindow_Newline<ConsoleWriter_File>,
|
||||
ConsoleToWindow_SetTitle<ConsoleWriter_File>,
|
||||
|
||||
0
|
||||
};
|
||||
|
||||
void Pcsx2App::EnableAllLogging()
|
||||
|
|
|
@ -56,7 +56,7 @@ DefaultCpuUsageProvider::DefaultCpuUsageProvider()
|
|||
|
||||
void DefaultCpuUsageProvider::Reset()
|
||||
{
|
||||
for( int i=0; i<QueueDepth; ++i )
|
||||
for( uint i=0; i<QueueDepth; ++i )
|
||||
m_queue[i].LoadWithCurrentTimes();
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ bool MsgButtons::Allows( wxWindowID id ) const
|
|||
|
||||
// [TODO] : maybe add in an Ignore All?
|
||||
case wxID_IGNORE: return HasIgnore();
|
||||
|
||||
|
||||
case wxID_RESET: return HasReset();
|
||||
case wxID_CLOSE: return HasClose();
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ static wxWindowID ParseThatResult( const wxString& src, const MsgButtons& validT
|
|||
wxID_ANY,
|
||||
};
|
||||
|
||||
for( int i=0; i<ArraySize( retvals ); ++i )
|
||||
for( uint i=0; i<ArraySize( retvals ); ++i )
|
||||
{
|
||||
if( (validTypes.Allows( retvals[i] )) && (src == ResultToString(retvals[i], validTypes)) )
|
||||
return retvals[i];
|
||||
|
|
|
@ -21,8 +21,6 @@ Dialogs::GameDatabaseDialog::GameDatabaseDialog(wxWindow* parent)
|
|||
: BaseConfigurationDialog( parent, AddAppName(_("Game Database - %s")), 580 )
|
||||
{
|
||||
ScopedBusyCursor busy( Cursor_ReallyBusy );
|
||||
|
||||
*this += new Panels::GameDatabasePanel(this);
|
||||
|
||||
AddOkCancel();
|
||||
}
|
||||
|
|
|
@ -155,6 +155,7 @@ void MainEmuFrame::ConnectMenus()
|
|||
ConnectMenu( MenuId_Config_SysSettings, Menu_SysSettings_Click );
|
||||
ConnectMenu( MenuId_Config_McdSettings, Menu_McdSettings_Click );
|
||||
ConnectMenu( MenuId_Config_AppSettings, Menu_WindowSettings_Click );
|
||||
ConnectMenu( MenuId_Config_GameDatabase,Menu_GameDatabase_Click );
|
||||
ConnectMenu( MenuId_Config_BIOS, Menu_SelectPluginsBios_Click );
|
||||
ConnectMenu( MenuId_Config_ResetAll, Menu_ResetAllSettings_Click );
|
||||
|
||||
|
@ -421,7 +422,8 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title)
|
|||
|
||||
m_menuConfig.Append(MenuId_Config_SysSettings, _("Emulation &Settings") );
|
||||
m_menuConfig.Append(MenuId_Config_McdSettings, _("&Memory cards") );
|
||||
m_menuConfig.Append(MenuId_Config_BIOS, _("&Plugin/BIOS Selector...") );
|
||||
m_menuConfig.Append(MenuId_Config_BIOS, _("&Plugin/BIOS Selector") );
|
||||
m_menuConfig.Append(MenuId_Config_GameDatabase, _("Game Database Editor") );
|
||||
m_menuConfig.AppendSeparator();
|
||||
|
||||
m_menuConfig.Append(MenuId_Config_GS, _("&Video (GS)"), m_PluginMenuPacks[PluginId_GS]);
|
||||
|
|
|
@ -162,6 +162,7 @@ protected:
|
|||
|
||||
void Menu_SysSettings_Click(wxCommandEvent &event);
|
||||
void Menu_McdSettings_Click(wxCommandEvent &event);
|
||||
void Menu_GameDatabase_Click(wxCommandEvent &event);
|
||||
void Menu_WindowSettings_Click(wxCommandEvent &event);
|
||||
void Menu_GSSettings_Click(wxCommandEvent &event);
|
||||
void Menu_SelectPluginsBios_Click(wxCommandEvent &event);
|
||||
|
|
|
@ -48,6 +48,11 @@ void MainEmuFrame::Menu_McdSettings_Click(wxCommandEvent &event)
|
|||
AppOpenDialog<McdConfigDialog>( this );
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_GameDatabase_Click(wxCommandEvent &event)
|
||||
{
|
||||
AppOpenDialog<McdConfigDialog>( this );
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_WindowSettings_Click(wxCommandEvent &event)
|
||||
{
|
||||
wxCommandEvent evt( pxEvt_SetSettingsPage );
|
||||
|
|
|
@ -1,189 +1,189 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "App.h"
|
||||
#include "AppGameDatabase.h"
|
||||
#include "ConfigurationPanels.h"
|
||||
|
||||
extern wxString DiscSerial;
|
||||
using namespace pxSizerFlags;
|
||||
|
||||
#define blankLine() { \
|
||||
sizer1+=5; sizer1+=5; sizer1+=Text(L""); sizer1+=5; sizer1+=5; \
|
||||
}
|
||||
|
||||
#define placeTextBox(wxBox, txt) { \
|
||||
sizer1 += Label(_(txt)); \
|
||||
sizer1 += 5; \
|
||||
sizer1 += wxBox | pxCenter; \
|
||||
sizer1 += 5; \
|
||||
sizer1 += 5; \
|
||||
}
|
||||
|
||||
wxTextCtrl* CreateMultiLineTextCtrl( wxWindow* parent, int digits, long flags = 0 )
|
||||
{
|
||||
wxTextCtrl* ctrl = new wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
|
||||
pxFitToDigits(ctrl, digits);
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
|
||||
: BaseApplicableConfigPanel( parent )
|
||||
{
|
||||
IGameDatabase* GameDB = AppHost_GetGameDatabase();
|
||||
pxAssume( GameDB != NULL );
|
||||
|
||||
searchBtn = new wxButton (this, wxID_ANY, _("Search"));
|
||||
|
||||
serialBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
|
||||
nameBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
|
||||
regionBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
|
||||
compatBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
|
||||
commentBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT);
|
||||
patchesBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT);
|
||||
|
||||
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
|
||||
gameFixes[i] = new pxCheckBox(this, EnumToString(i), wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER );
|
||||
|
||||
*this += Heading(_("Game Database Editor")).Bold() | StdExpand();
|
||||
*this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand();
|
||||
|
||||
wxFlexGridSizer& sizer1(*new wxFlexGridSizer(5, StdPadding));
|
||||
sizer1.AddGrowableCol(0);
|
||||
|
||||
blankLine();
|
||||
sizer1 += Label(L"Serial: ");
|
||||
sizer1 += 5;
|
||||
sizer1 += serialBox | pxCenter;
|
||||
sizer1 += 5;
|
||||
sizer1 += searchBtn;
|
||||
|
||||
placeTextBox(nameBox, "Name: ");
|
||||
placeTextBox(regionBox, "Region: ");
|
||||
placeTextBox(compatBox, "Compatibility: ");
|
||||
placeTextBox(commentBox, "Comments: ");
|
||||
placeTextBox(patchesBox, "Patches: ");
|
||||
|
||||
blankLine();
|
||||
|
||||
wxStaticBoxSizer& sizer2 = *new wxStaticBoxSizer(wxVERTICAL, this, _("Gamefixes"));
|
||||
wxFlexGridSizer& sizer3(*new wxFlexGridSizer(3, 0, StdPadding*4));
|
||||
sizer3.AddGrowableCol(0);
|
||||
|
||||
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
|
||||
sizer3 += gameFixes[i];
|
||||
|
||||
sizer2 += sizer3 | StdCenter();
|
||||
|
||||
*this += sizer1 | pxCenter;
|
||||
*this += sizer2 | pxCenter;
|
||||
|
||||
Connect(searchBtn->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(GameDatabasePanel::Search_Click));
|
||||
PopulateFields();
|
||||
}
|
||||
|
||||
void Panels::GameDatabasePanel::PopulateFields( const wxString& id ) {
|
||||
IGameDatabase* GameDB = AppHost_GetGameDatabase();
|
||||
if (!pxAssert(GameDB)) return;
|
||||
|
||||
Game_Data game;
|
||||
if (GameDB->findGame(game, id.IsEmpty() ? SysGetDiscID() : id))
|
||||
{
|
||||
serialBox ->SetLabel(game.getString("Serial"));
|
||||
nameBox ->SetLabel(game.getString("Name"));
|
||||
regionBox ->SetLabel(game.getString("Region"));
|
||||
compatBox ->SetLabel(game.getString("Compat"));
|
||||
commentBox->SetLabel(game.getString("[comments]"));
|
||||
patchesBox->SetLabel(game.getString("[patches]"));
|
||||
|
||||
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
|
||||
{
|
||||
wxString keyName (EnumToString(i)); keyName += L"Hack";
|
||||
if( game.keyExists(keyName) )
|
||||
gameFixes[i]->SetValue(game.getBool(keyName));
|
||||
else
|
||||
gameFixes[i]->SetIndeterminate();
|
||||
}
|
||||
}
|
||||
else {
|
||||
serialBox ->SetLabel(wxEmptyString);
|
||||
nameBox ->SetLabel(wxEmptyString);
|
||||
regionBox ->SetLabel(wxEmptyString);
|
||||
compatBox ->SetLabel(wxEmptyString);
|
||||
commentBox->SetLabel(wxEmptyString);
|
||||
patchesBox->SetLabel(wxEmptyString);
|
||||
for (int i = 0; i < GamefixId_COUNT; i++) {
|
||||
gameFixes[i]->SetValue(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define writeTextBoxToDB(_key, _value) { \
|
||||
if (_value.IsEmpty()) GameDB->deleteKey(wxT(_key)); \
|
||||
else GameDB->writeString(wxT(_key), _value); \
|
||||
}
|
||||
|
||||
// returns True if the database is modified, or FALSE if no changes to save.
|
||||
bool Panels::GameDatabasePanel::WriteFieldsToDB() {
|
||||
IGameDatabase* GameDB = AppHost_GetGameDatabase();
|
||||
if (!GameDB) return false;
|
||||
|
||||
if (serialBox->GetValue().IsEmpty()) return false;
|
||||
|
||||
Game_Data game;
|
||||
GameDB->findGame(game, serialBox->GetValue());
|
||||
|
||||
game.id = serialBox->GetValue();
|
||||
|
||||
game.writeString(L"Serial", serialBox->GetValue());
|
||||
game.writeString(L"Name", nameBox->GetValue());
|
||||
game.writeString(L"Region", regionBox->GetValue());
|
||||
game.writeString(L"Compat", compatBox->GetValue());
|
||||
game.writeString(L"[comments]", commentBox->GetValue());
|
||||
game.writeString(L"[patches]", patchesBox->GetValue());
|
||||
|
||||
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) {
|
||||
wxString keyName (EnumToString(i)); keyName += L"Hack";
|
||||
|
||||
if (gameFixes[i]->IsIndeterminate())
|
||||
game.deleteKey(keyName);
|
||||
else
|
||||
game.writeBool(keyName, gameFixes[i]->GetValue());
|
||||
}
|
||||
GameDB->updateGame(game);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) {
|
||||
IGameDatabase* GameDB = AppHost_GetGameDatabase();
|
||||
if( !GameDB ) return;
|
||||
|
||||
PopulateFields( serialBox->GetValue() );
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
void Panels::GameDatabasePanel::Apply() {
|
||||
AppGameDatabase* GameDB = wxGetApp().GetGameDatabase();
|
||||
if( WriteFieldsToDB() )
|
||||
{
|
||||
Console.WriteLn("Saving changes to Game Database...");
|
||||
GameDB->SaveToFile();
|
||||
}
|
||||
}
|
||||
|
||||
void Panels::GameDatabasePanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
}
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "App.h"
|
||||
#include "AppGameDatabase.h"
|
||||
#include "ConfigurationPanels.h"
|
||||
|
||||
extern wxString DiscSerial;
|
||||
using namespace pxSizerFlags;
|
||||
|
||||
#define blankLine() { \
|
||||
sizer1+=5; sizer1+=5; sizer1+=Text(L""); sizer1+=5; sizer1+=5; \
|
||||
}
|
||||
|
||||
#define placeTextBox(wxBox, txt) { \
|
||||
sizer1 += Label(_(txt)); \
|
||||
sizer1 += 5; \
|
||||
sizer1 += wxBox | pxCenter; \
|
||||
sizer1 += 5; \
|
||||
sizer1 += 5; \
|
||||
}
|
||||
|
||||
wxTextCtrl* CreateMultiLineTextCtrl( wxWindow* parent, int digits, long flags = 0 )
|
||||
{
|
||||
wxTextCtrl* ctrl = new wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
|
||||
pxFitToDigits(ctrl, digits);
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
|
||||
: BaseApplicableConfigPanel( parent )
|
||||
{
|
||||
IGameDatabase* GameDB = AppHost_GetGameDatabase();
|
||||
pxAssume( GameDB != NULL );
|
||||
|
||||
searchBtn = new wxButton (this, wxID_ANY, _("Search"));
|
||||
|
||||
serialBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
|
||||
nameBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
|
||||
regionBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
|
||||
compatBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
|
||||
commentBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT);
|
||||
patchesBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT);
|
||||
|
||||
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
|
||||
gameFixes[i] = new pxCheckBox(this, EnumToString(i), wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER );
|
||||
|
||||
*this += Heading(_("Game Database Editor")).Bold() | StdExpand();
|
||||
//*this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand();
|
||||
|
||||
wxFlexGridSizer& sizer1(*new wxFlexGridSizer(5, StdPadding));
|
||||
sizer1.AddGrowableCol(0);
|
||||
|
||||
blankLine();
|
||||
sizer1 += Label(L"Serial: ");
|
||||
sizer1 += 5;
|
||||
sizer1 += serialBox | pxCenter;
|
||||
sizer1 += 5;
|
||||
sizer1 += searchBtn;
|
||||
|
||||
placeTextBox(nameBox, "Name: ");
|
||||
placeTextBox(regionBox, "Region: ");
|
||||
placeTextBox(compatBox, "Compatibility: ");
|
||||
placeTextBox(commentBox, "Comments: ");
|
||||
placeTextBox(patchesBox, "Patches: ");
|
||||
|
||||
blankLine();
|
||||
|
||||
wxStaticBoxSizer& sizer2 = *new wxStaticBoxSizer(wxVERTICAL, this, _("Gamefixes"));
|
||||
wxFlexGridSizer& sizer3(*new wxFlexGridSizer(3, 0, StdPadding*4));
|
||||
sizer3.AddGrowableCol(0);
|
||||
|
||||
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
|
||||
sizer3 += gameFixes[i];
|
||||
|
||||
sizer2 += sizer3 | StdCenter();
|
||||
|
||||
*this += sizer1 | pxCenter;
|
||||
*this += sizer2 | pxCenter;
|
||||
|
||||
Connect(searchBtn->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(GameDatabasePanel::Search_Click));
|
||||
PopulateFields();
|
||||
}
|
||||
|
||||
void Panels::GameDatabasePanel::PopulateFields( const wxString& id ) {
|
||||
IGameDatabase* GameDB = AppHost_GetGameDatabase();
|
||||
if (!pxAssert(GameDB)) return;
|
||||
|
||||
Game_Data game;
|
||||
if (GameDB->findGame(game, id.IsEmpty() ? SysGetDiscID() : id))
|
||||
{
|
||||
serialBox ->SetLabel(game.getString("Serial"));
|
||||
nameBox ->SetLabel(game.getString("Name"));
|
||||
regionBox ->SetLabel(game.getString("Region"));
|
||||
compatBox ->SetLabel(game.getString("Compat"));
|
||||
commentBox->SetLabel(game.getString("[comments]"));
|
||||
patchesBox->SetLabel(game.getString("[patches]"));
|
||||
|
||||
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
|
||||
{
|
||||
wxString keyName (EnumToString(i)); keyName += L"Hack";
|
||||
if( game.keyExists(keyName) )
|
||||
gameFixes[i]->SetValue(game.getBool(keyName));
|
||||
else
|
||||
gameFixes[i]->SetIndeterminate();
|
||||
}
|
||||
}
|
||||
else {
|
||||
serialBox ->SetLabel(wxEmptyString);
|
||||
nameBox ->SetLabel(wxEmptyString);
|
||||
regionBox ->SetLabel(wxEmptyString);
|
||||
compatBox ->SetLabel(wxEmptyString);
|
||||
commentBox->SetLabel(wxEmptyString);
|
||||
patchesBox->SetLabel(wxEmptyString);
|
||||
for (int i = 0; i < GamefixId_COUNT; i++) {
|
||||
gameFixes[i]->SetValue(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define writeTextBoxToDB(_key, _value) { \
|
||||
if (_value.IsEmpty()) GameDB->deleteKey(wxT(_key)); \
|
||||
else GameDB->writeString(wxT(_key), _value); \
|
||||
}
|
||||
|
||||
// returns True if the database is modified, or FALSE if no changes to save.
|
||||
bool Panels::GameDatabasePanel::WriteFieldsToDB() {
|
||||
IGameDatabase* GameDB = AppHost_GetGameDatabase();
|
||||
if (!GameDB) return false;
|
||||
|
||||
if (serialBox->GetValue().IsEmpty()) return false;
|
||||
|
||||
Game_Data game;
|
||||
GameDB->findGame(game, serialBox->GetValue());
|
||||
|
||||
game.id = serialBox->GetValue();
|
||||
|
||||
game.writeString(L"Serial", serialBox->GetValue());
|
||||
game.writeString(L"Name", nameBox->GetValue());
|
||||
game.writeString(L"Region", regionBox->GetValue());
|
||||
game.writeString(L"Compat", compatBox->GetValue());
|
||||
game.writeString(L"[comments]", commentBox->GetValue());
|
||||
game.writeString(L"[patches]", patchesBox->GetValue());
|
||||
|
||||
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) {
|
||||
wxString keyName (EnumToString(i)); keyName += L"Hack";
|
||||
|
||||
if (gameFixes[i]->IsIndeterminate())
|
||||
game.deleteKey(keyName);
|
||||
else
|
||||
game.writeBool(keyName, gameFixes[i]->GetValue());
|
||||
}
|
||||
GameDB->updateGame(game);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) {
|
||||
IGameDatabase* GameDB = AppHost_GetGameDatabase();
|
||||
if( !GameDB ) return;
|
||||
|
||||
PopulateFields( serialBox->GetValue() );
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
void Panels::GameDatabasePanel::Apply() {
|
||||
AppGameDatabase* GameDB = wxGetApp().GetGameDatabase();
|
||||
if( WriteFieldsToDB() )
|
||||
{
|
||||
Console.WriteLn("Saving changes to Game Database...");
|
||||
GameDB->SaveToFile();
|
||||
}
|
||||
}
|
||||
|
||||
void Panels::GameDatabasePanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -144,10 +144,10 @@ static SysTraceLog * const traceLogList[] =
|
|||
&SysTrace.EE.SPR,
|
||||
&SysTrace.EE.VIF,
|
||||
&SysTrace.EE.GIF,
|
||||
|
||||
|
||||
|
||||
|
||||
// IOP Section
|
||||
|
||||
|
||||
&SysTrace.IOP.Bios,
|
||||
&SysTrace.IOP.Memcards,
|
||||
&SysTrace.IOP.PAD,
|
||||
|
@ -164,7 +164,7 @@ static SysTraceLog * const traceLogList[] =
|
|||
&SysTrace.IOP.CDVD,
|
||||
};
|
||||
|
||||
static const int traceLogCount = ArraySize(traceLogList);
|
||||
static const uint traceLogCount = ArraySize(traceLogList);
|
||||
|
||||
void SysTraceLog_LoadSaveSettings( IniInterface& ini )
|
||||
{
|
||||
|
@ -270,7 +270,7 @@ Panels::BaseCpuLogOptionsPanel* Panels::LogOptionsPanel::GetCpuPanel( const wxSt
|
|||
{
|
||||
if( token == L"EE" ) return m_eeSection;
|
||||
if( token == L"IOP" ) return m_iopSection;
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -316,7 +316,7 @@ void Panels::LogOptionsPanel::Apply()
|
|||
m_iopSection->Apply();
|
||||
|
||||
m_IsDirty = false;
|
||||
|
||||
|
||||
for( uint i = 0; i<traceLogCount; ++i )
|
||||
{
|
||||
if (!traceLogList[i] || !m_checks[i]) continue;
|
||||
|
|
|
@ -59,7 +59,15 @@ namespace Exception
|
|||
class NotEnumerablePlugin : public BadStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, BadStream, wxLt("File is not a PCSX2 plugin") );
|
||||
DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, BadStream );
|
||||
|
||||
wxString FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("File is not a PCSX2 plugin");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -62,21 +62,6 @@ static void SaveStateFile_ReadHeader( IStreamReader& thr )
|
|||
.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
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// gzipReader
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -104,7 +104,7 @@ __fi tDMA_TAG *SPRdmaGetAddr(u32 addr, bool write)
|
|||
// FIXME: Why??? DMA uses physical addresses
|
||||
addr &= 0x1ffffff0;
|
||||
|
||||
if (addr < Ps2MemSize::Base)
|
||||
if (addr < Ps2MemSize::MainRam)
|
||||
{
|
||||
return (tDMA_TAG*)&eeMem->Main[addr];
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ __ri tDMA_TAG *dmaGetAddr(u32 addr, bool write)
|
|||
// FIXME: Why??? DMA uses physical addresses
|
||||
addr &= 0x1ffffff0;
|
||||
|
||||
if (addr < Ps2MemSize::Base)
|
||||
if (addr < Ps2MemSize::MainRam)
|
||||
{
|
||||
return (tDMA_TAG*)&eeMem->Main[addr];
|
||||
}
|
||||
|
|
301
pcsx2/vtlb.cpp
301
pcsx2/vtlb.cpp
|
@ -33,9 +33,10 @@
|
|||
#include "Common.h"
|
||||
#include "vtlb.h"
|
||||
#include "COP0.h"
|
||||
|
||||
#include "R5900Exceptions.h"
|
||||
|
||||
#include "Utilities/MemsetFast.inl"
|
||||
|
||||
using namespace R5900;
|
||||
using namespace vtlb_private;
|
||||
|
||||
|
@ -46,7 +47,7 @@ namespace vtlb_private
|
|||
__aligned(64) MapData vtlbdata;
|
||||
}
|
||||
|
||||
static vtlbHandler vtlbHandlerCount=0;
|
||||
static vtlbHandler vtlbHandlerCount = 0;
|
||||
|
||||
static vtlbHandler DefaultPhyHandler;
|
||||
static vtlbHandler UnmappedVirtHandler0;
|
||||
|
@ -78,9 +79,9 @@ DataType __fastcall vtlb_memRead(u32 addr)
|
|||
|
||||
switch( DataSize )
|
||||
{
|
||||
case 8: return ((vtlbMemR8FP*)vtlbdata.RWFT[0][0][hand])(paddr);
|
||||
case 16: return ((vtlbMemR16FP*)vtlbdata.RWFT[1][0][hand])(paddr);
|
||||
case 32: return ((vtlbMemR32FP*)vtlbdata.RWFT[2][0][hand])(paddr);
|
||||
case 8: return ((vtlbMemR8FP*)vtlbdata.RWFT[0][0][hand])(paddr);
|
||||
case 16: return ((vtlbMemR16FP*)vtlbdata.RWFT[1][0][hand])(paddr);
|
||||
case 32: return ((vtlbMemR32FP*)vtlbdata.RWFT[2][0][hand])(paddr);
|
||||
|
||||
jNO_DEFAULT;
|
||||
}
|
||||
|
@ -147,9 +148,9 @@ void __fastcall vtlb_memWrite(u32 addr, DataType data)
|
|||
|
||||
switch( DataSize )
|
||||
{
|
||||
case 8: return ((vtlbMemW8FP*)vtlbdata.RWFT[0][1][hand])(paddr, (u8)data);
|
||||
case 16: return ((vtlbMemW16FP*)vtlbdata.RWFT[1][1][hand])(paddr, (u16)data);
|
||||
case 32: return ((vtlbMemW32FP*)vtlbdata.RWFT[2][1][hand])(paddr, (u32)data);
|
||||
case 8: return ((vtlbMemW8FP*)vtlbdata.RWFT[0][1][hand])(paddr, (u8)data);
|
||||
case 16: return ((vtlbMemW16FP*)vtlbdata.RWFT[1][1][hand])(paddr, (u16)data);
|
||||
case 32: return ((vtlbMemW32FP*)vtlbdata.RWFT[2][1][hand])(paddr, (u32)data);
|
||||
|
||||
jNO_DEFAULT;
|
||||
}
|
||||
|
@ -255,65 +256,55 @@ _tmpl(void) vtlbUnmappedPWriteLg(u32 addr,const OperandType* data) { vtlb_BusErr
|
|||
|
||||
static mem8_t __fastcall vtlbDefaultPhyRead8(u32 addr)
|
||||
{
|
||||
Console.Error("vtlbDefaultPhyRead8: 0x%08X", addr);
|
||||
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
|
||||
pxFailDev(pxsFmt("(VTLB) Attempted read8 from unmapped physical address @ 0x%08X.", addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static mem16_t __fastcall vtlbDefaultPhyRead16(u32 addr)
|
||||
{
|
||||
Console.Error("vtlbDefaultPhyRead16: 0x%08X", addr);
|
||||
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
|
||||
pxFailDev(pxsFmt("(VTLB) Attempted read16 from unmapped physical address @ 0x%08X.", addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static mem32_t __fastcall vtlbDefaultPhyRead32(u32 addr)
|
||||
{
|
||||
Console.Error("vtlbDefaultPhyRead32: 0x%08X", addr);
|
||||
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
|
||||
pxFailDev(pxsFmt("(VTLB) Attempted read32 from unmapped physical address @ 0x%08X.", addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __fastcall vtlbDefaultPhyRead64(u32 addr, mem64_t* dest)
|
||||
{
|
||||
Console.Error("vtlbDefaultPhyRead64: 0x%08X", addr);
|
||||
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
|
||||
pxFailDev(pxsFmt("(VTLB) Attempted read64 from unmapped physical address @ 0x%08X.", addr));
|
||||
}
|
||||
|
||||
static void __fastcall vtlbDefaultPhyRead128(u32 addr, mem128_t* dest)
|
||||
{
|
||||
Console.Error("vtlbDefaultPhyRead128: 0x%08X", addr);
|
||||
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
|
||||
pxFailDev(pxsFmt("(VTLB) Attempted read128 from unmapped physical address @ 0x%08X.", addr));
|
||||
}
|
||||
|
||||
static void __fastcall vtlbDefaultPhyWrite8(u32 addr, mem8_t data)
|
||||
{
|
||||
Console.Error("vtlbDefaultPhyWrite8: 0x%08X",addr);
|
||||
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
|
||||
pxFailDev(pxsFmt("(VTLB) Attempted write8 to unmapped physical address @ 0x%08X.", addr));
|
||||
}
|
||||
|
||||
static void __fastcall vtlbDefaultPhyWrite16(u32 addr, mem16_t data)
|
||||
{
|
||||
Console.Error("vtlbDefaultPhyWrite16: 0x%08X",addr);
|
||||
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
|
||||
pxFailDev(pxsFmt("(VTLB) Attempted write16 to unmapped physical address @ 0x%08X.", addr));
|
||||
}
|
||||
|
||||
static void __fastcall vtlbDefaultPhyWrite32(u32 addr, mem32_t data)
|
||||
{
|
||||
Console.Error("vtlbDefaultPhyWrite32: 0x%08X",addr);
|
||||
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
|
||||
pxFailDev(pxsFmt("(VTLB) Attempted write32 to unmapped physical address @ 0x%08X.", addr));
|
||||
}
|
||||
|
||||
static void __fastcall vtlbDefaultPhyWrite64(u32 addr,const mem64_t* data)
|
||||
{
|
||||
Console.Error("vtlbDefaultPhyWrite64: 0x%08X",addr);
|
||||
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
|
||||
pxFailDev(pxsFmt("(VTLB) Attempted write64 to unmapped physical address @ 0x%08X.", addr));
|
||||
}
|
||||
|
||||
static void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data)
|
||||
{
|
||||
Console.Error("vtlbDefaultPhyWrite128: 0x%08X",addr);
|
||||
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
|
||||
pxFailDev(pxsFmt("(VTLB) Attempted write128 to unmapped physical address @ 0x%08X.", addr));
|
||||
}
|
||||
#undef _tmpl
|
||||
|
||||
|
@ -333,6 +324,8 @@ __ri void vtlb_ReassignHandler( vtlbHandler rv,
|
|||
vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
|
||||
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128 )
|
||||
{
|
||||
pxAssume(rv < VTLB_HANDLER_ITEMS);
|
||||
|
||||
vtlbdata.RWFT[0][0][rv] = (void*)((r8!=0) ? r8 : vtlbDefaultPhyRead8);
|
||||
vtlbdata.RWFT[1][0][rv] = (void*)((r16!=0) ? r16 : vtlbDefaultPhyRead16);
|
||||
vtlbdata.RWFT[2][0][rv] = (void*)((r32!=0) ? r32 : vtlbDefaultPhyRead32);
|
||||
|
@ -348,7 +341,7 @@ __ri void vtlb_ReassignHandler( vtlbHandler rv,
|
|||
|
||||
vtlbHandler vtlb_NewHandler()
|
||||
{
|
||||
pxAssertDev( vtlbHandlerCount < 127, "VTLB allowed handler count exceeded!" );
|
||||
pxAssertDev( vtlbHandlerCount < VTLB_HANDLER_ITEMS, "VTLB handler count overflow!" );
|
||||
return vtlbHandlerCount++;
|
||||
}
|
||||
|
||||
|
@ -362,7 +355,7 @@ vtlbHandler vtlb_NewHandler()
|
|||
// Returns a handle for the newly created handler See vtlb_MapHandler for use of the return value.
|
||||
//
|
||||
__ri vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
|
||||
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128)
|
||||
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128)
|
||||
{
|
||||
vtlbHandler rv = vtlb_NewHandler();
|
||||
vtlb_ReassignHandler( rv, r8, r16, r32, r64, r128, w8, w16, w32, w64, w128 );
|
||||
|
@ -377,45 +370,47 @@ __ri vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMem
|
|||
// function.
|
||||
//
|
||||
// The memory region start and size parameters must be pagesize aligned.
|
||||
void vtlb_MapHandler(vtlbHandler handler,u32 start,u32 size)
|
||||
void vtlb_MapHandler(vtlbHandler handler, u32 start, u32 size)
|
||||
{
|
||||
verify(0==(start&VTLB_PAGE_MASK));
|
||||
verify(0==(size&VTLB_PAGE_MASK) && size>0);
|
||||
s32 value=handler|0x80000000;
|
||||
|
||||
while(size>0)
|
||||
s32 value = handler | 0x80000000;
|
||||
u32 end = start + (size - VTLB_PAGE_SIZE);
|
||||
pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) );
|
||||
|
||||
while (start <= end)
|
||||
{
|
||||
vtlbdata.pmap[start>>VTLB_PAGE_BITS]=value;
|
||||
|
||||
start+=VTLB_PAGE_SIZE;
|
||||
size-=VTLB_PAGE_SIZE;
|
||||
vtlbdata.pmap[start>>VTLB_PAGE_BITS] = value;
|
||||
start += VTLB_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize)
|
||||
void vtlb_MapBlock(void* base, u32 start, u32 size, u32 blocksize)
|
||||
{
|
||||
s32 baseint=(s32)base;
|
||||
|
||||
verify(0==(start&VTLB_PAGE_MASK));
|
||||
verify(0==(size&VTLB_PAGE_MASK) && size>0);
|
||||
if (blocksize==0)
|
||||
blocksize=size;
|
||||
if (!blocksize)
|
||||
blocksize = size;
|
||||
verify(0==(blocksize&VTLB_PAGE_MASK) && blocksize>0);
|
||||
verify(0==(size%blocksize));
|
||||
|
||||
while(size>0)
|
||||
s32 baseint = (s32)base;
|
||||
u32 end = start + (size - VTLB_PAGE_SIZE);
|
||||
pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) );
|
||||
|
||||
while (start <= end)
|
||||
{
|
||||
u32 blocksz=blocksize;
|
||||
s32 ptr=baseint;
|
||||
u32 loopsz = blocksize;
|
||||
s32 ptr = baseint;
|
||||
|
||||
while(blocksz>0)
|
||||
while (loopsz > 0)
|
||||
{
|
||||
vtlbdata.pmap[start>>VTLB_PAGE_BITS]=ptr;
|
||||
vtlbdata.pmap[start>>VTLB_PAGE_BITS] = ptr;
|
||||
|
||||
start+=VTLB_PAGE_SIZE;
|
||||
ptr+=VTLB_PAGE_SIZE;
|
||||
blocksz-=VTLB_PAGE_SIZE;
|
||||
size-=VTLB_PAGE_SIZE;
|
||||
start += VTLB_PAGE_SIZE;
|
||||
ptr += VTLB_PAGE_SIZE;
|
||||
loopsz -= VTLB_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -426,13 +421,15 @@ void vtlb_Mirror(u32 new_region,u32 start,u32 size)
|
|||
verify(0==(start&VTLB_PAGE_MASK));
|
||||
verify(0==(size&VTLB_PAGE_MASK) && size>0);
|
||||
|
||||
while(size>0)
|
||||
{
|
||||
vtlbdata.pmap[start>>VTLB_PAGE_BITS]=vtlbdata.pmap[new_region>>VTLB_PAGE_BITS];
|
||||
u32 end = start + (size-VTLB_PAGE_SIZE);
|
||||
pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) );
|
||||
|
||||
start+=VTLB_PAGE_SIZE;
|
||||
new_region+=VTLB_PAGE_SIZE;
|
||||
size-=VTLB_PAGE_SIZE;
|
||||
while(start <= end)
|
||||
{
|
||||
vtlbdata.pmap[start>>VTLB_PAGE_BITS] = vtlbdata.pmap[new_region>>VTLB_PAGE_BITS];
|
||||
|
||||
start += VTLB_PAGE_SIZE;
|
||||
new_region += VTLB_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -446,66 +443,70 @@ __fi void* vtlb_GetPhyPtr(u32 paddr)
|
|||
|
||||
//virtual mappings
|
||||
//TODO: Add invalid paddr checks
|
||||
void vtlb_VMap(u32 vaddr,u32 paddr,u32 sz)
|
||||
void vtlb_VMap(u32 vaddr,u32 paddr,u32 size)
|
||||
{
|
||||
verify(0==(vaddr&VTLB_PAGE_MASK));
|
||||
verify(0==(paddr&VTLB_PAGE_MASK));
|
||||
verify(0==(sz&VTLB_PAGE_MASK) && sz>0);
|
||||
verify(0==(size&VTLB_PAGE_MASK) && size>0);
|
||||
|
||||
while(sz>0)
|
||||
while (size > 0)
|
||||
{
|
||||
s32 pme;
|
||||
if (paddr>=VTLB_PMAP_SZ)
|
||||
if (paddr >= VTLB_PMAP_SZ)
|
||||
{
|
||||
pme=UnmappedPhyHandler0;
|
||||
if (paddr&0x80000000)
|
||||
pme=UnmappedPhyHandler1;
|
||||
pme|=0x80000000;
|
||||
pme|=paddr;// top bit is set anyway ...
|
||||
pme = UnmappedPhyHandler0;
|
||||
if (paddr & 0x80000000)
|
||||
pme = UnmappedPhyHandler1;
|
||||
pme |= 0x80000000;
|
||||
pme |= paddr;// top bit is set anyway ...
|
||||
}
|
||||
else
|
||||
{
|
||||
pme=vtlbdata.pmap[paddr>>VTLB_PAGE_BITS];
|
||||
pme = vtlbdata.pmap[paddr>>VTLB_PAGE_BITS];
|
||||
if (pme<0)
|
||||
pme|=paddr;// top bit is set anyway ...
|
||||
pme |= paddr;// top bit is set anyway ...
|
||||
}
|
||||
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=pme-vaddr;
|
||||
vaddr+=VTLB_PAGE_SIZE;
|
||||
paddr+=VTLB_PAGE_SIZE;
|
||||
sz-=VTLB_PAGE_SIZE;
|
||||
|
||||
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS] = pme-vaddr;
|
||||
vaddr += VTLB_PAGE_SIZE;
|
||||
paddr += VTLB_PAGE_SIZE;
|
||||
size -= VTLB_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void vtlb_VMapBuffer(u32 vaddr,void* buffer,u32 sz)
|
||||
void vtlb_VMapBuffer(u32 vaddr,void* buffer,u32 size)
|
||||
{
|
||||
verify(0==(vaddr&VTLB_PAGE_MASK));
|
||||
verify(0==(sz&VTLB_PAGE_MASK) && sz>0);
|
||||
u32 bu8=(u32)buffer;
|
||||
while(sz>0)
|
||||
verify(0==(size&VTLB_PAGE_MASK) && size>0);
|
||||
|
||||
u32 bu8 = (u32)buffer;
|
||||
while (size > 0)
|
||||
{
|
||||
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=bu8-vaddr;
|
||||
vaddr+=VTLB_PAGE_SIZE;
|
||||
bu8+=VTLB_PAGE_SIZE;
|
||||
sz-=VTLB_PAGE_SIZE;
|
||||
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS] = bu8-vaddr;
|
||||
vaddr += VTLB_PAGE_SIZE;
|
||||
bu8 += VTLB_PAGE_SIZE;
|
||||
size -= VTLB_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
void vtlb_VMapUnmap(u32 vaddr,u32 sz)
|
||||
void vtlb_VMapUnmap(u32 vaddr,u32 size)
|
||||
{
|
||||
verify(0==(vaddr&VTLB_PAGE_MASK));
|
||||
verify(0==(sz&VTLB_PAGE_MASK) && sz>0);
|
||||
verify(0==(size&VTLB_PAGE_MASK) && size>0);
|
||||
|
||||
while(sz>0)
|
||||
while (size > 0)
|
||||
{
|
||||
u32 handl=UnmappedVirtHandler0;
|
||||
if (vaddr&0x80000000)
|
||||
u32 handl = UnmappedVirtHandler0;
|
||||
if (vaddr & 0x80000000)
|
||||
{
|
||||
handl=UnmappedVirtHandler1;
|
||||
handl = UnmappedVirtHandler1;
|
||||
}
|
||||
handl|=vaddr; // top bit is set anyway ...
|
||||
handl|=0x80000000;
|
||||
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=handl-vaddr;
|
||||
vaddr+=VTLB_PAGE_SIZE;
|
||||
sz-=VTLB_PAGE_SIZE;
|
||||
|
||||
handl |= vaddr; // top bit is set anyway ...
|
||||
handl |= 0x80000000;
|
||||
|
||||
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS] = handl-vaddr;
|
||||
vaddr += VTLB_PAGE_SIZE;
|
||||
size -= VTLB_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,60 +563,86 @@ void vtlb_Term()
|
|||
}
|
||||
|
||||
// Reserves the vtlb core allocation used by various emulation components!
|
||||
//
|
||||
// [TODO] basemem - request allocating memory at the specified virtual location, which can allow
|
||||
// for easier debugging and/or 3rd party cheat programs. If 0, the operating system
|
||||
// default is used.
|
||||
void vtlb_Core_Alloc()
|
||||
{
|
||||
if( vtlbdata.alloc_base != NULL ) return;
|
||||
|
||||
vtlbdata.alloc_current = 0;
|
||||
|
||||
#ifdef __LINUX__
|
||||
vtlbdata.alloc_base = SysMmapEx( 0x16000000, VTLB_ALLOC_SIZE, 0x80000000, "Vtlb" );
|
||||
#else
|
||||
// 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( pxsFmt(L"PS2 mappable system ram (%u megs)", VTLB_ALLOC_SIZE / _1mb) );
|
||||
#endif
|
||||
if (!vtlbdata.vmap)
|
||||
{
|
||||
vtlbdata.vmap = (s32*)_aligned_malloc( VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap), 16 );
|
||||
if (!vtlbdata.vmap)
|
||||
throw Exception::OutOfMemory( L"VTLB Virtual Address Translation LUT" )
|
||||
.SetDiagMsg(pxsFmt("(%u megs)", VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap) / _1mb)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void vtlb_Core_Shutdown()
|
||||
void vtlb_Core_Free()
|
||||
{
|
||||
if( vtlbdata.alloc_base == NULL ) return;
|
||||
|
||||
#ifdef __LINUX__
|
||||
SafeSysMunmap( vtlbdata.alloc_base, VTLB_ALLOC_SIZE );
|
||||
#else
|
||||
// Make sure and unprotect memory first, since CrtDebug will try to write to it.
|
||||
HostSys::MemProtect( vtlbdata.alloc_base, VTLB_ALLOC_SIZE, Protect_ReadWrite );
|
||||
safe_aligned_free( vtlbdata.alloc_base );
|
||||
#endif
|
||||
|
||||
safe_aligned_free( vtlbdata.vmap );
|
||||
}
|
||||
|
||||
// This function allocates memory block with are compatible with the Vtlb's requirements
|
||||
// for memory locations. The Vtlb requires the topmost bit (Sign bit) of the memory
|
||||
// pointer to be cleared. Some operating systems and/or implementations of malloc do that,
|
||||
// but others do not. So use this instead to allocate the memory correctly for your
|
||||
// platform.
|
||||
//
|
||||
u8* vtlb_malloc( uint size, uint align )
|
||||
static wxString GetHostVmErrorMsg()
|
||||
{
|
||||
vtlbdata.alloc_current += align-1;
|
||||
vtlbdata.alloc_current &= ~(align-1);
|
||||
|
||||
int rv = vtlbdata.alloc_current;
|
||||
vtlbdata.alloc_current += size;
|
||||
|
||||
pxAssertDev( vtlbdata.alloc_current < VTLB_ALLOC_SIZE, "(vtlb_malloc) memory overflow! Please increase the size of VTLB_ALLOC_SIZE!" );
|
||||
return &vtlbdata.alloc_base[rv];
|
||||
return pxE(".Error:HostVmReserve",
|
||||
L"Your system is too low on virtual resources for PCSX2 to run. This can be "
|
||||
L"caused by having a small or disabled swapfile, or by other programs that are "
|
||||
L"hogging resources."
|
||||
);
|
||||
}
|
||||
|
||||
void vtlb_free( void* pmem, uint size )
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VtlbMemoryReserve (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
VtlbMemoryReserve::VtlbMemoryReserve( const wxString& name, size_t size )
|
||||
: m_reserve( name, size )
|
||||
{
|
||||
vtlbdata.alloc_current -= size;
|
||||
|
||||
pxAssertDev( vtlbdata.alloc_current >= 0, "(vtlb_free) mismatched calls to vtlb_malloc and free detected via memory underflow." );
|
||||
|
||||
return;
|
||||
m_reserve.SetPageAccessOnCommit( PageAccess_ReadWrite() );
|
||||
}
|
||||
|
||||
void VtlbMemoryReserve::SetBaseAddr( uptr newaddr )
|
||||
{
|
||||
m_reserve.SetBaseAddr( newaddr );
|
||||
}
|
||||
|
||||
void VtlbMemoryReserve::Reserve( sptr hostptr )
|
||||
{
|
||||
if (!m_reserve.ReserveAt( hostptr ))
|
||||
{
|
||||
throw Exception::OutOfMemory( m_reserve.GetName() )
|
||||
.SetDiagMsg(L"Vtlb memory could not be reserved.")
|
||||
.SetUserMsg(GetHostVmErrorMsg());
|
||||
}
|
||||
}
|
||||
|
||||
void VtlbMemoryReserve::Commit()
|
||||
{
|
||||
if (IsCommitted()) return;
|
||||
if (!m_reserve.Commit())
|
||||
{
|
||||
throw Exception::OutOfMemory( m_reserve.GetName() )
|
||||
.SetDiagMsg(L"Vtlb memory could not be committed.")
|
||||
.SetUserMsg(GetHostVmErrorMsg());
|
||||
}
|
||||
}
|
||||
|
||||
void VtlbMemoryReserve::Reset()
|
||||
{
|
||||
Commit();
|
||||
memzero_sse_a(m_reserve.GetPtr(), m_reserve.GetCommittedBytes());
|
||||
}
|
||||
|
||||
void VtlbMemoryReserve::Decommit()
|
||||
{
|
||||
m_reserve.Reset();
|
||||
}
|
||||
|
||||
void VtlbMemoryReserve::Release()
|
||||
{
|
||||
m_reserve.Release();
|
||||
}
|
||||
|
||||
bool VtlbMemoryReserve::IsCommitted() const
|
||||
{
|
||||
return !!m_reserve.GetCommittedPageCount();
|
||||
}
|
125
pcsx2/vtlb.h
125
pcsx2/vtlb.h
|
@ -17,6 +17,10 @@
|
|||
|
||||
#include "MemoryTypes.h"
|
||||
|
||||
#include "Utilities/PageFaultSource.h"
|
||||
|
||||
static const uptr VTLB_AllocUpperBounds = _1gb * 2;
|
||||
|
||||
// Specialized function pointers for each read type
|
||||
typedef mem8_t __fastcall vtlbMemR8FP(u32 addr);
|
||||
typedef mem16_t __fastcall vtlbMemR16FP(u32 addr);
|
||||
|
@ -34,12 +38,10 @@ typedef void __fastcall vtlbMemW128FP(u32 addr,const mem128_t* data);
|
|||
typedef u32 vtlbHandler;
|
||||
|
||||
extern void vtlb_Core_Alloc();
|
||||
extern void vtlb_Core_Shutdown();
|
||||
extern void vtlb_Core_Free();
|
||||
extern void vtlb_Init();
|
||||
extern void vtlb_Reset();
|
||||
extern void vtlb_Term();
|
||||
extern u8* vtlb_malloc( uint size, uint align );
|
||||
extern void vtlb_free( void* pmem, uint size );
|
||||
|
||||
|
||||
extern vtlbHandler vtlb_NewHandler();
|
||||
|
@ -85,32 +87,121 @@ extern void vtlb_DynGenWrite_Const( u32 bits, u32 addr_const );
|
|||
extern void vtlb_DynGenRead64_Const( u32 bits, u32 addr_const );
|
||||
extern void vtlb_DynGenRead32_Const( u32 bits, bool sign, u32 addr_const );
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VtlbMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class VtlbMemoryReserve
|
||||
{
|
||||
protected:
|
||||
VirtualMemoryReserve m_reserve;
|
||||
|
||||
public:
|
||||
VtlbMemoryReserve( const wxString& name, size_t size );
|
||||
virtual ~VtlbMemoryReserve() throw()
|
||||
{
|
||||
m_reserve.Release();
|
||||
}
|
||||
|
||||
virtual void Reserve( sptr hostptr );
|
||||
virtual void Release();
|
||||
|
||||
virtual void Commit();
|
||||
virtual void Reset();
|
||||
virtual void Decommit();
|
||||
virtual void SetBaseAddr( uptr newaddr );
|
||||
|
||||
bool IsCommitted() const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// eeMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class eeMemoryReserve : public VtlbMemoryReserve
|
||||
{
|
||||
typedef VtlbMemoryReserve _parent;
|
||||
|
||||
public:
|
||||
eeMemoryReserve();
|
||||
virtual ~eeMemoryReserve() throw()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
void Reserve();
|
||||
void Commit();
|
||||
void Decommit();
|
||||
void Reset();
|
||||
void Release();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// iopMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class iopMemoryReserve : public VtlbMemoryReserve
|
||||
{
|
||||
typedef VtlbMemoryReserve _parent;
|
||||
|
||||
public:
|
||||
iopMemoryReserve();
|
||||
virtual ~iopMemoryReserve() throw()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
void Reserve();
|
||||
void Commit();
|
||||
void Decommit();
|
||||
void Release();
|
||||
void Reset();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// vuMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class vuMemoryReserve : public VtlbMemoryReserve
|
||||
{
|
||||
typedef VtlbMemoryReserve _parent;
|
||||
|
||||
public:
|
||||
vuMemoryReserve();
|
||||
virtual ~vuMemoryReserve() throw()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
virtual void Reserve();
|
||||
virtual void Release();
|
||||
|
||||
void Reset();
|
||||
};
|
||||
|
||||
namespace vtlb_private
|
||||
{
|
||||
// Allocate enough memory for both EE and IOP memory space (IOP is roughly 2.5mb,
|
||||
// so we alloc 4mb for now -- a little more than is needed).
|
||||
static const uint VTLB_ALLOC_SIZE = sizeof(*eeMem) + (_1mb*4);
|
||||
|
||||
static const uint VTLB_PAGE_BITS = 12;
|
||||
static const uint VTLB_PAGE_MASK = 4095;
|
||||
static const uint VTLB_PAGE_SIZE = 4096;
|
||||
|
||||
static const uint VTLB_PMAP_ITEMS = 0x20000000 / VTLB_PAGE_SIZE;
|
||||
static const uint VTLB_PMAP_SZ = 0x20000000;
|
||||
static const uint VTLB_VMAP_ITEMS = 0x100000000ULL / VTLB_PAGE_SIZE;
|
||||
static const uint VTLB_PMAP_SZ = _1mb * 512;
|
||||
static const uint VTLB_PMAP_ITEMS = VTLB_PMAP_SZ / VTLB_PAGE_SIZE;
|
||||
static const uint VTLB_VMAP_ITEMS = _4gb / VTLB_PAGE_SIZE;
|
||||
|
||||
static const uint VTLB_HANDLER_ITEMS = 128;
|
||||
|
||||
struct MapData
|
||||
{
|
||||
u8* alloc_base; //base of the memory array
|
||||
int alloc_current; //current base
|
||||
|
||||
s32 pmap[VTLB_PMAP_ITEMS]; //512KB
|
||||
s32 vmap[VTLB_VMAP_ITEMS]; //4MB
|
||||
|
||||
// first indexer -- 8/16/32/64/128 bit tables [values 0-4]
|
||||
// second indexer -- read/write [0 or 1]
|
||||
// third indexer -- 128 possible handlers!
|
||||
void* RWFT[5][2][128];
|
||||
void* RWFT[5][2][VTLB_HANDLER_ITEMS];
|
||||
|
||||
s32 pmap[VTLB_PMAP_ITEMS]; //512KB
|
||||
|
||||
s32* vmap; //4MB (allocated by vtlb_init)
|
||||
|
||||
MapData()
|
||||
{
|
||||
vmap = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
extern __aligned(64) MapData vtlbdata;
|
||||
|
|
|
@ -119,40 +119,47 @@ static bool _registeredName( const wxString& name )
|
|||
return false;
|
||||
}
|
||||
|
||||
void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz)
|
||||
void ProfilerRegisterSource(const wxString& Name, const void* buff, u32 sz)
|
||||
{
|
||||
if( ProfRunning )
|
||||
EnterCriticalSection( &ProfModulesLock );
|
||||
|
||||
wxString strName( fromUTF8(Name) );
|
||||
if( !_registeredName( strName ) )
|
||||
ProfModules.push_back( Module( strName, buff, sz ) );
|
||||
if( !_registeredName( Name ) )
|
||||
ProfModules.push_back( Module( Name, buff, sz ) );
|
||||
|
||||
if( ProfRunning )
|
||||
LeaveCriticalSection( &ProfModulesLock );
|
||||
}
|
||||
|
||||
void ProfilerRegisterSource(const wxString& Name, const void* function)
|
||||
{
|
||||
if( ProfRunning )
|
||||
EnterCriticalSection( &ProfModulesLock );
|
||||
|
||||
if( !_registeredName( Name ) )
|
||||
ProfModules.push_back( Module(Name,function) );
|
||||
|
||||
if( ProfRunning )
|
||||
LeaveCriticalSection( &ProfModulesLock );
|
||||
}
|
||||
|
||||
void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz)
|
||||
{
|
||||
ProfilerRegisterSource( fromUTF8(Name), buff, sz );
|
||||
}
|
||||
|
||||
void ProfilerRegisterSource(const char* Name, const void* function)
|
||||
{
|
||||
if( ProfRunning )
|
||||
EnterCriticalSection( &ProfModulesLock );
|
||||
|
||||
wxString strName( fromUTF8(Name) );
|
||||
if( !_registeredName( strName ) )
|
||||
ProfModules.push_back( Module(strName,function) );
|
||||
|
||||
if( ProfRunning )
|
||||
LeaveCriticalSection( &ProfModulesLock );
|
||||
ProfilerRegisterSource( fromUTF8(Name), function );
|
||||
}
|
||||
|
||||
void ProfilerTerminateSource( const char* Name )
|
||||
void ProfilerTerminateSource( const wxString& Name )
|
||||
{
|
||||
wxString strName( fromUTF8(Name) );
|
||||
for( vector<Module>::const_iterator
|
||||
iter = ProfModules.begin(),
|
||||
end = ProfModules.end(); iter<end; ++iter )
|
||||
{
|
||||
if( iter->name.compare( strName ) == 0 )
|
||||
if( iter->name.compare( Name ) == 0 )
|
||||
{
|
||||
ProfModules.erase( iter );
|
||||
break;
|
||||
|
@ -160,6 +167,11 @@ void ProfilerTerminateSource( const char* Name )
|
|||
}
|
||||
}
|
||||
|
||||
void ProfilerTerminateSource( const char* Name )
|
||||
{
|
||||
ProfilerTerminateSource( fromUTF8(Name) );
|
||||
}
|
||||
|
||||
static bool DispatchKnownModules( uint Eip )
|
||||
{
|
||||
bool retval = false;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -46,7 +46,7 @@ void StreamException_ThrowLastError( const wxString& streamname, HANDLE result )
|
|||
|
||||
default:
|
||||
{
|
||||
throw Exception::Stream( streamname ).SetDiagMsg(wxsFormat( L"General Win32 File/stream error [GetLastError: %d]", error ));
|
||||
throw Exception::BadStream( streamname ).SetDiagMsg(pxsFmt( L"General Win32 File/stream error [GetLastError: %d]", error ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ bool StreamException_LogLastError( const wxString& streamname, const wxChar* act
|
|||
{
|
||||
StreamException_ThrowLastError( streamname, result );
|
||||
}
|
||||
catch( Exception::Stream& ex )
|
||||
catch( Exception::BadStream& ex )
|
||||
{
|
||||
Console.WriteLn( Color_Yellow, L"%s: %s", action, ex.FormatDiagnosticMessage().c_str() );
|
||||
return true;
|
||||
|
|
|
@ -18,18 +18,4 @@
|
|||
#include <winnt.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "System/PageFaultSource.h"
|
||||
|
||||
int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
|
||||
{
|
||||
if( eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION )
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
Source_PageFault.Dispatch( PageFaultInfo( (uptr)eps->ExceptionRecord->ExceptionInformation[1] ) );
|
||||
return Source_PageFault.WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
void InstallSignalHandler()
|
||||
{
|
||||
// NOP on Win32 systems -- we use __try{} __except{} instead.
|
||||
}
|
||||
#include "Utilities/PageFaultSource.h"
|
||||
|
|
|
@ -1083,7 +1083,7 @@ BOOL CALLBACK BrowserProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
|||
case IDC_SKIPMPEG:
|
||||
{
|
||||
u8 *p = eeMem->Main;
|
||||
u8 *d = p + Ps2MemSize::Base;
|
||||
u8 *d = p + Ps2MemSize::MainRam;
|
||||
d -= 16;
|
||||
u32 *u;
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ bool FirstSearch;
|
|||
|
||||
bool FirstShow;
|
||||
|
||||
char olds[Ps2MemSize::Base];
|
||||
char olds[Ps2MemSize::MainRam];
|
||||
|
||||
char tn[100];
|
||||
char to[100];
|
||||
|
|
|
@ -81,9 +81,6 @@ public:
|
|||
__fi int Index (u32 startpc) const
|
||||
{
|
||||
int idx = LastIndex(startpc);
|
||||
// fixme: I changed the parenthesis to be unambiguous, but this needs to be checked to see if ((x or y or z) and w)
|
||||
// is correct, or ((x or y) or (z and w)), or some other variation. --arcum42
|
||||
// Mixing &&'s and ||'s is not actually ambiguous; &&'s take precedence. Reverted to old behavior -- ChickenLiver.
|
||||
if ((idx == -1) || (startpc < blocks[idx].startpc) ||
|
||||
((blocks[idx].size) && (startpc >= blocks[idx].startpc + blocks[idx].size * 4)))
|
||||
return -1;
|
||||
|
@ -139,9 +136,10 @@ public:
|
|||
static void recLUT_SetPage(uptr reclut[0x10000], uptr hwlut[0x10000],
|
||||
BASEBLOCK *mapbase, uint pagebase, uint pageidx, uint mappage)
|
||||
{
|
||||
// this value is in 64k pages!
|
||||
uint page = pagebase + pageidx;
|
||||
|
||||
jASSUME( page < 0x10000 );
|
||||
pxAssume( page < 0x10000 );
|
||||
reclut[page] = (uptr)&mapbase[(mappage - page) << 14];
|
||||
if (hwlut)
|
||||
hwlut[page] = 0u - (pagebase << 16);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "iR3000A.h"
|
||||
#include "BaseblockEx.h"
|
||||
#include "System/RecTypes.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
@ -32,7 +33,6 @@
|
|||
#include "IopCommon.h"
|
||||
#include "iCore.h"
|
||||
|
||||
#include "SamplProf.h"
|
||||
#include "NakedAsm.h"
|
||||
#include "AppConfig.h"
|
||||
|
||||
|
@ -50,13 +50,8 @@ uptr psxhwLUT[0x10000];
|
|||
|
||||
#define HWADDR(mem) (psxhwLUT[mem >> 16] + (mem))
|
||||
|
||||
#define MAPBASE 0x48000000
|
||||
#define RECMEM_SIZE (8*1024*1024)
|
||||
static RecompiledCodeReserve* recMem = NULL;
|
||||
|
||||
// R3000A statics
|
||||
int psxreclog = 0;
|
||||
|
||||
static u8 *recMem = NULL; // the recompiled blocks will be here
|
||||
static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here
|
||||
static BASEBLOCK *recROM = NULL; // and here
|
||||
static BASEBLOCK *recROM1 = NULL; // also here
|
||||
|
@ -130,7 +125,7 @@ static void recEventTest()
|
|||
// stackframe setup code in this function)
|
||||
static void __fastcall StackFrameCheckFailed( int espORebp, int regval )
|
||||
{
|
||||
pxFailDev( wxsFormat( L"(R3000A Recompiler Stackframe) Sanity check failed on %s\n\tCurrent=%d; Saved=%d",
|
||||
pxFailDev( pxsFmt( L"(R3000A Recompiler Stackframe) Sanity check failed on %s\n\tCurrent=%d; Saved=%d",
|
||||
(espORebp==0) ? L"ESP" : L"EBP", regval, (espORebp==0) ? s_store_esp : s_store_ebp )
|
||||
);
|
||||
|
||||
|
@ -346,7 +341,7 @@ static DynGenFunc* _DynGen_EnterRecompiledCode()
|
|||
static void _DynGen_Dispatchers()
|
||||
{
|
||||
// In case init gets called multiple times:
|
||||
HostSys::MemProtectStatic( iopRecDispatchers, Protect_ReadWrite, false );
|
||||
HostSys::MemProtectStatic( iopRecDispatchers, PageAccess_ReadWrite() );
|
||||
|
||||
// clear the buffer to 0xcc (easier debugging).
|
||||
memset_8<0xcc,__pagesize>( iopRecDispatchers );
|
||||
|
@ -363,7 +358,7 @@ static void _DynGen_Dispatchers()
|
|||
iopJITCompileInBlock = _DynGen_JITCompileInBlock();
|
||||
iopEnterRecompiledCode = _DynGen_EnterRecompiledCode();
|
||||
|
||||
HostSys::MemProtectStatic( iopRecDispatchers, Protect_ReadOnly, true );
|
||||
HostSys::MemProtectStatic( iopRecDispatchers, PageAccess_ExecOnly() );
|
||||
|
||||
recBlocks.SetJITCompile( iopJITCompile );
|
||||
}
|
||||
|
@ -754,23 +749,38 @@ void psxRecompileCodeConst3(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode,
|
|||
noconstcode(0);
|
||||
}
|
||||
|
||||
static uptr m_ConfiguredCacheReserve = 32;
|
||||
static u8* m_recBlockAlloc = NULL;
|
||||
|
||||
static const uint m_recBlockAllocSize =
|
||||
(((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK));
|
||||
|
||||
static void recReserveCache()
|
||||
{
|
||||
if (!recMem) recMem = new RecompiledCodeReserve(L"R3000A Recompiler Cache", _1mb * 2);
|
||||
recMem->SetProfilerName("IOPrec");
|
||||
|
||||
while (!recMem->IsOk())
|
||||
{
|
||||
if (recMem->Reserve( m_ConfiguredCacheReserve * _1mb, HostMemoryMap::IOPrec ) != NULL) break;
|
||||
|
||||
// If it failed, then try again (if possible):
|
||||
if (m_ConfiguredCacheReserve < 4) break;
|
||||
m_ConfiguredCacheReserve /= 2;
|
||||
}
|
||||
|
||||
recMem->ThrowIfNotOk();
|
||||
}
|
||||
|
||||
static void recReserve()
|
||||
{
|
||||
// IOP has no hardware requirements!
|
||||
|
||||
recReserveCache();
|
||||
}
|
||||
|
||||
static void recAlloc()
|
||||
{
|
||||
// Note: the VUrec depends on being able to grab an allocation below the 0x10000000 line,
|
||||
// so we give the EErec an address above that to try first as it's basemem address, hence
|
||||
// the 0x28000000 pick (0x20000000 is picked by the EE)
|
||||
|
||||
if( recMem == NULL )
|
||||
recMem = (u8*)SysMmapEx( 0x28000000, RECMEM_SIZE, 0, "recAlloc(R3000a)" );
|
||||
|
||||
if( recMem == NULL )
|
||||
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
|
||||
// always 4 bytes long).
|
||||
|
@ -795,24 +805,22 @@ static void recAlloc()
|
|||
if( s_pInstCache == NULL )
|
||||
throw Exception::OutOfMemory( L"R3000 InstCache." );
|
||||
|
||||
ProfilerRegisterSource( "IOP Rec", recMem, RECMEM_SIZE );
|
||||
_DynGen_Dispatchers();
|
||||
}
|
||||
|
||||
void recResetIOP()
|
||||
{
|
||||
// calling recResetIOP without first calling recInit is bad mojo.
|
||||
pxAssert( recMem != NULL );
|
||||
pxAssert( m_recBlockAlloc != NULL );
|
||||
|
||||
DevCon.WriteLn( "iR3000A Recompiler reset." );
|
||||
|
||||
memset_8<0xcc,RECMEM_SIZE>( recMem ); // 0xcc is INT3
|
||||
recAlloc();
|
||||
recMem->Reset();
|
||||
|
||||
iopClearRecLUT((BASEBLOCK*)m_recBlockAlloc,
|
||||
(((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4)));
|
||||
|
||||
for (int i = 0; i < 0x10000; i++)
|
||||
recLUT_SetPage(psxRecLUT, 0, 0, 0, i, 0);
|
||||
|
||||
// IOP knows 64k pages, hence for the 0x10000's
|
||||
|
||||
// The bottom 2 bits of PC are always zero, so we <<14 to "compress"
|
||||
|
@ -820,6 +828,7 @@ void recResetIOP()
|
|||
|
||||
// We're only mapping 20 pages here in 4 places.
|
||||
// 0x80 comes from : (Ps2MemSize::IopRam / 0x10000) * 4
|
||||
|
||||
for (int i=0; i<0x80; i++)
|
||||
{
|
||||
recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0x0000, i, i & 0x1f);
|
||||
|
@ -847,15 +856,14 @@ void recResetIOP()
|
|||
recBlocks.Reset();
|
||||
g_psxMaxRecMem = 0;
|
||||
|
||||
recPtr = recMem;
|
||||
recPtr = *recMem;
|
||||
psxbranch = 0;
|
||||
}
|
||||
|
||||
static void recShutdown()
|
||||
{
|
||||
ProfilerTerminateSource( "IOPRec" );
|
||||
safe_delete( recMem );
|
||||
|
||||
SafeSysMunmap(recMem, RECMEM_SIZE);
|
||||
safe_aligned_free( m_recBlockAlloc );
|
||||
|
||||
safe_free( s_pInstCache );
|
||||
|
@ -1202,8 +1210,9 @@ static void __fastcall iopRecRecompile( const u32 startpc )
|
|||
pxAssert( startpc );
|
||||
|
||||
// if recPtr reached the mem limit reset whole mem
|
||||
if (((uptr)recPtr - (uptr)recMem) >= (RECMEM_SIZE - 0x10000))
|
||||
if (recPtr >= (recMem->GetPtrEnd() - _64kb)) {
|
||||
recResetIOP();
|
||||
}
|
||||
|
||||
x86SetPtr( recPtr );
|
||||
x86Align(16);
|
||||
|
@ -1390,12 +1399,12 @@ StartRecomp:
|
|||
}
|
||||
}
|
||||
|
||||
pxAssert( x86Ptr < recMem+RECMEM_SIZE );
|
||||
pxAssert( xGetPtr() < recMem->GetPtrEnd() );
|
||||
|
||||
pxAssert(x86Ptr - recPtr < 0x10000);
|
||||
s_pCurBlockEx->x86size = x86Ptr - recPtr;
|
||||
pxAssert(xGetPtr() - recPtr < _64kb);
|
||||
s_pCurBlockEx->x86size = xGetPtr() - recPtr;
|
||||
|
||||
recPtr = x86Ptr;
|
||||
recPtr = xGetPtr();
|
||||
|
||||
pxAssert( (g_psxHasConstReg&g_psxFlushedConstReg) == g_psxHasConstReg );
|
||||
|
||||
|
@ -1403,12 +1412,25 @@ StartRecomp:
|
|||
s_pCurBlockEx = NULL;
|
||||
}
|
||||
|
||||
static void recSetCacheReserve( uint reserveInMegs )
|
||||
{
|
||||
m_ConfiguredCacheReserve = reserveInMegs;
|
||||
}
|
||||
|
||||
static uint recGetCacheReserve()
|
||||
{
|
||||
return m_ConfiguredCacheReserve;
|
||||
}
|
||||
|
||||
R3000Acpu psxRec = {
|
||||
recAlloc,
|
||||
recReserve,
|
||||
recResetIOP,
|
||||
recExecute,
|
||||
recExecuteBlock,
|
||||
recClearIOP,
|
||||
recShutdown
|
||||
recShutdown,
|
||||
|
||||
recGetCacheReserve,
|
||||
recSetCacheReserve
|
||||
};
|
||||
|
||||
|
|
|
@ -21,15 +21,14 @@
|
|||
#include "R5900Exceptions.h"
|
||||
#include "R5900OpcodeTables.h"
|
||||
#include "iR5900.h"
|
||||
|
||||
#include "BaseblockEx.h"
|
||||
#include "System/RecTypes.h"
|
||||
|
||||
#include "vtlb.h"
|
||||
#include "SamplProf.h"
|
||||
#include "Dump.h"
|
||||
|
||||
#include "System/SysThreads.h"
|
||||
#include "GS.h"
|
||||
|
||||
#include "CDVD/CDVD.h"
|
||||
#include "Elfheader.h"
|
||||
|
||||
|
@ -37,14 +36,18 @@
|
|||
# include <csetjmp>
|
||||
#endif
|
||||
|
||||
|
||||
#include "Utilities/MemsetFast.inl"
|
||||
|
||||
|
||||
using namespace x86Emitter;
|
||||
using namespace R5900;
|
||||
|
||||
#define PC_GETBLOCK(x) PC_GETBLOCK_(x, recLUT)
|
||||
|
||||
u32 maxrecmem = 0;
|
||||
static __aligned16 uptr recLUT[0x10000];
|
||||
static __aligned16 uptr hwLUT[0x10000];
|
||||
static __aligned16 uptr recLUT[_64kb];
|
||||
static __aligned16 uptr hwLUT[_64kb];
|
||||
|
||||
#define HWADDR(mem) (hwLUT[mem >> 16] + (mem))
|
||||
|
||||
|
@ -57,18 +60,41 @@ __aligned16 GPR_reg64 g_cpuConstRegs[32] = {0};
|
|||
u32 g_cpuHasConstReg = 0, g_cpuFlushedConstReg = 0;
|
||||
bool g_cpuFlushedPC, g_cpuFlushedCode, g_recompilingDelaySlot, g_maySignalException;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// R5900LutReserve_RAM
|
||||
// --------------------------------------------------------------------------------------
|
||||
class R5900LutReserve_RAM : public SpatialArrayReserve
|
||||
{
|
||||
typedef SpatialArrayReserve _parent;
|
||||
|
||||
public:
|
||||
R5900LutReserve_RAM( const wxString& name )
|
||||
: _parent( name )
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void OnCommittedBlock( void* block );
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Static Private Variables - R5900 Dynarec
|
||||
|
||||
#define X86
|
||||
static const int RECCONSTBUF_SIZE = 16384 * 2; // 64 bit consts in 32 bit units
|
||||
|
||||
static u8 *recMem = NULL; // the recompiled blocks will be here
|
||||
static RecompiledCodeReserve* recMem = NULL;
|
||||
static SpatialArrayReserve* recRAMCopy = NULL;
|
||||
static R5900LutReserve_RAM* recLutReserve_RAM = NULL;
|
||||
|
||||
static uptr m_ConfiguredCacheReserve = 64;
|
||||
|
||||
static u32* recConstBuf = NULL; // 64-bit pseudo-immediates
|
||||
static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here
|
||||
static BASEBLOCK *recROM = NULL; // and here
|
||||
static BASEBLOCK *recROM1 = NULL; // also here
|
||||
static u32 *recRAMCopy = NULL;
|
||||
|
||||
static BaseBlocks recBlocks;
|
||||
static u8* recPtr = NULL;
|
||||
static u32 *recConstBufPtr = NULL;
|
||||
|
@ -506,7 +532,7 @@ static DynGenFunc* _DynGen_EnterRecompiledCode()
|
|||
static void _DynGen_Dispatchers()
|
||||
{
|
||||
// In case init gets called multiple times:
|
||||
HostSys::MemProtectStatic( eeRecDispatchers, Protect_ReadWrite, false );
|
||||
HostSys::MemProtectStatic( eeRecDispatchers, PageAccess_ReadWrite() );
|
||||
|
||||
// clear the buffer to 0xcc (easier debugging).
|
||||
memset_8<0xcc,__pagesize>( eeRecDispatchers );
|
||||
|
@ -523,7 +549,7 @@ static void _DynGen_Dispatchers()
|
|||
JITCompileInBlock = _DynGen_JITCompileInBlock();
|
||||
EnterRecompiledCode = _DynGen_EnterRecompiledCode();
|
||||
|
||||
HostSys::MemProtectStatic( eeRecDispatchers, Protect_ReadOnly, true );
|
||||
HostSys::MemProtectStatic( eeRecDispatchers, PageAccess_ExecOnly() );
|
||||
|
||||
recBlocks.SetJITCompile( JITCompile );
|
||||
}
|
||||
|
@ -531,24 +557,45 @@ static void _DynGen_Dispatchers()
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
static const int REC_CACHEMEM = 0x01000000;
|
||||
static void __fastcall dyna_block_discard(u32 start,u32 sz);
|
||||
|
||||
// memory allocation handle for the entire BASEBLOCK and stack allocations.
|
||||
static u8* m_recBlockAlloc = NULL;
|
||||
static __ri void ClearRecLUT(BASEBLOCK* base, int memsize)
|
||||
{
|
||||
for (int i = 0; i < memsize/4; i++)
|
||||
base[i].SetFnptr((uptr)JITCompile);
|
||||
}
|
||||
|
||||
static const uint m_recBlockAllocSize =
|
||||
(((Ps2MemSize::Base + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK))
|
||||
+ RECCONSTBUF_SIZE * sizeof(u32) + Ps2MemSize::Base;
|
||||
void R5900LutReserve_RAM::OnCommittedBlock( void* block )
|
||||
{
|
||||
_parent::OnCommittedBlock(block);
|
||||
ClearRecLUT((BASEBLOCK*)block, __pagesize * m_blocksize);
|
||||
}
|
||||
|
||||
static void recThrowHardwareDeficiency( const wxChar* 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 ));
|
||||
.SetDiagMsg(pxsFmt( L"R5900-32 recompiler init failed: %s is not available.", extFail))
|
||||
.SetUserMsg(pxsFmt(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail ));
|
||||
}
|
||||
|
||||
static void recAlloc()
|
||||
static void recReserveCache()
|
||||
{
|
||||
if (!recMem) recMem = new RecompiledCodeReserve(L"R5900-32 Recompiler Cache", _1mb * 4);
|
||||
recMem->SetProfilerName("EErec");
|
||||
|
||||
while (!recMem->IsOk())
|
||||
{
|
||||
if (recMem->Reserve( m_ConfiguredCacheReserve * _1mb, HostMemoryMap::EErec ) != NULL) break;
|
||||
|
||||
// If it failed, then try again (if possible):
|
||||
if (m_ConfiguredCacheReserve < 16) break;
|
||||
m_ConfiguredCacheReserve /= 2;
|
||||
}
|
||||
|
||||
recMem->ThrowIfNotOk();
|
||||
}
|
||||
|
||||
static void recReserve()
|
||||
{
|
||||
// Hardware Requirements Check...
|
||||
|
||||
|
@ -561,99 +608,31 @@ static void recAlloc()
|
|||
if ( !x86caps.hasStreamingSIMD2Extensions )
|
||||
recThrowHardwareDeficiency( L"SSE2" );
|
||||
|
||||
if( recMem == NULL )
|
||||
{
|
||||
// It's handy to have a constant base address for the EE recompiler buffer, since it
|
||||
// allows me to key in the address directly in the debugger, and also recognize EE
|
||||
// recompiled code from user-provisioned stack traces. But besides those, the recompiler
|
||||
// has no actual restrictions on where it's compiled code buffer is located.
|
||||
|
||||
// Note: the SuperVU recompiler depends on being able to grab an allocation below the
|
||||
// 0x10000000 line, so we give the EErec an address above that to try first as it's
|
||||
// basemem address, hence the 0x20000000 pick.
|
||||
|
||||
const uint cachememsize = REC_CACHEMEM+0x1000;
|
||||
recMem = (u8*)SysMmapEx( 0x20000000, cachememsize, 0, "recAlloc(R5900)" );
|
||||
}
|
||||
|
||||
if( recMem == NULL )
|
||||
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
|
||||
// always 4 bytes long).
|
||||
|
||||
if( m_recBlockAlloc == NULL )
|
||||
m_recBlockAlloc = (u8*) _aligned_malloc( m_recBlockAllocSize, 4096 );
|
||||
|
||||
if( m_recBlockAlloc == NULL )
|
||||
throw Exception::OutOfMemory( L"R5900-32 BASEBLOCK tables" );
|
||||
|
||||
u8* curpos = m_recBlockAlloc;
|
||||
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK);
|
||||
recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK);
|
||||
recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK);
|
||||
recConstBuf = (u32*)curpos; curpos += RECCONSTBUF_SIZE * sizeof(u32);
|
||||
recRAMCopy = (u32*)curpos;
|
||||
|
||||
if( s_pInstCache == NULL )
|
||||
{
|
||||
s_nInstCacheSize = 128;
|
||||
s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize );
|
||||
}
|
||||
|
||||
if( s_pInstCache == NULL )
|
||||
throw Exception::OutOfMemory( L"R5900-32 InstCache" );
|
||||
|
||||
// No errors.. Proceed with initialization:
|
||||
|
||||
ProfilerRegisterSource( "EE Rec", recMem, REC_CACHEMEM+0x1000 );
|
||||
_DynGen_Dispatchers();
|
||||
|
||||
x86FpuState = FPU_STATE;
|
||||
recReserveCache();
|
||||
}
|
||||
|
||||
struct ManualPageTracking
|
||||
static void recAlloc()
|
||||
{
|
||||
u16 page;
|
||||
u8 counter;
|
||||
};
|
||||
if (!recRAMCopy)
|
||||
{
|
||||
recRAMCopy = new SpatialArrayReserve( L"R5900 RAM copy" );
|
||||
recRAMCopy->SetBlockSize(_16kb);
|
||||
recRAMCopy->Reserve(Ps2MemSize::MainRam);
|
||||
}
|
||||
|
||||
if (!recRAM)
|
||||
{
|
||||
recLutReserve_RAM = new R5900LutReserve_RAM( L"R5900 RAM LUT" );
|
||||
recLutReserve_RAM->SetBlockSize(_16kb);
|
||||
recLutReserve_RAM->Reserve(Ps2MemSize::MainRam + Ps2MemSize::Rom + Ps2MemSize::Rom1);
|
||||
}
|
||||
|
||||
static __aligned16 u16 manual_page[Ps2MemSize::Base >> 12];
|
||||
static __aligned16 u8 manual_counter[Ps2MemSize::Base >> 12];
|
||||
BASEBLOCK* basepos = (BASEBLOCK*)recLutReserve_RAM->GetPtr();
|
||||
recRAM = basepos; basepos += (Ps2MemSize::MainRam / 4);
|
||||
recROM = basepos; basepos += (Ps2MemSize::Rom / 4);
|
||||
recROM1 = basepos; basepos += (Ps2MemSize::Rom1 / 4);
|
||||
|
||||
static u32 eeRecIsReset = false;
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
void recResetEE( void )
|
||||
{
|
||||
//AtomicExchange( eeRecNeedsReset, false );
|
||||
if( AtomicExchange( eeRecIsReset, true ) ) return;
|
||||
|
||||
Console.WriteLn( Color_StrongBlack, "EE/iR5900-32 Recompiler Reset" );
|
||||
|
||||
maxrecmem = 0;
|
||||
|
||||
if (IsDevBuild)
|
||||
memset_8<0xcc, REC_CACHEMEM>(recMem); // 0xcc is INT3
|
||||
memzero_ptr<m_recBlockAllocSize - Ps2MemSize::Base>( m_recBlockAlloc ); // Excluding the 32mb ram copy
|
||||
memzero_ptr<RECCONSTBUF_SIZE * sizeof(u32)>(recConstBuf);
|
||||
memzero( manual_page );
|
||||
memzero( manual_counter );
|
||||
ClearRecLUT((BASEBLOCK*)m_recBlockAlloc,
|
||||
(((Ps2MemSize::Base + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4)));
|
||||
|
||||
if( s_pInstCache )
|
||||
memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize );
|
||||
|
||||
recBlocks.Reset();
|
||||
mmap_ResetBlockTracking();
|
||||
|
||||
#ifdef _MSC_VER
|
||||
__asm emms;
|
||||
#else
|
||||
__asm__("emms");
|
||||
#endif
|
||||
pxAssert(recLutReserve_RAM->GetPtrEnd() == (u8*)basepos);
|
||||
|
||||
for (int i = 0; i < 0x10000; i++)
|
||||
recLUT_SetPage(recLUT, 0, 0, 0, i, 0);
|
||||
|
@ -684,30 +663,100 @@ void recResetEE( void )
|
|||
recLUT_SetPage(recLUT, hwLUT, recROM1, 0xa000, i, i - 0x1e00);
|
||||
}
|
||||
|
||||
x86SetPtr(recMem);
|
||||
if( recConstBuf == NULL )
|
||||
recConstBuf = (u32*) _aligned_malloc( RECCONSTBUF_SIZE * sizeof(*recConstBuf), 16 );
|
||||
|
||||
recPtr = recMem;
|
||||
if( recConstBuf == NULL )
|
||||
throw Exception::OutOfMemory( L"R5900-32 SIMD Constants Buffer" );
|
||||
|
||||
if( s_pInstCache == NULL )
|
||||
{
|
||||
s_nInstCacheSize = 128;
|
||||
s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize );
|
||||
}
|
||||
|
||||
if( s_pInstCache == NULL )
|
||||
throw Exception::OutOfMemory( L"R5900-32 InstCache" );
|
||||
|
||||
// No errors.. Proceed with initialization:
|
||||
|
||||
_DynGen_Dispatchers();
|
||||
|
||||
x86FpuState = FPU_STATE;
|
||||
}
|
||||
|
||||
struct ManualPageTracking
|
||||
{
|
||||
u16 page;
|
||||
u8 counter;
|
||||
};
|
||||
|
||||
static __aligned16 u16 manual_page[Ps2MemSize::MainRam >> 12];
|
||||
static __aligned16 u8 manual_counter[Ps2MemSize::MainRam >> 12];
|
||||
|
||||
static u32 eeRecIsReset = false;
|
||||
static u32 eeRecNeedsReset = false;
|
||||
static bool eeCpuExecuting = false;
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
static void recResetRaw()
|
||||
{
|
||||
recAlloc();
|
||||
|
||||
if( AtomicExchange( eeRecIsReset, true ) ) return;
|
||||
AtomicExchange( eeRecNeedsReset, false );
|
||||
|
||||
Console.WriteLn( Color_StrongBlack, "EE/iR5900-32 Recompiler Reset" );
|
||||
|
||||
recMem->Reset();
|
||||
recRAMCopy->Reset();
|
||||
recLutReserve_RAM->Reset();
|
||||
|
||||
maxrecmem = 0;
|
||||
|
||||
memzero_ptr<RECCONSTBUF_SIZE * sizeof(recConstBuf)>(recConstBuf);
|
||||
|
||||
if( s_pInstCache )
|
||||
memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize );
|
||||
|
||||
recBlocks.Reset();
|
||||
mmap_ResetBlockTracking();
|
||||
|
||||
x86SetPtr(*recMem);
|
||||
|
||||
recPtr = *recMem;
|
||||
recConstBufPtr = recConstBuf;
|
||||
x86FpuState = FPU_STATE;
|
||||
|
||||
branch = 0;
|
||||
}
|
||||
|
||||
static void recShutdown( void )
|
||||
static void recShutdown()
|
||||
{
|
||||
ProfilerTerminateSource( "EERec" );
|
||||
safe_delete( recMem );
|
||||
safe_delete( recRAMCopy );
|
||||
safe_delete( recLutReserve_RAM );
|
||||
|
||||
recBlocks.Reset();
|
||||
|
||||
SafeSysMunmap( recMem, REC_CACHEMEM );
|
||||
safe_aligned_free( m_recBlockAlloc );
|
||||
recRAM = recROM = recROM1 = NULL;
|
||||
recConstBuf = NULL;
|
||||
recRAMCopy = NULL;
|
||||
|
||||
safe_aligned_free( recConstBuf );
|
||||
safe_free( s_pInstCache );
|
||||
s_nInstCacheSize = 0;
|
||||
}
|
||||
|
||||
static void recResetEE()
|
||||
{
|
||||
if (eeCpuExecuting)
|
||||
{
|
||||
AtomicExchange( eeRecNeedsReset, true );
|
||||
return;
|
||||
}
|
||||
|
||||
recResetRaw();
|
||||
}
|
||||
|
||||
void recStep( void )
|
||||
{
|
||||
}
|
||||
|
@ -744,8 +793,6 @@ static void recCheckExecutionState()
|
|||
}
|
||||
}
|
||||
|
||||
static bool m_recExecutingCode = false;
|
||||
|
||||
static void recExecute()
|
||||
{
|
||||
// Implementation Notes:
|
||||
|
@ -753,12 +800,14 @@ static void recExecute()
|
|||
|
||||
#if PCSX2_SEH
|
||||
eeRecIsReset = false;
|
||||
ScopedBool executing(m_recExecutingCode);
|
||||
ScopedBool executing(eeCpuExecuting);
|
||||
|
||||
try {
|
||||
EnterRecompiledCode();
|
||||
}
|
||||
catch( Exception::ExitCpuExecute& ) { }
|
||||
catch( Exception::ExitCpuExecute& )
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
@ -816,18 +865,8 @@ void R5900::Dynarec::OpcodeImpl::recBREAK( void )
|
|||
//branch = 2;
|
||||
}
|
||||
|
||||
// Clears the recLUT table so that all blocks are mapped to the JIT recompiler by default.
|
||||
static __ri void ClearRecLUT(BASEBLOCK* base, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
base[i].SetFnptr((uptr)JITCompile);
|
||||
}
|
||||
|
||||
void recClear(u32 addr, u32 size)
|
||||
{
|
||||
BASEBLOCKEX* pexblock;
|
||||
BASEBLOCK* pblock;
|
||||
|
||||
// necessary since recompiler doesn't call femms/emms
|
||||
#ifdef _MSC_VER
|
||||
__asm emms;
|
||||
|
@ -846,14 +885,14 @@ void recClear(u32 addr, u32 size)
|
|||
|
||||
u32 lowerextent = (u32)-1, upperextent = 0, ceiling = (u32)-1;
|
||||
|
||||
pexblock = recBlocks[blockidx + 1];
|
||||
BASEBLOCKEX* pexblock = recBlocks[blockidx + 1];
|
||||
if (pexblock)
|
||||
ceiling = pexblock->startpc;
|
||||
|
||||
while (pexblock = recBlocks[blockidx]) {
|
||||
u32 blockstart = pexblock->startpc;
|
||||
u32 blockend = pexblock->startpc + pexblock->size * 4;
|
||||
pblock = PC_GETBLOCK(blockstart);
|
||||
BASEBLOCK* pblock = PC_GETBLOCK(blockstart);
|
||||
|
||||
if (pblock == s_pCurBlock) {
|
||||
blockidx--;
|
||||
|
@ -889,7 +928,7 @@ void recClear(u32 addr, u32 size)
|
|||
}
|
||||
|
||||
if (upperextent > lowerextent)
|
||||
ClearRecLUT(PC_GETBLOCK(lowerextent), (upperextent - lowerextent) / 4);
|
||||
ClearRecLUT(PC_GETBLOCK(lowerextent), upperextent - lowerextent);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1354,17 +1393,22 @@ static void __fastcall recRecompile( const u32 startpc )
|
|||
pxAssume( startpc );
|
||||
|
||||
// if recPtr reached the mem limit reset whole mem
|
||||
if ( ( (uptr)recPtr - (uptr)recMem ) >= REC_CACHEMEM-0x40000 || dumplog == 0xffffffff) {
|
||||
recResetEE();
|
||||
if (recPtr >= (recMem->GetPtrEnd() - _64kb)) {
|
||||
AtomicExchange( eeRecNeedsReset, true );
|
||||
}
|
||||
if ( (recConstBufPtr - recConstBuf) >= RECCONSTBUF_SIZE - 64 ) {
|
||||
else if ((recConstBufPtr - recConstBuf) >= RECCONSTBUF_SIZE - 64) {
|
||||
Console.WriteLn("EE recompiler stack reset");
|
||||
recResetEE();
|
||||
AtomicExchange( eeRecNeedsReset, true );
|
||||
}
|
||||
|
||||
if (eeRecNeedsReset) recResetRaw();
|
||||
|
||||
xSetPtr( recPtr );
|
||||
recPtr = xGetAlignedCallTarget();
|
||||
|
||||
if (0x8000d618 == startpc)
|
||||
DbgCon.WriteLn("Compiling block @ 0x%08x", startpc);
|
||||
|
||||
s_pCurBlock = PC_GETBLOCK(startpc);
|
||||
|
||||
pxAssert(s_pCurBlock->GetFnptr() == (uptr)JITCompile
|
||||
|
@ -1764,7 +1808,7 @@ StartRecomp:
|
|||
pxAssert( (pc-startpc)>>2 <= 0xffff );
|
||||
s_pCurBlockEx->size = (pc-startpc)>>2;
|
||||
|
||||
if (HWADDR(pc) <= Ps2MemSize::Base) {
|
||||
if (HWADDR(pc) <= Ps2MemSize::MainRam) {
|
||||
BASEBLOCKEX *oldBlock;
|
||||
int i;
|
||||
|
||||
|
@ -1774,10 +1818,12 @@ StartRecomp:
|
|||
continue;
|
||||
if (oldBlock->startpc >= HWADDR(pc))
|
||||
continue;
|
||||
if (oldBlock->startpc + oldBlock->size * 4 <= HWADDR(startpc))
|
||||
if ((oldBlock->startpc + oldBlock->size * 4) <= HWADDR(startpc))
|
||||
break;
|
||||
if (memcmp(&recRAMCopy[oldBlock->startpc / 4], PSM(oldBlock->startpc),
|
||||
oldBlock->size * 4)) {
|
||||
|
||||
if (memcmp(&(*recRAMCopy)[oldBlock->startpc / 4], PSM(oldBlock->startpc),
|
||||
oldBlock->size * 4))
|
||||
{
|
||||
recClear(startpc, (pc - startpc) / 4);
|
||||
s_pCurBlockEx = recBlocks.Get(HWADDR(startpc));
|
||||
pxAssert(s_pCurBlockEx->startpc == HWADDR(startpc));
|
||||
|
@ -1785,7 +1831,7 @@ StartRecomp:
|
|||
}
|
||||
}
|
||||
|
||||
memcpy_fast(&recRAMCopy[HWADDR(startpc) / 4], PSM(startpc), pc - startpc);
|
||||
memcpy_fast(&(*recRAMCopy)[HWADDR(startpc) / 4], PSM(startpc), pc - startpc);
|
||||
}
|
||||
|
||||
s_pCurBlock->SetFnptr((uptr)recPtr);
|
||||
|
@ -1836,11 +1882,11 @@ StartRecomp:
|
|||
}
|
||||
}
|
||||
|
||||
pxAssert( xGetPtr() < recMem+REC_CACHEMEM );
|
||||
pxAssert( xGetPtr() < recMem->GetPtrEnd() );
|
||||
pxAssert( recConstBufPtr < recConstBuf + RECCONSTBUF_SIZE );
|
||||
pxAssert( x86FpuState == 0 );
|
||||
|
||||
pxAssert(xGetPtr() - recPtr < 0x10000);
|
||||
pxAssert(xGetPtr() - recPtr < _64kb);
|
||||
s_pCurBlockEx->x86size = xGetPtr() - recPtr;
|
||||
|
||||
recPtr = xGetPtr();
|
||||
|
@ -1859,7 +1905,7 @@ static void recThrowException( const BaseR5900Exception& ex )
|
|||
#if PCSX2_SEH
|
||||
ex.Rethrow();
|
||||
#else
|
||||
if (!m_recExecutingCode) ex.Rethrow();
|
||||
if (!eeCpuExecuting) ex.Rethrow();
|
||||
m_cpuException = ex.Clone();
|
||||
recExitExecution();
|
||||
#endif
|
||||
|
@ -1870,15 +1916,25 @@ static void recThrowException( const BaseException& ex )
|
|||
#if PCSX2_SEH
|
||||
ex.Rethrow();
|
||||
#else
|
||||
if (!m_recExecutingCode) ex.Rethrow();
|
||||
if (!eeCpuExecuting) ex.Rethrow();
|
||||
m_Exception = ex.Clone();
|
||||
recExitExecution();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void recSetCacheReserve( uint reserveInMegs )
|
||||
{
|
||||
m_ConfiguredCacheReserve = reserveInMegs;
|
||||
}
|
||||
|
||||
static uint recGetCacheReserve()
|
||||
{
|
||||
return m_ConfiguredCacheReserve;
|
||||
}
|
||||
|
||||
R5900cpu recCpu =
|
||||
{
|
||||
recAlloc,
|
||||
recReserve,
|
||||
recShutdown,
|
||||
|
||||
recResetEE,
|
||||
|
@ -1889,4 +1945,7 @@ R5900cpu recCpu =
|
|||
recThrowException,
|
||||
recThrowException,
|
||||
recClear,
|
||||
|
||||
recGetCacheReserve,
|
||||
recSetCacheReserve,
|
||||
};
|
||||
|
|
|
@ -287,7 +287,7 @@ void vtlb_dynarec_init()
|
|||
hasBeenCalled = true;
|
||||
|
||||
// In case init gets called multiple times:
|
||||
HostSys::MemProtectStatic( m_IndirectDispatchers, Protect_ReadWrite, false );
|
||||
HostSys::MemProtectStatic( m_IndirectDispatchers, PageAccess_ReadWrite() );
|
||||
|
||||
// clear the buffer to 0xcc (easier debugging).
|
||||
memset_8<0xcc,0x1000>( m_IndirectDispatchers );
|
||||
|
@ -309,7 +309,7 @@ void vtlb_dynarec_init()
|
|||
}
|
||||
}
|
||||
|
||||
HostSys::MemProtectStatic( m_IndirectDispatchers, Protect_ReadOnly, true );
|
||||
HostSys::MemProtectStatic( m_IndirectDispatchers, PageAccess_ExecOnly() );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
#include "Common.h"
|
||||
#include "microVU.h"
|
||||
#include "System/RecTypes.h"
|
||||
|
||||
// Include all the *.inl files (Needed because C++ sucks with templates and *.cpp files)
|
||||
#include "microVU_Clamp.inl"
|
||||
|
@ -80,8 +81,20 @@ const __aligned(32) mVU_Globals mVUglob = {
|
|||
|
||||
static __fi void mVUthrowHardwareDeficiency(const wxChar* extFail, int vuIndex) {
|
||||
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 ));
|
||||
.SetDiagMsg(pxsFmt(L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail))
|
||||
.SetUserMsg(pxsFmt(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail ));
|
||||
}
|
||||
|
||||
void microVU::reserveCache()
|
||||
{
|
||||
cache_reserve = new RecompiledCodeReserve( pxsFmt("Micro VU%u Recompiler Cache", index) );
|
||||
cache_reserve->SetProfilerName( pxsFmt("mVU%urec", index) );
|
||||
|
||||
cache = index ?
|
||||
(u8*)cache_reserve->Reserve( cacheSize * _1mb, HostMemoryMap::mVU1rec ) :
|
||||
(u8*)cache_reserve->Reserve( cacheSize * _1mb, HostMemoryMap::mVU0rec );
|
||||
|
||||
cache_reserve->ThrowIfNotOk();
|
||||
}
|
||||
|
||||
// Only run this once per VU! ;)
|
||||
|
@ -99,22 +112,14 @@ void microVU::init(uint vuIndex) {
|
|||
microMemSize = (index ? 0x4000 : 0x1000);
|
||||
progSize = (index ? 0x4000 : 0x1000) / 4;
|
||||
progMemMask = progSize-1;
|
||||
dispCache = NULL;
|
||||
cache = NULL;
|
||||
cacheSize = mVUcacheSize;
|
||||
regAlloc = new microRegAlloc(index);
|
||||
|
||||
for (u32 i = 0; i < (progSize / 2); i++) {
|
||||
prog.prog[i] = new deque<microProgram*>();
|
||||
}
|
||||
reserveCache();
|
||||
|
||||
dispCache = SysMmapEx(0, mVUdispCacheSize, 0, (index ? "Micro VU1 Dispatcher" : "Micro VU0 Dispatcher"));
|
||||
if (!dispCache) throw Exception::OutOfMemory( index ? L"Micro VU1 Dispatcher" : L"Micro VU0 Dispatcher" );
|
||||
memset(dispCache, 0xcc, mVUdispCacheSize);
|
||||
|
||||
// Allocates rec-cache and calls mVUreset()
|
||||
mVUresizeCache(this, cacheSize + mVUcacheSafeZone);
|
||||
//if (vuIndex) gen_memcpy_vibes();
|
||||
regAlloc = new microRegAlloc(index);
|
||||
}
|
||||
|
||||
// Resets Rec Data
|
||||
|
@ -123,16 +128,12 @@ void microVU::reset() {
|
|||
x86SetPtr(dispCache);
|
||||
mVUdispatcherA(this);
|
||||
mVUdispatcherB(this);
|
||||
mVUemitSearch();
|
||||
mVUemitSearch();
|
||||
|
||||
// Clear All Program Data
|
||||
//memset(&prog, 0, sizeof(prog));
|
||||
memset(&prog.lpState, 0, sizeof(prog.lpState));
|
||||
|
||||
if (IsDevBuild) { // Release builds shouldn't need this
|
||||
memset(cache, 0xcc, cacheSize);
|
||||
}
|
||||
|
||||
// Program Variables
|
||||
prog.cleared = 1;
|
||||
prog.isSame = -1;
|
||||
|
@ -144,9 +145,15 @@ void microVU::reset() {
|
|||
u8* z = cache;
|
||||
prog.x86start = z;
|
||||
prog.x86ptr = z;
|
||||
prog.x86end = (u8*)((uptr)z + (uptr)(cacheSize - mVUcacheSafeZone)); // "Safe Zone"
|
||||
prog.x86end = z + ((cacheSize - mVUcacheSafeZone) * _1mb);
|
||||
|
||||
for (u32 i = 0; i < (progSize / 2); i++) {
|
||||
if (!prog.prog[i])
|
||||
{
|
||||
prog.prog[i] = new deque<microProgram*>();
|
||||
continue;
|
||||
}
|
||||
|
||||
deque<microProgram*>::iterator it(prog.prog[i]->begin());
|
||||
for ( ; it != prog.prog[i]->end(); ++it) {
|
||||
if (index) mVUdeleteProg<1>(it[0]);
|
||||
|
@ -161,11 +168,13 @@ void microVU::reset() {
|
|||
// Free Allocated Resources
|
||||
void microVU::close() {
|
||||
|
||||
if (dispCache) { HostSys::Munmap(dispCache, mVUdispCacheSize); dispCache = NULL; }
|
||||
if (cache) { HostSys::Munmap(cache, cacheSize); cache = NULL; }
|
||||
safe_delete(cache_reserve);
|
||||
|
||||
SafeSysMunmap(dispCache, mVUdispCacheSize);
|
||||
|
||||
// Delete Programs and Block Managers
|
||||
for (u32 i = 0; i < (progSize / 2); i++) {
|
||||
if (!prog.prog[i]) continue;
|
||||
deque<microProgram*>::iterator it(prog.prog[i]->begin());
|
||||
for ( ; it != prog.prog[i]->end(); ++it) {
|
||||
if (index) mVUdeleteProg<1>(it[0]);
|
||||
|
@ -175,35 +184,6 @@ void microVU::close() {
|
|||
}
|
||||
}
|
||||
|
||||
static void mVUresizeCache(mV, u32 size) {
|
||||
|
||||
if (size >= (u32)mVUcacheMaxSize) {
|
||||
if (mVU->cacheSize==mVUcacheMaxSize) {
|
||||
// We can't grow the rec any larger, so just reset it and start over.
|
||||
//(if we don't reset, the rec will eventually crash)
|
||||
Console.WriteLn(Color_Magenta, "microVU%d: Cannot grow cache, size limit reached! [%dmb]. Resetting rec.", mVU->index, mVU->cacheSize/_1mb);
|
||||
mVU->reset();
|
||||
return;
|
||||
}
|
||||
size = mVUcacheMaxSize;
|
||||
}
|
||||
|
||||
if (mVU->cache) Console.WriteLn(Color_Green, "microVU%d: Attempting to resize Cache [%dmb]", mVU->index, size/_1mb);
|
||||
|
||||
u8* cache = SysMmapEx(0, 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); mVU->reset(); return; }
|
||||
if (mVU->cache) {
|
||||
HostSys::Munmap(mVU->cache, mVU->cacheSize);
|
||||
ProfilerTerminateSource(isVU1?"mVU1 Rec":"mVU0 Rec");
|
||||
}
|
||||
|
||||
mVU->cache = cache;
|
||||
mVU->cacheSize = size;
|
||||
ProfilerRegisterSource(isVU1?"mVU1 Rec":"mVU0 Rec", mVU->cache, mVU->cacheSize);
|
||||
mVU->reset();
|
||||
}
|
||||
|
||||
// Clears Block Data in specified range
|
||||
static __fi void mVUclear(mV, u32 addr, u32 size) {
|
||||
if (!mVU->prog.cleared) {
|
||||
|
@ -323,55 +303,40 @@ _mVUt __fi void* mVUsearchProg(u32 startPC, uptr pState) {
|
|||
// recMicroVU0 / recMicroVU1
|
||||
//------------------------------------------------------------------
|
||||
|
||||
static u32 mvu0_allocated = 0;
|
||||
static u32 mvu1_allocated = 0;
|
||||
|
||||
recMicroVU0::recMicroVU0() { m_Idx = 0; IsInterpreter = false; }
|
||||
recMicroVU1::recMicroVU1() { m_Idx = 1; IsInterpreter = false; }
|
||||
void recMicroVU0::Vsync() throw() { mVUvsyncUpdate(µVU0); }
|
||||
void recMicroVU1::Vsync() throw() { mVUvsyncUpdate(µVU1); }
|
||||
|
||||
void recMicroVU0::Allocate() {
|
||||
if(!m_AllocCount) {
|
||||
m_AllocCount++;
|
||||
if (AtomicExchange(mvu0_allocated, 1) == 0)
|
||||
microVU0.init(0);
|
||||
}
|
||||
void recMicroVU0::Reserve() {
|
||||
if (AtomicExchange(m_Reserved, 1) == 0)
|
||||
microVU0.init(0);
|
||||
}
|
||||
void recMicroVU1::Allocate() {
|
||||
if(!m_AllocCount) {
|
||||
m_AllocCount++;
|
||||
if (AtomicExchange(mvu1_allocated, 1) == 0)
|
||||
microVU1.init(1);
|
||||
}
|
||||
void recMicroVU1::Reserve() {
|
||||
if (AtomicExchange(m_Reserved, 1) == 0)
|
||||
microVU1.init(1);
|
||||
}
|
||||
|
||||
void recMicroVU0::Shutdown() throw() {
|
||||
if (m_AllocCount > 0) {
|
||||
m_AllocCount--;
|
||||
if (AtomicExchange(mvu0_allocated, 0) == 1)
|
||||
microVU0.close();
|
||||
}
|
||||
if (AtomicExchange(m_Reserved, 0) == 1)
|
||||
microVU0.close();
|
||||
}
|
||||
void recMicroVU1::Shutdown() throw() {
|
||||
if (m_AllocCount > 0) {
|
||||
m_AllocCount--;
|
||||
if (AtomicExchange(mvu1_allocated, 0) == 1)
|
||||
microVU1.close();
|
||||
}
|
||||
if (AtomicExchange(m_Reserved, 0) == 1)
|
||||
microVU1.close();
|
||||
}
|
||||
|
||||
void recMicroVU0::Reset() {
|
||||
if(!pxAssertDev(m_AllocCount, "MicroVU0 CPU Provider has not been allocated prior to reset!")) return;
|
||||
if(!pxAssertDev(m_Reserved, "MicroVU0 CPU Provider has not been reserved prior to reset!")) return;
|
||||
microVU0.reset();
|
||||
}
|
||||
void recMicroVU1::Reset() {
|
||||
if(!pxAssertDev(m_AllocCount, "MicroVU1 CPU Provider has not been allocated prior to reset!")) return;
|
||||
if(!pxAssertDev(m_Reserved, "MicroVU1 CPU Provider has not been reserved prior to reset!")) return;
|
||||
microVU1.reset();
|
||||
}
|
||||
|
||||
void recMicroVU0::Execute(u32 cycles) {
|
||||
pxAssert(mvu0_allocated); // please allocate me first! :|
|
||||
pxAssert(m_Reserved); // please allocate me first! :|
|
||||
|
||||
if(!(VU0.VI[REG_VPU_STAT].UL & 1)) return;
|
||||
|
||||
|
@ -381,17 +346,35 @@ void recMicroVU0::Execute(u32 cycles) {
|
|||
((mVUrecCall)microVU0.startFunct)(VU0.VI[REG_TPC].UL, cycles);
|
||||
}
|
||||
void recMicroVU1::Execute(u32 cycles) {
|
||||
pxAssert(mvu1_allocated); // please allocate me first! :|
|
||||
pxAssert(m_Reserved); // please allocate me first! :|
|
||||
|
||||
if(!(VU0.VI[REG_VPU_STAT].UL & 0x100)) return;
|
||||
((mVUrecCall)microVU1.startFunct)(VU1.VI[REG_TPC].UL, vu1RunCycles);
|
||||
}
|
||||
|
||||
void recMicroVU0::Clear(u32 addr, u32 size) {
|
||||
pxAssert(mvu0_allocated); // please allocate me first! :|
|
||||
pxAssert(m_Reserved); // please allocate me first! :|
|
||||
mVUclear(µVU0, addr, size);
|
||||
}
|
||||
void recMicroVU1::Clear(u32 addr, u32 size) {
|
||||
pxAssert(mvu1_allocated); // please allocate me first! :|
|
||||
pxAssert(m_Reserved); // please allocate me first! :|
|
||||
mVUclear(µVU1, addr, size);
|
||||
}
|
||||
|
||||
uint recMicroVU0::GetCacheReserve() const
|
||||
{
|
||||
return microVU0.cacheSize;
|
||||
}
|
||||
uint recMicroVU1::GetCacheReserve() const
|
||||
{
|
||||
return microVU1.cacheSize;
|
||||
}
|
||||
|
||||
void recMicroVU0::SetCacheReserve( uint reserveInMegs ) const
|
||||
{
|
||||
microVU0.cacheSize = reserveInMegs;
|
||||
}
|
||||
void recMicroVU1::SetCacheReserve( uint reserveInMegs ) const
|
||||
{
|
||||
microVU1.cacheSize = reserveInMegs;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ using namespace x86Emitter;
|
|||
#include "iR5900.h"
|
||||
#include "R5900OpcodeTables.h"
|
||||
#include "x86emitter/x86emitter.h"
|
||||
#include "SamplProf.h"
|
||||
#include "microVU_Misc.h"
|
||||
#include "microVU_IR.h"
|
||||
|
||||
|
@ -150,11 +149,8 @@ struct microProgManager {
|
|||
microRegInfo lpState; // Pipeline state from where program left off (useful for continuing execution)
|
||||
};
|
||||
|
||||
#define mVUdispCacheSize (0x1000) // Dispatcher Cache Size
|
||||
#define mVUcacheSize ((index) ? (_1mb * 17) : (_1mb * 7)) // Initial Size (Excluding Safe-Zone)
|
||||
#define mVUcacheMaxSize ((mVU->index) ? (_1mb * 100) : (_1mb * 50)) // Max Size allowed to grow to
|
||||
#define mVUcacheGrowBy ((mVU->index) ? (_1mb * 15) : (_1mb * 10)) // Grows by this amount
|
||||
#define mVUcacheSafeZone ((index) ? (_1mb * 3) : (_1mb * 3)) // Safe-Zone for last program
|
||||
static const uint mVUdispCacheSize = __pagesize; // Dispatcher Cache Size (in bytes)
|
||||
static const uint mVUcacheSafeZone = 3; // Safe-Zone for program recompilation (in megabytes)
|
||||
|
||||
struct microVU {
|
||||
|
||||
|
@ -171,11 +167,13 @@ struct microVU {
|
|||
u32 progMemMask; // VU Micro Memory Size (in u32's)
|
||||
u32 cacheSize; // VU Cache Size
|
||||
|
||||
microProgManager prog; // Micro Program Data
|
||||
microProgManager prog; // Micro Program Data
|
||||
ScopedPtr<microRegAlloc> regAlloc; // Reg Alloc Class
|
||||
ScopedPtr<AsciiFile> logFile; // Log File Pointer
|
||||
|
||||
u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to)
|
||||
|
||||
RecompiledCodeReserve* cache_reserve;
|
||||
u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to)
|
||||
u8* dispCache; // Dispatchers Cache (where startFunct and exitFunct are written to)
|
||||
u8* startFunct; // Ptr Function to the Start code for recompiled programs
|
||||
u8* exitFunct; // Ptr Function to the Exit code for recompiled programs
|
||||
|
@ -224,7 +222,17 @@ struct microVU {
|
|||
pxAssumeDev((prog.IRinfo.curPC & 1) == 0, "microVU recompiler: Upper instructions cannot have valid branch addresses.");
|
||||
return (((prog.IRinfo.curPC + 4) + (Imm11() * 2)) & progMemMask) * 4;
|
||||
}
|
||||
|
||||
microVU()
|
||||
{
|
||||
cacheSize = 64;
|
||||
cache = NULL;
|
||||
dispCache = NULL;
|
||||
startFunct = NULL;
|
||||
exitFunct = NULL;
|
||||
}
|
||||
|
||||
void reserveCache();
|
||||
void init(uint vuIndex);
|
||||
void reset();
|
||||
void close();
|
||||
|
@ -239,7 +247,6 @@ int mVUdebugNow = 0;
|
|||
|
||||
// Main Functions
|
||||
static void mVUclear(mV, u32, u32);
|
||||
static void mVUresizeCache(mV, u32);
|
||||
static void* mVUblockFetch(microVU* mVU, u32 startPC, uptr pState);
|
||||
_mVUt extern void* __fastcall mVUcompileJIT(u32 startPC, uptr pState);
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ void mVUdispatcherB(mV) {
|
|||
|
||||
xRET();
|
||||
|
||||
mVUcacheCheck(x86Ptr, mVU->dispCache, mVUdispCacheSize);
|
||||
pxAssertDev(xGetPtr() < (mVU->dispCache + mVUdispCacheSize), "microVU: Dispatcher generation exceeded reserved cache area!");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
@ -121,8 +121,14 @@ _mVUt void mVUcleanUp() {
|
|||
//mVUprint("microVU: Program exited successfully!");
|
||||
//mVUprint("microVU: VF0 = {%x,%x,%x,%x}", mVU->regs().VF[0].UL[0], mVU->regs().VF[0].UL[1], mVU->regs().VF[0].UL[2], mVU->regs().VF[0].UL[3]);
|
||||
//mVUprint("microVU: VI0 = %x", mVU->regs().VI[0].UL);
|
||||
|
||||
mVU->prog.x86ptr = x86Ptr;
|
||||
mVUcacheCheck(x86Ptr, mVU->prog.x86start, (uptr)(mVU->prog.x86end - mVU->prog.x86start));
|
||||
|
||||
if ((xGetPtr() < mVU->prog.x86start) || (xGetPtr() >= mVU->prog.x86end)) {
|
||||
Console.WriteLn(vuIndex ? Color_Orange : Color_Magenta, "microVU%d: Program cache limit reached.", mVU->index);
|
||||
mVU->reset();
|
||||
}
|
||||
|
||||
mVU->cycles = mVU->totalCycles - mVU->cycles;
|
||||
mVU->regs().cycle += mVU->cycles;
|
||||
cpuRegs.cycle += ((mVU->cycles < 3000) ? mVU->cycles : 3000) * EmuConfig.Speedhacks.VUCycleSteal;
|
||||
|
|
|
@ -298,15 +298,6 @@ static const bool doConstProp = 0; // Set to 1 to turn on vi15 const propagation
|
|||
|
||||
//------------------------------------------------------------------
|
||||
|
||||
// Cache Limit Check
|
||||
#define mVUcacheCheck(ptr, start, limit) { \
|
||||
uptr diff = ptr - start; \
|
||||
if (diff >= limit) { \
|
||||
DevCon.WriteLn("microVU%d: Program cache limit reached. Size = 0x%x", mVU->index, diff); \
|
||||
mVUresizeCache(mVU, mVU->cacheSize + mVUcacheGrowBy); \
|
||||
} \
|
||||
}
|
||||
|
||||
extern void mVUmergeRegs(const xmm& dest, const xmm& src, int xyzw, bool modXYZW=false);
|
||||
extern void mVUsaveReg(const xmm& reg, xAddressVoid ptr, int xyzw, bool modXYZW);
|
||||
extern void mVUloadReg(const xmm& reg, xAddressVoid ptr, int xyzw);
|
||||
|
|
|
@ -251,7 +251,7 @@ __fi void mVUaddrFix(mV, const x32& gprReg)
|
|||
else {
|
||||
if (IsDevBuild && !isCOP2) mVUbackupRegs(mVU, true);
|
||||
xTEST(gprReg, 0x400);
|
||||
xForwardJNZ8 jmpA; // if addr & 0x4000, reads VU1's VF regs and VI regs
|
||||
xForwardJNZ8 jmpA; // if addr & 0x4000, reads VU1's VF regs and VI regs
|
||||
xAND(gprReg, 0xff); // if !(addr & 0x4000), wrap around
|
||||
xForwardJump8 jmpB;
|
||||
jmpA.SetTarget();
|
||||
|
@ -481,7 +481,7 @@ static __pagealigned u8 mVUsearchXMM[__pagesize];
|
|||
// Generates a custom optimized block-search function
|
||||
// Note: Structs must be 16-byte aligned! (GCC doesn't guarantee this)
|
||||
void mVUcustomSearch() {
|
||||
HostSys::MemProtectStatic(mVUsearchXMM, Protect_ReadWrite, false);
|
||||
HostSys::MemProtectStatic(mVUsearchXMM, PageAccess_ReadWrite());
|
||||
memset_8<0xcc,__pagesize>(mVUsearchXMM);
|
||||
xSetPtr(mVUsearchXMM);
|
||||
|
||||
|
@ -526,5 +526,5 @@ void mVUcustomSearch() {
|
|||
|
||||
exitPoint.SetTarget();
|
||||
xRET();
|
||||
HostSys::MemProtectStatic(mVUsearchXMM, Protect_ReadOnly, true);
|
||||
HostSys::MemProtectStatic(mVUsearchXMM, PageAccess_ExecOnly());
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "VU.h"
|
||||
|
||||
#include "x86emitter/x86emitter.h"
|
||||
#include "System/RecTypes.h"
|
||||
|
||||
using namespace x86Emitter;
|
||||
|
||||
#define aMax(x, y) std::max(x,y)
|
||||
|
@ -28,13 +30,14 @@ using namespace x86Emitter;
|
|||
typedef u32 (__fastcall *nVifCall)(void*, const void*);
|
||||
typedef void (__fastcall *nVifrecCall)(uptr dest, uptr src);
|
||||
|
||||
#include "newVif_BlockBuffer.h"
|
||||
#include "newVif_HashBucket.h"
|
||||
|
||||
extern void mVUmergeRegs(const xRegisterSSE& dest, const xRegisterSSE& src, int xyzw, bool modXYZW = 0);
|
||||
extern void _nVifUnpack (int idx, const u8* data, uint mode, bool isFill);
|
||||
extern void dVifReserve (int idx);
|
||||
extern void dVifReset (int idx);
|
||||
extern void dVifClose (int idx);
|
||||
extern void dVifRelease (int idx);
|
||||
extern void VifUnpackSSE_Init();
|
||||
|
||||
_vifT extern void dVifUnpack (const u8* data, bool isFill);
|
||||
|
@ -76,23 +79,25 @@ struct nVifStruct {
|
|||
u32 bSize; // Size of 'buffer'
|
||||
u32 bPtr;
|
||||
|
||||
u32 idx; // VIF0 or VIF1
|
||||
u8* recPtr; // Cur Pos to recompile to
|
||||
u8* recEnd; // 'Safe' End of Rec Cache
|
||||
BlockBuffer* vifCache; // Block Buffer
|
||||
uint recReserveSizeMB; // reserve size, in megabytes.
|
||||
RecompiledCodeReserve* recReserve;
|
||||
u8* recWritePtr; // current write pos into the reserve
|
||||
|
||||
HashBucket<_tParams>* vifBlocks; // Vif Blocks
|
||||
int numBlocks; // # of Blocks Recompiled
|
||||
|
||||
nVifStruct()
|
||||
{
|
||||
vifCache = NULL;
|
||||
vifBlocks = NULL;
|
||||
numBlocks = 0;
|
||||
recPtr = NULL;
|
||||
recEnd = NULL;
|
||||
}
|
||||
|
||||
// VIF0 or VIF1 - provided for debugging helpfulness only, and is generally unused.
|
||||
// (templates are used for most or all VIF indexing)
|
||||
u32 idx;
|
||||
|
||||
nVifStruct();
|
||||
};
|
||||
|
||||
extern void reserveNewVif(int idx);
|
||||
extern void closeNewVif(int idx);
|
||||
extern void resetNewVif(int idx);
|
||||
extern void releaseNewVif(int idx);
|
||||
|
||||
extern __aligned16 nVifStruct nVif[2];
|
||||
extern __aligned16 nVifCall nVifUpk[(2*2*16)*4]; // ([USN][Masking][Unpack Type]) [curCycle]
|
||||
extern __aligned16 u32 nVifMask[3][4][4]; // [MaskNumber][CycleNumber][Vector]
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Allocates a Chunk of memory using SysMmapEx...
|
||||
// This memory can be used to write recompiled code to.
|
||||
// Its got basic resizing/growing ability too, but probably
|
||||
// won't be too useful since growing the block buffer will
|
||||
// invalidate any pointers pointing to the old block buffer.
|
||||
// (so remember to invalidate those block pointers :D)
|
||||
// It also deallocates itself on 'delete', so you can
|
||||
// just use 'new' and 'delete' for initialization and
|
||||
// deletion/cleanup respectfully...
|
||||
class BlockBuffer {
|
||||
protected:
|
||||
u32 mSize; // Cur Size (in bytes)
|
||||
u32 mSizeT; // Total Size (in bytes)
|
||||
u32 mGrowBy; // amount to grow by when buffer fills (in bytes)
|
||||
u8* mData; // Data Ptr (allocated via SysMmap)
|
||||
|
||||
void alloc(int size) {
|
||||
mData = SysMmapEx(0, size, 0, "nVif_BlockBuffer");
|
||||
if (!mData) throw Exception::OutOfMemory(L"nVif recompiled code buffer (nVif_BlockBuffer)");
|
||||
clear();
|
||||
}
|
||||
void dealloc(u8* &dPtr, int size) {
|
||||
SafeSysMunmap( dPtr, size );
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~BlockBuffer() throw() {
|
||||
dealloc(mData, mSizeT);
|
||||
}
|
||||
|
||||
BlockBuffer(u32 tSize, u32 growby=_1mb*2) {
|
||||
mSizeT = tSize;
|
||||
mGrowBy = growby;
|
||||
mSize = 0;
|
||||
alloc(mSizeT);
|
||||
}
|
||||
|
||||
void append(void *addr, u32 size) {
|
||||
if ((mSize + size) > mSizeT) grow(mSizeT + mGrowBy);
|
||||
memcpy_fast(&mData[mSize], addr, size);
|
||||
mSize += size;
|
||||
}
|
||||
|
||||
// Increases the allocation size. Warning: Unlike 'realloc' this function will
|
||||
// CLEAR all contents of the buffer. This is because copying contents of recompiled
|
||||
// caches is mostly useless since it invalidates any pointers into the block.
|
||||
// (code relocation techniques are possible, but are difficult, potentially slow,
|
||||
// and easily bug prone. Not recommended at this time). --air
|
||||
void grow(u32 newSize) {
|
||||
pxAssume( newSize > mSizeT );
|
||||
u8* temp = mData;
|
||||
alloc(newSize);
|
||||
dealloc(temp, mSizeT);
|
||||
clear();
|
||||
mSizeT = newSize;
|
||||
}
|
||||
|
||||
// clears the entire buffer to recompiler fill (0xcc), and sets mSize to 0.
|
||||
// (indicating none of the buffer is allocated).
|
||||
void clear() {
|
||||
if( mSize == 0 ) return; // no clears needed if nothing's been written/modified
|
||||
mSize = 0;
|
||||
memset(mData, 0xcc, mSizeT);
|
||||
}
|
||||
|
||||
u32 getCurSize() { return mSize; }
|
||||
u32 getAllocSize() { return mSizeT; }
|
||||
u8* getBlock() { return mData; }
|
||||
};
|
|
@ -22,34 +22,37 @@
|
|||
|
||||
static __aligned16 nVifBlock _vBlock = {0};
|
||||
|
||||
void dVifReset(int idx) {
|
||||
// If the VIF cache is greater than 12mb, then it's due for a complete reset back
|
||||
// down to a reasonable starting point of 4mb.
|
||||
if( nVif[idx].vifCache && (nVif[idx].vifCache->getAllocSize() > _1mb*12) )
|
||||
safe_delete(nVif[idx].vifCache);
|
||||
void dVifReserve(int idx)
|
||||
{
|
||||
if (!nVif[idx].recReserve)
|
||||
nVif[idx].recReserve = new RecompiledCodeReserve(pxsFmt(L"VIF%u Unpack Recompiler Cache", idx));
|
||||
|
||||
if( !nVif[idx].vifCache )
|
||||
nVif[idx].vifCache = new BlockBuffer(_1mb*4);
|
||||
else
|
||||
nVif[idx].vifCache->clear();
|
||||
nVif[idx].recReserve->Reserve( nVif[idx].recReserveSizeMB * _1mb, idx ? HostMemoryMap::VIF1rec : HostMemoryMap::VIF0rec );
|
||||
}
|
||||
|
||||
void dVifReset(int idx) {
|
||||
|
||||
if( !nVif[idx].vifBlocks )
|
||||
nVif[idx].vifBlocks = new HashBucket<_tParams>();
|
||||
else
|
||||
nVif[idx].vifBlocks->clear();
|
||||
|
||||
nVif[idx].numBlocks = 0;
|
||||
|
||||
nVif[idx].recPtr = nVif[idx].vifCache->getBlock();
|
||||
nVif[idx].recEnd = &nVif[idx].recPtr[nVif[idx].vifCache->getAllocSize()-(_1mb/4)]; // .25mb Safe Zone
|
||||
nVif[idx].recReserve->Reset();
|
||||
nVif[idx].numBlocks = 0;
|
||||
nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr();
|
||||
}
|
||||
|
||||
void dVifClose(int idx) {
|
||||
nVif[idx].numBlocks = 0;
|
||||
safe_delete(nVif[idx].vifCache);
|
||||
nVif[idx].recReserve->Reset();
|
||||
|
||||
safe_delete(nVif[idx].vifBlocks);
|
||||
}
|
||||
|
||||
void dVifRelease(int idx) {
|
||||
safe_delete(nVif[idx].recReserve);
|
||||
}
|
||||
|
||||
VifUnpackSSE_Dynarec::VifUnpackSSE_Dynarec(const nVifStruct& vif_, const nVifBlock& vifBlock_)
|
||||
: v(vif_)
|
||||
, vB(vifBlock_)
|
||||
|
@ -223,11 +226,10 @@ _vifT static __fi u8* dVifsetVUptr(uint cl, uint wl, bool isFill) {
|
|||
// [TODO] : Finish implementing support for VIF's growable recBlocks buffer. Currently
|
||||
// it clears the buffer only.
|
||||
static __fi void dVifRecLimit(int idx) {
|
||||
if (nVif[idx].recPtr > nVif[idx].recEnd) {
|
||||
DevCon.WriteLn("nVif Rec - Out of Rec Cache! [%x > %x]", nVif[idx].recPtr, nVif[idx].recEnd);
|
||||
nVif[idx].vifBlocks->clear();
|
||||
nVif[idx].recPtr = nVif[idx].vifCache->getBlock();
|
||||
nVif[idx].recEnd = &nVif[idx].recPtr[nVif[idx].vifCache->getAllocSize()-(_1mb/4)]; // .25mb Safe Zone
|
||||
if (nVif[idx].recWritePtr > (nVif[idx].recReserve->GetPtrEnd() - _256kb)) {
|
||||
DevCon.WriteLn("nVif Recompiler Cache Reset! [0x%08x > 0x%08x]", nVif[idx].recWritePtr, nVif[idx].recReserve->GetPtrEnd());
|
||||
nVif[idx].recReserve->Reset();
|
||||
nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,11 +279,11 @@ _vifT __fi void dVifUnpack(const u8* data, bool isFill) {
|
|||
|
||||
if (dVifExecuteUnpack<idx>(data, isFill)) return;
|
||||
|
||||
xSetPtr(v.recPtr);
|
||||
xSetPtr(v.recWritePtr);
|
||||
_vBlock.startPtr = (uptr)xGetAlignedCallTarget();
|
||||
v.vifBlocks->add(_vBlock);
|
||||
VifUnpackSSE_Dynarec( v, _vBlock ).CompileRoutine();
|
||||
nVif[idx].recPtr = xGetPtr();
|
||||
nVif[idx].recWritePtr = xGetPtr();
|
||||
|
||||
// [TODO] : Ideally we should test recompile buffer limits prior to each instruction,
|
||||
// which would be safer and more memory efficient than using an 0.25 meg recEnd marker.
|
||||
|
|
|
@ -70,6 +70,19 @@ static const __aligned16 Fnptr_VifUnpackLoop UnpackLoopTable[2][2][2] = {
|
|||
};
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
nVifStruct::nVifStruct()
|
||||
{
|
||||
vifBlocks = NULL;
|
||||
numBlocks = 0;
|
||||
|
||||
recReserveSizeMB = 8;
|
||||
}
|
||||
|
||||
void reserveNewVif(int idx)
|
||||
{
|
||||
if (newVifDynaRec) dVifReserve(idx);
|
||||
}
|
||||
|
||||
void resetNewVif(int idx)
|
||||
{
|
||||
// Safety Reset : Reassign all VIF structure info, just in case the VU1 pointers have
|
||||
|
@ -86,6 +99,10 @@ void closeNewVif(int idx) {
|
|||
if (newVifDynaRec) dVifClose(idx);
|
||||
}
|
||||
|
||||
void releaseNewVif(int idx) {
|
||||
if (newVifDynaRec) dVifRelease(idx);
|
||||
}
|
||||
|
||||
static __fi u8* getVUptr(uint idx, int offset) {
|
||||
return (u8*)(vuRegs[idx].Mem + ( offset & (idx ? 0x3ff0 : 0xff0) ));
|
||||
}
|
||||
|
|
|
@ -295,7 +295,7 @@ static void nVifGen(int usn, int mask, int curCycle) {
|
|||
|
||||
void VifUnpackSSE_Init()
|
||||
{
|
||||
HostSys::MemProtectStatic(nVifUpkExec, Protect_ReadWrite, false);
|
||||
HostSys::MemProtectStatic(nVifUpkExec, PageAccess_ReadWrite());
|
||||
memset8<0xcc>( nVifUpkExec );
|
||||
|
||||
xSetPtr( nVifUpkExec );
|
||||
|
@ -306,5 +306,5 @@ void VifUnpackSSE_Init()
|
|||
nVifGen(a, b, c);
|
||||
}}}
|
||||
|
||||
HostSys::MemProtectStatic(nVifUpkExec, Protect_ReadOnly, true);
|
||||
HostSys::MemProtectStatic(nVifUpkExec, PageAccess_ExecOnly());
|
||||
}
|
||||
|
|
|
@ -35,9 +35,9 @@
|
|||
|
||||
#include "R5900.h"
|
||||
#include "iR5900.h"
|
||||
#include "System/RecTypes.h"
|
||||
|
||||
#include "sVU_zerorec.h"
|
||||
#include "SamplProf.h"
|
||||
#include "NakedAsm.h"
|
||||
#include "AppConfig.h"
|
||||
|
||||
|
@ -72,7 +72,7 @@ extern void iDumpVU1Registers();
|
|||
|
||||
#define SUPERVU_CHECKCONDITION 0 // has to be 0!!
|
||||
|
||||
#define VU_EXESIZE 0x00800000
|
||||
static const uint sVU_EXESIZE = _8mb;
|
||||
|
||||
#define _Imm11_ (s32)( (vucode & 0x400) ? (0xfffffc00 | (vucode & 0x3ff)) : (vucode & 0x3ff) )
|
||||
#define _UImm11_ (s32)(vucode & 0x7ff)
|
||||
|
@ -90,7 +90,9 @@ static const u32 PWaitTimes[] = { 53, 43, 28, 23, 17, 11, 10 };
|
|||
static u32 s_vuInfo; // info passed into rec insts
|
||||
|
||||
static const u32 s_MemSize[2] = {VU0_MEMSIZE, VU1_MEMSIZE};
|
||||
static u8* s_recVUMem = NULL, *s_recVUPtr = NULL;
|
||||
//static u8* s_recVUMem = NULL, *s_recVUPtr = NULL;
|
||||
static RecompiledCodeReserve* s_recVUMem[2] = { NULL, NULL };
|
||||
static u8* s_recVUPtr[2] = { NULL, NULL };
|
||||
|
||||
// tables which are defined at the bottom of this massive file.
|
||||
extern void (*recVU_UPPER_OPCODE[64])(VURegs* VU, s32 info);
|
||||
|
@ -315,9 +317,11 @@ VuBaseBlock::VuBaseBlock()
|
|||
|
||||
static list<VuFunctionHeader*> s_listVUHeaders[2];
|
||||
static list<VuFunctionHeader*>* s_plistCachedHeaders[2] = {NULL, NULL};
|
||||
static VuFunctionHeader** recVUHeaders[2] = {NULL, NULL};
|
||||
static VuBlockHeader* recVUBlocks[2] = {NULL, NULL};
|
||||
static u8* recVUStack = NULL, *recVUStackPtr = NULL;
|
||||
static VuFunctionHeader** recVUHeaders[2] = { NULL, NULL };
|
||||
static VuBlockHeader* recVUBlocks[2] = { NULL, NULL };
|
||||
static u8* recVUStack[2] = { NULL, NULL };
|
||||
static u8* recVUStackPtr[2] = { NULL, NULL };
|
||||
|
||||
static vector<_x86regs> s_vecRegArray(128);
|
||||
|
||||
static VURegs* VU = NULL;
|
||||
|
@ -343,47 +347,23 @@ static void SuperVURecompile();
|
|||
// allocate VU resources
|
||||
static void SuperVUAlloc(int vuindex)
|
||||
{
|
||||
// The old -1 crap has been depreciated on this function. Please
|
||||
// specify either 0 or 1, thanks.
|
||||
pxAssert(vuindex >= 0);
|
||||
if (s_recVUMem[vuindex]) return;
|
||||
|
||||
s_recVUMem[vuindex] = new RecompiledCodeReserve( pxsFmt("SuperVU%u Recompiler Cache", vuindex), 0 );
|
||||
s_recVUMem[vuindex]->Reserve( sVU_EXESIZE, vuindex ? HostMemoryMap::sVU1rec : HostMemoryMap::sVU0rec, _256mb );
|
||||
s_recVUMem[vuindex]->SetProfilerName(pxsFmt("sVU%urec",vuindex));
|
||||
|
||||
// upper 4 bits must be zero!
|
||||
if (s_recVUMem == NULL)
|
||||
if (!s_recVUMem[vuindex]->IsOk())
|
||||
{
|
||||
// upper 4 bits must be zero!
|
||||
// Changed "first try base" to 0xf1e0000, since 0x0c000000 liked to fail a lot. (cottonvibes)
|
||||
s_recVUMem = SysMmapEx(0xf1e0000, VU_EXESIZE, 0x10000000, "SuperVUAlloc");
|
||||
|
||||
// Try again at some other random memory location... whatever. >_<
|
||||
if( s_recVUMem == NULL )
|
||||
s_recVUMem = SysMmapEx(0xc2b0000, VU_EXESIZE, 0x10000000, "SuperVUAlloc");
|
||||
|
||||
if (s_recVUMem == NULL)
|
||||
{
|
||||
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);
|
||||
|
||||
if (recVUStack == NULL) recVUStack = new u8[SUPERVU_STACKSIZE * 4];
|
||||
}
|
||||
|
||||
if (vuindex >= 0)
|
||||
{
|
||||
pxAssert(s_recVUMem != NULL);
|
||||
|
||||
if (recVUHeaders[vuindex] == NULL)
|
||||
recVUHeaders[vuindex] = new VuFunctionHeader* [s_MemSize[vuindex] / 8];
|
||||
if (recVUBlocks[vuindex] == NULL)
|
||||
recVUBlocks[vuindex] = new VuBlockHeader[s_MemSize[vuindex] / 8];
|
||||
if (s_plistCachedHeaders[vuindex] == NULL)
|
||||
s_plistCachedHeaders[vuindex] = new list<VuFunctionHeader*>[s_MemSize[vuindex] / 8];
|
||||
safe_delete(s_recVUMem[vuindex]);
|
||||
throw Exception::VirtualMemoryMapConflict( s_recVUMem[vuindex]->GetName() )
|
||||
.SetDiagMsg(pxsFmt( 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. :)"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,72 +396,64 @@ void DestroyVUHeaders(int vuindex)
|
|||
// destroy VU resources
|
||||
void SuperVUDestroy(int vuindex)
|
||||
{
|
||||
list<VuFunctionHeader*>::iterator it;
|
||||
pxAssumeDev(vuindex >= 0 && vuindex <= 2, "Invalid VU index parameter!");
|
||||
|
||||
if (vuindex < 0)
|
||||
{
|
||||
SuperVUDestroy(0);
|
||||
SuperVUDestroy(1);
|
||||
ProfilerTerminateSource("VURec");
|
||||
SafeSysMunmap(s_recVUMem, VU_EXESIZE);
|
||||
safe_delete_array(recVUStack);
|
||||
}
|
||||
else
|
||||
{
|
||||
safe_delete_array(recVUHeaders[vuindex]);
|
||||
safe_delete_array(recVUBlocks[vuindex]);
|
||||
safe_delete_array(recVUHeaders[vuindex]);
|
||||
safe_delete_array(recVUBlocks[vuindex]);
|
||||
|
||||
if (s_plistCachedHeaders[vuindex] != NULL)
|
||||
if (s_plistCachedHeaders[vuindex] != NULL)
|
||||
{
|
||||
for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j)
|
||||
{
|
||||
for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j)
|
||||
{
|
||||
DestroyCachedHeaders(vuindex, j);
|
||||
}
|
||||
safe_delete_array(s_plistCachedHeaders[vuindex]);
|
||||
DestroyCachedHeaders(vuindex, j);
|
||||
}
|
||||
DestroyVUHeaders(vuindex);
|
||||
safe_delete_array(s_plistCachedHeaders[vuindex]);
|
||||
}
|
||||
DestroyVUHeaders(vuindex);
|
||||
|
||||
safe_delete(s_recVUMem[vuindex]);
|
||||
safe_delete_array(recVUStack[vuindex]);
|
||||
}
|
||||
|
||||
// reset VU
|
||||
void SuperVUReset(int vuindex)
|
||||
{
|
||||
pxAssumeDev(vuindex >= 0 && vuindex <= 2, "Invalid VU index parameter!");
|
||||
|
||||
#ifdef PCSX2_DEBUG
|
||||
s_vucount = 0;
|
||||
#endif
|
||||
|
||||
if (s_recVUMem == NULL)
|
||||
return;
|
||||
DevCon.WriteLn("SuperVU%d: Resetting function and block lists.", vuindex);
|
||||
|
||||
//pxAssume( s_recVUMem != NULL );
|
||||
if (recVUHeaders[vuindex] == NULL)
|
||||
recVUHeaders[vuindex] = new VuFunctionHeader* [s_MemSize[vuindex] / 8];
|
||||
if (recVUBlocks[vuindex] == NULL)
|
||||
recVUBlocks[vuindex] = new VuBlockHeader[s_MemSize[vuindex] / 8];
|
||||
if (s_plistCachedHeaders[vuindex] == NULL)
|
||||
s_plistCachedHeaders[vuindex] = new std::list<VuFunctionHeader*>[s_MemSize[vuindex] / 8];
|
||||
|
||||
if (vuindex < 0)
|
||||
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));
|
||||
|
||||
if (s_plistCachedHeaders[vuindex] != NULL)
|
||||
{
|
||||
DbgCon.WriteLn("SuperVU: Resetting recompiler memory and structures.");
|
||||
|
||||
// Does this cause problems on VU recompiler resets? It could, if the VU works like
|
||||
// the EE used to, and actually tries to re-enter the recBlock after issuing a clear. (air)
|
||||
|
||||
//memset_8<0xcd, VU_EXESIZE>(s_recVUMem);
|
||||
memzero_ptr<SUPERVU_STACKSIZE>(recVUStack);
|
||||
|
||||
s_recVUPtr = s_recVUMem;
|
||||
}
|
||||
else
|
||||
{
|
||||
DbgCon.WriteLn("SuperVU [VU%d]: Resetting the recs and junk", vuindex);
|
||||
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));
|
||||
|
||||
if (s_plistCachedHeaders[vuindex] != NULL)
|
||||
for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j)
|
||||
{
|
||||
for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j)
|
||||
{
|
||||
DestroyCachedHeaders(vuindex, j);
|
||||
}
|
||||
DestroyCachedHeaders(vuindex, j);
|
||||
}
|
||||
DestroyVUHeaders(vuindex);
|
||||
}
|
||||
DestroyVUHeaders(vuindex);
|
||||
|
||||
if (!s_recVUMem[vuindex] || !s_recVUMem[vuindex]->IsOk()) return;
|
||||
|
||||
DevCon.WriteLn("SuperVU%u: Resetting recompiler cache.", vuindex);
|
||||
|
||||
if (!recVUStack[vuindex]) recVUStack[vuindex] = new u8[SUPERVU_STACKSIZE * 4];
|
||||
memzero_ptr<SUPERVU_STACKSIZE>(recVUStack[vuindex]);
|
||||
|
||||
s_recVUMem[vuindex]->Reset();
|
||||
s_recVUPtr[vuindex] = *s_recVUMem[vuindex];
|
||||
}
|
||||
|
||||
// clear the block and any joining blocks
|
||||
|
@ -847,16 +819,15 @@ void VuBaseBlock::GetInstsAtPc(int instpc, list<VuInstruction*>& listinsts)
|
|||
static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex)
|
||||
{
|
||||
pxAssert(vuindex < 2);
|
||||
pxAssert(s_recVUPtr != NULL);
|
||||
pxAssert(s_recVUPtr[vuindex] != NULL);
|
||||
//Console.WriteLn("svu%c rec: %x", '0'+vuindex, startpc);
|
||||
|
||||
// if recPtr reached the mem limit reset whole mem
|
||||
if (((uptr)s_recVUPtr - (uptr)s_recVUMem) >= VU_EXESIZE - 0x40000)
|
||||
if ((s_recVUPtr[vuindex] < s_recVUMem[vuindex]->GetPtr()) || (s_recVUPtr[vuindex] >= s_recVUMem[vuindex]->GetPtrEnd() - _256kb))
|
||||
{
|
||||
//Console.WriteLn("SuperVU reset mem");
|
||||
Console.WriteLn("SuperVU%u: Recompiler cache reset...", vuindex);
|
||||
SuperVUReset(0);
|
||||
SuperVUReset(1);
|
||||
SuperVUReset(-1);
|
||||
if (s_TotalVUCycles > 0)
|
||||
{
|
||||
// already executing, so return NULL
|
||||
|
@ -912,12 +883,12 @@ static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex)
|
|||
#endif
|
||||
|
||||
// code generation
|
||||
x86SetPtr(s_recVUPtr);
|
||||
xSetPtr(s_recVUPtr[vuindex]);
|
||||
branch = 0;
|
||||
|
||||
SuperVURecompile();
|
||||
|
||||
s_recVUPtr = x86Ptr;
|
||||
s_recVUPtr[vuindex] = xGetPtr();
|
||||
|
||||
// set the function's range
|
||||
VuFunctionHeader::RANGE r;
|
||||
|
@ -947,7 +918,7 @@ static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex)
|
|||
}
|
||||
s_listBlocks.clear();
|
||||
|
||||
pxAssert(s_recVUPtr < s_recVUMem + VU_EXESIZE);
|
||||
pxAssertDev(s_recVUPtr[vuindex] < s_recVUMem[vuindex]->GetPtrEnd(), "SuperVU recompiler cache exceeded! (possible memory corruption)");
|
||||
|
||||
return s_pFnHeader;
|
||||
}
|
||||
|
@ -2697,18 +2668,18 @@ void SuperVUFlush(int p, int wait)
|
|||
// executed only once per program
|
||||
static u32* SuperVUStaticAlloc(u32 size)
|
||||
{
|
||||
pxAssert(recVUStackPtr + size <= recVUStack + SUPERVU_STACKSIZE);
|
||||
pxAssert(recVUStackPtr[s_vu] + size <= recVUStack[s_vu] + SUPERVU_STACKSIZE);
|
||||
// always zero
|
||||
if (size == 4) *(u32*)recVUStackPtr = 0;
|
||||
else memset(recVUStackPtr, 0, size);
|
||||
recVUStackPtr += size;
|
||||
return (u32*)(recVUStackPtr - size);
|
||||
if (size == 4) *(u32*)recVUStackPtr[s_vu] = 0;
|
||||
else memset(recVUStackPtr[s_vu], 0, size);
|
||||
recVUStackPtr[s_vu] += size;
|
||||
return (u32*)(recVUStackPtr[s_vu] - size);
|
||||
}
|
||||
|
||||
static void SuperVURecompile()
|
||||
{
|
||||
// save cpu state
|
||||
recVUStackPtr = recVUStack;
|
||||
recVUStackPtr[s_vu] = recVUStack[s_vu];
|
||||
|
||||
_initXMMregs();
|
||||
|
||||
|
@ -4617,9 +4588,9 @@ recSuperVU0::recSuperVU0()
|
|||
IsInterpreter = false;
|
||||
}
|
||||
|
||||
void recSuperVU0::Allocate()
|
||||
void recSuperVU0::Reserve()
|
||||
{
|
||||
SuperVUAlloc( 0 );
|
||||
SuperVUAlloc(0);
|
||||
}
|
||||
|
||||
void recSuperVU0::Shutdown() throw()
|
||||
|
@ -4645,6 +4616,15 @@ void recSuperVU0::Clear(u32 Addr, u32 Size)
|
|||
SuperVUClear(Addr, Size, 0);
|
||||
}
|
||||
|
||||
uint recSuperVU0::GetCacheReserve() const
|
||||
{
|
||||
return sVU_EXESIZE / _1mb;
|
||||
}
|
||||
|
||||
void recSuperVU0::SetCacheReserve( uint reserveInMegs ) const
|
||||
{
|
||||
//microVU0.cacheSize = reserveInMegs * _1mb;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// recSuperVU1 Interface
|
||||
|
@ -4655,9 +4635,9 @@ recSuperVU1::recSuperVU1()
|
|||
IsInterpreter = false;
|
||||
}
|
||||
|
||||
void recSuperVU1::Allocate()
|
||||
void recSuperVU1::Reserve()
|
||||
{
|
||||
SuperVUAlloc( 1 );
|
||||
SuperVUAlloc(1);
|
||||
}
|
||||
|
||||
void recSuperVU1::Shutdown() throw()
|
||||
|
@ -4670,6 +4650,16 @@ void recSuperVU1::Reset()
|
|||
SuperVUReset( 1 );
|
||||
}
|
||||
|
||||
uint recSuperVU1::GetCacheReserve() const
|
||||
{
|
||||
return sVU_EXESIZE / _1mb;
|
||||
}
|
||||
|
||||
void recSuperVU1::SetCacheReserve( uint reserveInMegs ) const
|
||||
{
|
||||
//microVU0.cacheSize = reserveInMegs * _1mb;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include "sVU_Compare.h"
|
||||
#else
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
<Unit filename="ini.cpp" />
|
||||
<Unit filename="linux.cpp" />
|
||||
<Unit filename="linux.h" />
|
||||
<Unit filename="onepad.glade" />
|
||||
<Unit filename="../analog.cpp" />
|
||||
<Unit filename="../analog.h" />
|
||||
<Unit filename="../bitwise.h" />
|
||||
|
@ -68,6 +67,7 @@
|
|||
<Extensions>
|
||||
<code_completion />
|
||||
<debugger />
|
||||
<envvars />
|
||||
</Extensions>
|
||||
</Project>
|
||||
</CodeBlocks_project_file>
|
||||
|
|
|
@ -132,9 +132,6 @@
|
|||
</Unit>
|
||||
<Unit filename="../../Win32/Win32.h" />
|
||||
<Unit filename="../../Win32/aviUtil.h" />
|
||||
<Unit filename="../../Win32/jconfig.h" />
|
||||
<Unit filename="../../Win32/jmorecfg.h" />
|
||||
<Unit filename="../../Win32/jpeglib.h" />
|
||||
<Unit filename="../../Win32/resource.h" />
|
||||
<Unit filename="../../Win32/resrc1.h" />
|
||||
<Unit filename="../../Win32/wglext.h" />
|
||||
|
@ -177,6 +174,7 @@
|
|||
<Extensions>
|
||||
<code_completion />
|
||||
<debugger />
|
||||
<envvars />
|
||||
</Extensions>
|
||||
</Project>
|
||||
</CodeBlocks_project_file>
|
||||
|
|
Loading…
Reference in New Issue