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:
Jake.Stine 2010-11-17 05:49:11 +00:00
commit 2ee6b7abc6
97 changed files with 7081 additions and 5314 deletions

View File

@ -155,6 +155,8 @@
<Unit filename="../../include/Utilities/HashMap.h" /> <Unit filename="../../include/Utilities/HashMap.h" />
<Unit filename="../../include/Utilities/IniInterface.h" /> <Unit filename="../../include/Utilities/IniInterface.h" />
<Unit filename="../../include/Utilities/MemcpyFast.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/Path.h" />
<Unit filename="../../include/Utilities/PersistentThread.h" /> <Unit filename="../../include/Utilities/PersistentThread.h" />
<Unit filename="../../include/Utilities/RedtapeWindows.h" /> <Unit filename="../../include/Utilities/RedtapeWindows.h" />
@ -200,6 +202,7 @@
<Unit filename="../../src/Utilities/ThreadTools.cpp" /> <Unit filename="../../src/Utilities/ThreadTools.cpp" />
<Unit filename="../../src/Utilities/ThreadingDialogs.cpp" /> <Unit filename="../../src/Utilities/ThreadingDialogs.cpp" />
<Unit filename="../../src/Utilities/ThreadingInternal.h" /> <Unit filename="../../src/Utilities/ThreadingInternal.h" />
<Unit filename="../../src/Utilities/VirtualMemory.cpp" />
<Unit filename="../../src/Utilities/pxCheckBox.cpp" /> <Unit filename="../../src/Utilities/pxCheckBox.cpp" />
<Unit filename="../../src/Utilities/pxRadioPanel.cpp" /> <Unit filename="../../src/Utilities/pxRadioPanel.cpp" />
<Unit filename="../../src/Utilities/pxStaticText.cpp" /> <Unit filename="../../src/Utilities/pxStaticText.cpp" />

File diff suppressed because it is too large Load Diff

View File

@ -160,7 +160,7 @@ public:
~ScopedBool() throw() ~ScopedBool() throw()
{ {
m_boolme = false; *m_boolme = false;
} }
}; };
@ -177,6 +177,21 @@ public:
#include "Pcsx2Defs.h" #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! // i18n/Translation Feature Set!
// =========================================================================================== // ===========================================================================================

View File

@ -209,7 +209,7 @@ public: \
// //
class OutOfMemory : public RuntimeError class OutOfMemory : public RuntimeError
{ {
DEFINE_RUNTIME_EXCEPTION( OutOfMemory, RuntimeError, wxLt("Out of memory?!") ) DEFINE_RUNTIME_EXCEPTION( OutOfMemory, RuntimeError, wxEmptyString )
public: public:
wxString AllocDescription; wxString AllocDescription;
@ -236,7 +236,12 @@ public: \
// we'd really like to have access to. // we'd really like to have access to.
class VirtualMemoryMapConflict : public OutOfMemory 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 class HardwareDeficiency : public RuntimeError
@ -254,43 +259,40 @@ public: \
virtual classname& SetStreamName( const wxString& name ) { StreamName = name; return *this; } \ virtual classname& SetStreamName( const wxString& name ) { StreamName = name; return *this; } \
virtual classname& SetStreamName( const char* name ) { StreamName = fromUTF8(name); return *this; } virtual classname& SetStreamName( const char* name ) { StreamName = fromUTF8(name); return *this; }
#define DEFINE_STREAM_EXCEPTION( classname, parent, message ) \ #define DEFINE_STREAM_EXCEPTION( classname, parent ) \
DEFINE_RUNTIME_EXCEPTION( classname, parent, message ) \ DEFINE_RUNTIME_EXCEPTION( classname, parent, wxEmptyString ) \
classname( const wxString& filename ) { \ classname( const wxString& filename ) { \
StreamName = filename; \ StreamName = filename; \
SetBothMsgs(message); \
} \ } \
DEFINE_STREAM_EXCEPTION_ACCESSORS( classname ) DEFINE_STREAM_EXCEPTION_ACCESSORS( classname )
// Generic stream error. Contains the name of the stream and a message. // A generic base error class for bad streams -- corrupted data, sudden closures, loss of
// This exception is usually thrown via derived classes, except in the (rare) case of a // connection, or anything else that would indicate a failure to open a stream or read the
// generic / unknown error. // 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: public:
wxString StreamName; // name of the stream (if applicable) wxString StreamName; // name of the stream (if applicable)
virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const; virtual wxString FormatDisplayMessage() const;
};
// A generic base error class for bad streams -- corrupted data, sudden closures, loss of protected:
// connection, or anything else that would indicate a failure to read the data after the void _formatDiagMsg( FastFormatUnicode& dest ) const;
// stream was successfully opened. void _formatUserMsg( FastFormatUnicode& dest ) const;
//
class BadStream : public Stream
{
DEFINE_STREAM_EXCEPTION( BadStream, Stream, wxLt("File data is corrupted or incomplete, or the stream connection closed unexpectedly.") )
}; };
// A generic exception for odd-ball stream creation errors. // 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. // Exception thrown when an attempt to open a non-existent file is made.
@ -299,22 +301,31 @@ public: \
class FileNotFound : public CannotCreateStream class FileNotFound : public CannotCreateStream
{ {
public: 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 class AccessDenied : public CannotCreateStream
{ {
public: 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 // EndOfStream can be used either as an error, or used just as a shortcut for manual
// feof checks. // feof checks.
// //
class EndOfStream : public Stream class EndOfStream : public BadStream
{ {
public: 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__ #ifdef __WXMSW__

View File

@ -133,14 +133,84 @@ protected:
virtual void DoDeletion(); virtual void DoDeletion();
}; };
// --------------------------------------------------------------------------------------
enum PageProtectionMode // PageProtectionMode
// --------------------------------------------------------------------------------------
class PageProtectionMode
{ {
Protect_NoAccess = 0, protected:
Protect_ReadOnly, bool m_read;
Protect_ReadWrite 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 // HostSys
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -148,22 +218,29 @@ enum PageProtectionMode
// platform prior to wxWidgets .. it should prolly be removed -- air) // platform prior to wxWidgets .. it should prolly be removed -- air)
namespace HostSys 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. // Maps a block of memory for use as a recompiled code buffer.
// The allocated block has code execution privileges.
// Returns NULL on allocation failure. // 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 // 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 > 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 );
} }
} }

View File

@ -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) );
}

View File

@ -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;

View File

@ -102,6 +102,7 @@ public:
wxFileName operator+( const wxFileName& right ) const { return Combine( right ); } wxFileName operator+( const wxFileName& right ) const { return Combine( right ); }
wxDirName operator+( const wxDirName& 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); }
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 // 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 // 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 namespace Path
{ {

View File

@ -31,7 +31,8 @@ SafeArray<T>::SafeArray( const wxChar* name, T* allocated_mem, int initSize )
m_size = initSize; m_size = initSize;
if( m_ptr == NULL ) 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 > template< typename T >
@ -79,7 +80,8 @@ SafeArray<T>::SafeArray( int initialSize, const wxChar* name )
m_size = initialSize; m_size = initialSize;
if( (initialSize != 0) && (m_ptr == NULL) ) 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. // 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 ); m_ptr = _virtual_realloc( newsize );
if( m_ptr == NULL ) if( m_ptr == NULL )
throw Exception::OutOfMemory(Name + throw Exception::OutOfMemory(Name)
wxsFormat(L" (SafeArray::ExactAlloc) [oldsize=%d] [newsize=%d]", m_size, newsize) .SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ExactAlloc' [oldsize=%d] [newsize=%d]", m_size, newsize));
);
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) ); m_ptr = (T*)malloc( initialSize * sizeof(T) );
if( m_ptr == NULL ) if( m_ptr == NULL )
throw Exception::OutOfMemory(Name + throw Exception::OutOfMemory(Name)
wxsFormat(L" (SafeList::Constructor) [length=%d]", m_length) .SetDiagMsg(wxsFormat(L"called from 'SafeList::ctor' [length=%d]", m_length));
);
for( int i=0; i<m_allocsize; ++i ) for( int i=0; i<m_allocsize; ++i )
{ {
@ -227,9 +227,8 @@ void SafeList<T>::MakeRoomFor( int blockSize )
const int newalloc = blockSize + ChunkSize; const int newalloc = blockSize + ChunkSize;
m_ptr = _virtual_realloc( newalloc ); m_ptr = _virtual_realloc( newalloc );
if( m_ptr == NULL ) if( m_ptr == NULL )
throw Exception::OutOfMemory(Name + throw Exception::OutOfMemory(Name)
wxsFormat(L" (SafeList::MakeRoomFor) [oldlen=%d] [newlen=%d]", m_length, blockSize) .SetDiagMsg(wxsFormat(L"Called from 'SafeList::MakeRoomFor' [oldlen=%d] [newlen=%d]", m_length, blockSize));
);
for( ; m_allocsize<newalloc; ++m_allocsize ) for( ; m_allocsize<newalloc; ++m_allocsize )
{ {

View File

@ -60,6 +60,26 @@ extern void pcsx2_aligned_free(void* pmem);
# define _aligned_realloc pcsx2_aligned_realloc # define _aligned_realloc pcsx2_aligned_realloc
#endif #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 // BaseScopedAlloc

View File

@ -222,6 +222,8 @@ extern bool pxParseAssignmentString( const wxString& src, wxString& ldest, wxStr
#define pxsFmt FastFormatUnicode().Write #define pxsFmt FastFormatUnicode().Write
#define pxsFmtV FastFormatUnicode().WriteV #define pxsFmtV FastFormatUnicode().WriteV
#define pxsPtr(ptr) pxsFmt("0x%08X", (ptr)).c_str()
extern wxString& operator+=(wxString& str1, const FastFormatUnicode& str2); extern wxString& operator+=(wxString& str1, const FastFormatUnicode& str2);
extern wxString operator+(const wxString& str1, const FastFormatUnicode& str2); extern wxString operator+(const wxString& str1, const FastFormatUnicode& str2);
extern wxString operator+(const wxChar* str1, const FastFormatUnicode& str2); extern wxString operator+(const wxChar* str1, const FastFormatUnicode& str2);

View File

@ -1,181 +1,184 @@
# Check that people use the good file # Check that people use the good file
if(NOT TOP_CMAKE_WAS_SOURCED) if(NOT TOP_CMAKE_WAS_SOURCED)
message(FATAL_ERROR " message(FATAL_ERROR "
You did not 'cmake' the good CMakeLists.txt file. Use the one in the top dir. 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") It is advice to delete all wrongly generated cmake stuff => CMakeFiles & CMakeCache.txt")
endif(NOT TOP_CMAKE_WAS_SOURCED) endif(NOT TOP_CMAKE_WAS_SOURCED)
# library name # library name
set(Output Utilities) set(Output Utilities)
# set common flags # set common flags
set(CommonFlags set(CommonFlags
-pthread -pthread
-fvisibility=hidden -fvisibility=hidden
-fno-dse -fno-dse
-fno-guess-branch-probability -fno-guess-branch-probability
-fno-strict-aliasing -fno-strict-aliasing
-fno-tree-dse -fno-tree-dse
-pipe -pipe
-Wno-format -Wno-format
-Wno-unused-parameter -Wno-unused-parameter
-Wno-unused-value -Wno-unused-value
-Wunused-variable) -Wunused-variable)
# set warning flags # set warning flags
set(DebugFlags set(DebugFlags
-g -g
-W) -W)
# set optimization flags # set optimization flags
set(OptimizationFlags set(OptimizationFlags
-falign-functions -falign-functions
-falign-jumps -falign-jumps
-falign-labels -falign-labels
-falign-loops -falign-loops
-fcaller-saves -fcaller-saves
-fcprop-registers -fcprop-registers
-fcrossjumping -fcrossjumping
-fcse-follow-jumps -fcse-follow-jumps
-fcse-skip-blocks -fcse-skip-blocks
-fdefer-pop -fdefer-pop
-fdelete-null-pointer-checks -fdelete-null-pointer-checks
-fgcse -fgcse
-fgcse-lm -fgcse-lm
-fif-conversion -fif-conversion
-fif-conversion2 -fif-conversion2
-fmerge-constants -fmerge-constants
-foptimize-sibling-calls -foptimize-sibling-calls
-fpeephole2 -fpeephole2
-fregmove -fregmove
-freorder-blocks -freorder-blocks
-freorder-functions -freorder-functions
-frerun-cse-after-loop -frerun-cse-after-loop
-fsched-interblock -fsched-interblock
-fsched-spec -fsched-spec
-fstrict-overflow -fstrict-overflow
-fthread-jumps -fthread-jumps
-ftree-ccp -ftree-ccp
-ftree-ch -ftree-ch
-ftree-copyrename -ftree-copyrename
-ftree-dce -ftree-dce
-ftree-dominator-opts -ftree-dominator-opts
-ftree-fre -ftree-fre
-ftree-lrs -ftree-lrs
-ftree-pre -ftree-pre
-ftree-sra -ftree-sra
-ftree-ter -ftree-ter
-ftree-vrp -ftree-vrp
-funit-at-a-time) -funit-at-a-time)
# Debug - Build # Debug - Build
if(CMAKE_BUILD_TYPE STREQUAL Debug) if(CMAKE_BUILD_TYPE STREQUAL Debug)
# add defines # add defines
add_definitions(${CommonFlags} ${DebugFlags} -DPCSX2_DEBUG -DPCSX2_DEVBUILD) add_definitions(${CommonFlags} ${DebugFlags} -DPCSX2_DEBUG -DPCSX2_DEVBUILD)
endif(CMAKE_BUILD_TYPE STREQUAL Debug) endif(CMAKE_BUILD_TYPE STREQUAL Debug)
# Devel - Build # Devel - Build
if(CMAKE_BUILD_TYPE STREQUAL Devel) if(CMAKE_BUILD_TYPE STREQUAL Devel)
# add defines # add defines
add_definitions(${CommonFlags} ${OptimizationFlags} -DPCSX2_DEVBUILD) add_definitions(${CommonFlags} ${OptimizationFlags} -DPCSX2_DEVBUILD)
endif(CMAKE_BUILD_TYPE STREQUAL Devel) endif(CMAKE_BUILD_TYPE STREQUAL Devel)
# Release - Build # Release - Build
if(CMAKE_BUILD_TYPE STREQUAL Release) if(CMAKE_BUILD_TYPE STREQUAL Release)
# add defines # add defines
add_definitions(${CommonFlags} ${OptimizationFlags}) add_definitions(${CommonFlags} ${OptimizationFlags})
endif(CMAKE_BUILD_TYPE STREQUAL Release) endif(CMAKE_BUILD_TYPE STREQUAL Release)
# variable with all sources of this library # variable with all sources of this library
set(UtilitiesSources set(UtilitiesSources
../../include/Utilities/FixedPointTypes.inl ../../include/Utilities/FixedPointTypes.inl
../../include/Utilities/EventSource.inl ../../include/Utilities/EventSource.inl
../../include/Utilities/SafeArray.inl ../../include/Utilities/SafeArray.inl
../../include/Utilities/TlsVariable.inl ../../include/Utilities/TlsVariable.inl
AlignedMalloc.cpp AlignedMalloc.cpp
CheckedStaticBox.cpp CheckedStaticBox.cpp
Console.cpp Console.cpp
EventSource.cpp EventSource.cpp
Exceptions.cpp Exceptions.cpp
FastFormatString.cpp FastFormatString.cpp
HashTools.cpp HashTools.cpp
IniInterface.cpp IniInterface.cpp
Linux/LnxHostSys.cpp Linux/LnxHostSys.cpp
Linux/LnxMisc.cpp Linux/LnxMisc.cpp
Linux/LnxThreads.cpp Linux/LnxThreads.cpp
Mutex.cpp Mutex.cpp
PathUtils.cpp PathUtils.cpp
PrecompiledHeader.cpp PrecompiledHeader.cpp
pxCheckBox.cpp pxCheckBox.cpp
pxRadioPanel.cpp pxRadioPanel.cpp
pxStaticText.cpp pxStaticText.cpp
pxStreams.cpp pxStreams.cpp
pxTranslate.cpp pxTranslate.cpp
pxWindowTextWriter.cpp pxWindowTextWriter.cpp
Semaphore.cpp Semaphore.cpp
StringHelpers.cpp StringHelpers.cpp
ThreadingDialogs.cpp ThreadingDialogs.cpp
ThreadTools.cpp ThreadTools.cpp
vssprintf.cpp vssprintf.cpp
wxAppWithHelpers.cpp VirtualMemory.cpp
wxGuiTools.cpp wxAppWithHelpers.cpp
wxHelpers.cpp wxGuiTools.cpp
x86/MemcpyVibes.cpp wxHelpers.cpp
# x86/MemcpyFast.cpp x86/MemcpyVibes.cpp
) # x86/MemcpyFast.cpp
)
# collect .S files
set(UtilitiesSSources # collect .S files
x86/MemcpyFast.S) set(UtilitiesSSources
x86/MemcpyFast.S)
# variable with all headers of this library
set(UtilitiesHeaders # variable with all headers of this library
../../include/Utilities/Assertions.h set(UtilitiesHeaders
../../include/Utilities/CheckedStaticBox.h ../../include/Utilities/Assertions.h
../../include/Utilities/Console.h ../../include/Utilities/CheckedStaticBox.h
../../include/Utilities/Dependencies.h ../../include/Utilities/Console.h
../../include/Utilities/EventSource.h ../../include/Utilities/Dependencies.h
../../include/Utilities/Exceptions.h ../../include/Utilities/EventSource.h
../../include/Utilities/FixedPointTypes.h ../../include/Utilities/Exceptions.h
../../include/Utilities/General.h ../../include/Utilities/FixedPointTypes.h
../../include/Utilities/HashMap.h ../../include/Utilities/General.h
../../include/Utilities/lnx_memzero.h ../../include/Utilities/HashMap.h
../../include/Utilities/MemcpyFast.h ../../include/Utilities/lnx_memzero.h
../../include/Utilities/Path.h ../../include/Utilities/MemcpyFast.h
../../include/Utilities/pxCheckBox.h ../../include/Utilities/MemsetFast.inl
../../include/Utilities/pxRadioPanel.h ../../include/Utilities/Path.h
../../include/Utilities/pxStaticText.h ../../include/Utilities/PageFaultSource.h
../../include/Utilities/pxStreams.h ../../include/Utilities/pxCheckBox.h
../../include/Utilities/RedtapeWindows.h ../../include/Utilities/pxRadioPanel.h
../../include/Utilities/SafeArray.h ../../include/Utilities/pxStaticText.h
../../include/Utilities/ScopedAlloc.h ../../include/Utilities/pxStreams.h
../../include/Utilities/ScopedPtr.h ../../include/Utilities/RedtapeWindows.h
../../include/Utilities/ScopedPtrMT.h ../../include/Utilities/SafeArray.h
../../include/Utilities/StringHelpers.h ../../include/Utilities/ScopedAlloc.h
../../include/Utilities/Threading.h ../../include/Utilities/ScopedPtr.h
../../include/Utilities/ThreadingDialogs.h ../../include/Utilities/ScopedPtrMT.h
../../include/Utilities/TraceLog.h ../../include/Utilities/StringHelpers.h
../../include/Utilities/wxAppWithHelpers.h ../../include/Utilities/Threading.h
../../include/Utilities/wxBaseTools.h ../../include/Utilities/ThreadingDialogs.h
../../include/Utilities/wxGuiTools.h ../../include/Utilities/TraceLog.h
PrecompiledHeader.h) ../../include/Utilities/wxAppWithHelpers.h
../../include/Utilities/wxBaseTools.h
include_directories(.) ../../include/Utilities/wxGuiTools.h
PrecompiledHeader.h)
# change language of .S-files to c++
set_source_files_properties(${UtilitiesSSources} PROPERTIES LANGUAGE CXX) include_directories(.)
# add library # change language of .S-files to c++
add_library(${Output} STATIC ${UtilitiesSources} ${UtilitiesHeaders} ${UtilitiesSSources}) set_source_files_properties(${UtilitiesSSources} PROPERTIES LANGUAGE CXX)
# link target with wx # add library
target_link_libraries(${Output} ${wxWidgets_LIBRARIES}) add_library(${Output} STATIC ${UtilitiesSources} ${UtilitiesHeaders} ${UtilitiesSSources})
# User flags options # link target with wx
if(NOT USER_CMAKE_LD_FLAGS STREQUAL "") target_link_libraries(${Output} ${wxWidgets_LIBRARIES})
target_link_libraries(${Output} "${USER_CMAKE_LD_FLAGS}")
endif(NOT USER_CMAKE_LD_FLAGS STREQUAL "") # 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 "")

View File

@ -23,6 +23,9 @@
#include <signal.h> #include <signal.h>
#endif #endif
// for lack of a better place...
Fnptr_OutOfMemory pxDoOutOfMemory = NULL;
static wxString GetTranslation( const wxChar* msg ) static wxString GetTranslation( const wxChar* msg )
{ {
return msg ? wxGetTranslation( msg ) : wxEmptyString; 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) // Because wxTrap isn't available on Linux builds of wxWidgets (non-Debug, typically)
void pxTrap() void pxTrap()
{ {
@ -94,6 +91,16 @@ void pxTrap()
#endif // Win/Unix #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 ) DEVASSERT_INLINE void pxOnAssert( const DiagnosticOrigin& origin, const wxChar* msg )
{ {
// Recursion guard: Allow at least one recursive call. This is useful because sometimes // 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 ) Exception::OutOfMemory::OutOfMemory( const wxString& allocdesc )
{ {
AllocDescription = 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 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 wxString Exception::OutOfMemory::FormatDisplayMessage() const
{ {
if (m_message_user.IsEmpty()) return FormatDisplayMessage(); FastFormatUnicode retmsg;
return m_message_user + pxsFmt( L"\n\nInternal allocation descriptor: %s", AllocDescription.c_str()); 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; return L"Action canceled: " + m_message_diag;
} }
wxString Exception::Stream::FormatDiagnosticMessage() const // --------------------------------------------------------------------------------------
// Exception::BadStream (implementations)
// --------------------------------------------------------------------------------------
wxString Exception::BadStream::FormatDiagnosticMessage() const
{ {
return pxsFmt( FastFormatUnicode retval;
L"%s\n\tFile/Object: %s", _formatDiagMsg(retval);
m_message_diag.c_str(), StreamName.c_str() return retval;
);
} }
wxString Exception::Stream::FormatDisplayMessage() const wxString Exception::BadStream::FormatDisplayMessage() const
{ {
wxString retval( m_message_user ); FastFormatUnicode retval;
if (!StreamName.IsEmpty()) _formatUserMsg(retval);
retval += L"\n\n" + pxsFmt( _("Path: %s"), StreamName.c_str() ); 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; return retval;
} }
@ -249,7 +406,7 @@ BaseException* Exception::FromErrno( const wxString& streamname, int errcode )
{ {
case EINVAL: case EINVAL:
pxFailDev( L"Invalid argument" ); 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! case EACCES: // Access denied!
return new Exception::AccessDenied( streamname ); 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"); return &(new Exception::BadStream( streamname ))->SetDiagMsg(L"Bad file number");
default: 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 ));
} }
} }

View File

@ -55,7 +55,7 @@ protected:
typedef char CharType; typedef char CharType;
typedef CharBufferType BufferType; typedef CharBufferType BufferType;
static const uint BufferCount = 4; static const uint BufferCount = 6;
BufferType m_buffers[BufferCount]; BufferType m_buffers[BufferCount];
uint m_curslot; uint m_curslot;
@ -69,7 +69,7 @@ public:
for (uint i=0; i<BufferCount; ++i) for (uint i=0; i<BufferCount; ++i)
{ {
m_buffers[i].Alloc(1024); m_buffers[i].Alloc(512);
} }
m_curslot = 0; m_curslot = 0;
@ -174,7 +174,7 @@ static __ri void format_that_ascii_mess( CharBufferType& buffer, uint writepos,
len += writepos; len += writepos;
if (len < size) break; 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 // 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; len += writepos;
if (len < size) return len; 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 // performing an assertion or log of a truncated string is unsafe, so let's not; even

View File

@ -15,50 +15,204 @@
#include "../PrecompiledHeader.h" #include "../PrecompiledHeader.h"
#include "PageFaultSource.h"
#include <wx/thread.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <signal.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; pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr));
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;
} }
void Munmap(uptr base, u32 size) // Bad mojo! Completely invalid address.
{ // Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
munmap((uptr*)base, size);
}
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( case EINVAL:
L"Memory block size must be a multiple of the target platform's page size.\n" pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)",
L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)", baseaddr, (uptr)baseaddr+size, mode.ToString().c_str())
__pagesize, __pagesize, size, size ) );
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 );
} }
} }

View File

@ -143,7 +143,7 @@ wxString Path::Combine( const wxDirName& srcPath, const wxFileName& srcFile )
wxString Path::Combine( const wxString& srcPath, const wxDirName& 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. // Replaces the extension of the file with the one given.

View File

@ -118,6 +118,7 @@ wxString JoinString( const wxChar** src, const wxString& separator )
return dest; return dest;
} }
// Attempts to parse and return a value for the given template type, and throws a ParseError // 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/ // exception if the parse fails. The template type can be anything that is supported/
// implemented via one of the TryParse() method overloads. // implemented via one of the TryParse() method overloads.

View File

@ -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;
}

View File

@ -15,48 +15,124 @@
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#include "Utilities/RedtapeWindows.h" #include "Utilities/RedtapeWindows.h"
#include "PageFaultSource.h"
#include <winnt.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; Console.Warning("(MmapCommit) Received windows error %u {Virtual Memory Minimum Too Low}.", ERROR_COMMITMENT_MINIMUM);
VirtualFree((void*)base, size, MEM_DECOMMIT); Sleep(1000); // Cut windows some time to rework its memory...
VirtualFree((void*)base, 0, MEM_RELEASE); }
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( Exception::WinApiError apiError;
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)", apiError.SetDiagMsg(
__pagesize, __pagesize, size, size ) pxsFmt(L"VirtualProtect failed @ 0x%08X -> 0x%08X (mode=%s)",
); baseaddr, (uptr)baseaddr + size, mode.ToString().c_str()
));
DWORD winmode = 0; pxFailDev( apiError.FormatDiagnosticMessage() );
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 );
} }
} }

View File

@ -675,7 +675,7 @@ void wxAppWithHelpers::OnDeleteThread( wxCommandEvent& evt )
return; 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(); thr->RethrowException();
} }

View File

@ -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 // 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. // 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 ); xSetPtr( recSSE );
xFXSAVE( ptr[&targetFXSAVE] ); xFXSAVE( ptr[&targetFXSAVE] );
xRET(); xRET();
HostSys::MemProtectStatic( recSSE, Protect_ReadOnly, true ); HostSys::MemProtectStatic( recSSE, PageAccess_ExecOnly() );
CallAddress( recSSE ); CallAddress( recSSE );
@ -310,7 +310,7 @@ u32 x86capabilities::CalculateMHz() const
// Results of CPU // Results of CPU
void x86capabilities::SIMD_ExceptionTest() void x86capabilities::SIMD_ExceptionTest()
{ {
HostSys::MemProtectStatic( recSSE, Protect_ReadWrite, true ); HostSys::MemProtectStatic( recSSE, PageAccess_ReadWrite() );
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// SIMD Instruction Support Detection (Second Pass) // SIMD Instruction Support Detection (Second Pass)
@ -336,7 +336,7 @@ void x86capabilities::SIMD_ExceptionTest()
xMOVDQU( xmm1, ptr[ecx] ); xMOVDQU( xmm1, ptr[ecx] );
xRET(); xRET();
HostSys::MemProtectStatic( recSSE, Protect_ReadOnly, true ); HostSys::MemProtectStatic( recSSE, PageAccess_ExecOnly() );
bool sse3_result = _test_instruction( recSSE ); // sse3 bool sse3_result = _test_instruction( recSSE ); // sse3
bool ssse3_result = _test_instruction( funcSSSE3 ); bool ssse3_result = _test_instruction( funcSSSE3 );

View File

@ -78,7 +78,6 @@ bool isoFile::tryIsoType(u32 _size, s32 _offset, s32 _blockofs)
bool isoFile::Detect( bool readType ) bool isoFile::Detect( bool readType )
{ {
char buf[32]; char buf[32];
int len = m_filename.Length();
m_type = ISOTYPE_ILLEGAL; m_type = ISOTYPE_ILLEGAL;
@ -245,7 +244,7 @@ void isoFile::_WriteBlock(const u8* src, uint lsn)
void isoFile::_WriteBlockD(const u8* src, uint lsn) void isoFile::_WriteBlockD(const u8* src, uint lsn)
{ {
// Find and ignore blocks that have already been dumped: // 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; if (m_dtable[i] == lsn) return;
} }

View File

@ -383,7 +383,6 @@ set(pcsx2IPUHeaders
# Linux sources # Linux sources
set(pcsx2LinuxSources set(pcsx2LinuxSources
Linux/LnxHostSys.cpp
Linux/LnxKeyCodes.cpp) Linux/LnxKeyCodes.cpp)
# Linux headers # Linux headers
@ -432,7 +431,7 @@ set(pcsx2SystemSources
# System headers # System headers
set(pcsx2SystemHeaders set(pcsx2SystemHeaders
System/PageFaultSource.h System/RecTypes.h
System/SysThreads.h) System/SysThreads.h)
# Utilities sources # Utilities sources
@ -542,7 +541,6 @@ set(pcsx2x86Headers
x86/microVU_Tables.inl x86/microVU_Tables.inl
x86/microVU_Upper.inl x86/microVU_Upper.inl
x86/newVif.h x86/newVif.h
x86/newVif_BlockBuffer.h
x86/newVif_HashBucket.h x86/newVif_HashBucket.h
x86/newVif_UnpackSSE.h x86/newVif_UnpackSSE.h
x86/sVU_Compare.h x86/sVU_Compare.h

View File

@ -472,16 +472,16 @@ int GetPS2ElfName( wxString& name )
return 0; return 0;
} }
} }
catch (Exception::BadStream& ex)
{
Console.Error(ex.FormatDiagnosticMessage());
return 0; // ISO error
}
catch( Exception::FileNotFound& ) catch( Exception::FileNotFound& )
{ {
//Console.Warning(ex.FormatDiagnosticMessage()); //Console.Warning(ex.FormatDiagnosticMessage());
return 0; // no SYSTEM.CNF, not a PS1/PS2 disc. 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 #ifdef PCSX2_DEVBUILD
FILE *fp; FILE *fp;

View File

@ -26,6 +26,8 @@
#include "Vif_Dma.h" #include "Vif_Dma.h"
#include <limits.h> #include <limits.h>
#include "Utilities/MemsetFast.inl"
// the BP doesn't advance and returns -1 if there is no data to be read // the BP doesn't advance and returns -1 if there is no data to be read
__aligned16 tIPU_cmd ipu_cmd; __aligned16 tIPU_cmd ipu_cmd;
__aligned16 tIPU_BP g_BP; __aligned16 tIPU_BP g_BP;

View File

@ -33,6 +33,8 @@
#include "Mpeg.h" #include "Mpeg.h"
#include "Vlc.h" #include "Vlc.h"
#include "Utilities/MemsetFast.inl"
const int non_linear_quantizer_scale [] = const int non_linear_quantizer_scale [] =
{ {
0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,

View File

@ -24,48 +24,6 @@
#pragma once #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): // the IPU is fixed to 16 byte strides (128-bit / QWC resolution):
static const uint decoder_stride = 16; static const uint decoder_stride = 16;

View File

@ -359,11 +359,19 @@ void JALR()
} } } // end namespace R5900::Interpreter::OpcodeImpl } } } // end namespace R5900::Interpreter::OpcodeImpl
////////////////////////////////////////////////////////
// --------------------------------------------------------------------------------------
// R5900cpu/intCpu interface (implementations)
// --------------------------------------------------------------------------------------
static void intReserve()
{
// fixme : detect cpu for use the optimize asm code
}
static void intAlloc() static void intAlloc()
{ {
// fixme : detect cpu for use the optimize asm code // Nothing to do!
} }
static void intReset() static void intReset()
@ -419,19 +427,28 @@ static void intShutdown() {
static void intThrowException( const BaseR5900Exception& ex ) 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(); ex.Rethrow();
} }
static void intThrowException( const BaseException& ex ) 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(); ex.Rethrow();
} }
static void intSetCacheReserve( uint reserveInMegs )
{
}
static uint intGetCacheReserve()
{
return 0;
}
R5900cpu intCpu = R5900cpu intCpu =
{ {
intAlloc, intReserve,
intShutdown, intShutdown,
intReset, intReset,
@ -442,4 +459,7 @@ R5900cpu intCpu =
intThrowException, intThrowException,
intThrowException, intThrowException,
intClear, intClear,
intGetCacheReserve,
intSetCacheReserve,
}; };

View File

@ -24,26 +24,43 @@ IopVM_MemoryAllocMess* iopMem = NULL;
__pagealigned u8 iopHw[Ps2MemSize::IopHardware]; __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); void iopMemoryReserve::Reserve()
psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16); {
_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, // Note! Resetting the IOP's memory state is dependent on having *all* psx memory allocated,
// which is performed by MemInit and PsxMemInit() // which is performed by MemInit and PsxMemInit()
void psxMemReset() void iopMemoryReserve::Reset()
{ {
pxAssume( psxMemWLUT != NULL ); _parent::Reset();
pxAssume( iopMem != NULL );
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_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. // 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. // 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]; //for (i=0; i<0x0008; i++) psxMemWLUT[i + 0xbfc0] = (uptr)&psR[i << 16];
} }
void psxMemShutdown() void iopMemoryReserve::Decommit()
{ {
vtlb_free( iopMem, sizeof(*iopMem) ); _parent::Decommit();
iopMem = NULL;
safe_aligned_free(psxMemWLUT); safe_aligned_free(psxMemWLUT);
psxMemRLUT = NULL; psxMemRLUT = NULL;
iopMem = NULL;
} }
void iopMemoryReserve::Release()
{
_parent::Release();
iopMem = NULL;
}
u8 __fastcall iopMemRead8(u32 mem) u8 __fastcall iopMemRead8(u32 mem)
{ {
mem &= 0x1fffffff; mem &= 0x1fffffff;

View File

@ -71,6 +71,7 @@ static __fi u8* iopPhysMem( u32 addr )
#define psxHu16(mem) (*(u16*)&iopHw[(mem) & 0xffff]) #define psxHu16(mem) (*(u16*)&iopHw[(mem) & 0xffff])
#define psxHu32(mem) (*(u32*)&iopHw[(mem) & 0xffff]) #define psxHu32(mem) (*(u32*)&iopHw[(mem) & 0xffff])
extern void psxMemReserve();
extern void psxMemAlloc(); extern void psxMemAlloc();
extern void psxMemReset(); extern void psxMemReset();
extern void psxMemShutdown(); extern void psxMemShutdown();

View File

@ -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 ) {}

View File

@ -20,6 +20,8 @@
#include <gdk/gdkkeysyms.h> #include <gdk/gdkkeysyms.h>
#include <gdk/gdkx.h> #include <gdk/gdkx.h>
void NTFS_CompressFile( const wxString& file, bool compressStatus ) {}
// Returns a WXK_* keycode, given some kinda GDK input mess! // Returns a WXK_* keycode, given some kinda GDK input mess!
int TranslateGDKtoWXK( u32 keysym ) int TranslateGDKtoWXK( u32 keysym )
{ {

View File

@ -268,9 +268,7 @@
<Unit filename="../DebugTools/DisVUmicro.h" /> <Unit filename="../DebugTools/DisVUmicro.h" />
<Unit filename="../DebugTools/DisVUops.h" /> <Unit filename="../DebugTools/DisVUops.h" />
<Unit filename="../Dmac.h" /> <Unit filename="../Dmac.h" />
<Unit filename="../Docs/ChangeLog.txt" />
<Unit filename="../Docs/License.txt" /> <Unit filename="../Docs/License.txt" />
<Unit filename="../Docs/devblog.txt" />
<Unit filename="../Dump.cpp" /> <Unit filename="../Dump.cpp" />
<Unit filename="../Dump.h" /> <Unit filename="../Dump.h" />
<Unit filename="../Elfheader.cpp" /> <Unit filename="../Elfheader.cpp" />
@ -316,8 +314,6 @@
<Unit filename="../IopMem.h" /> <Unit filename="../IopMem.h" />
<Unit filename="../IopSio2.cpp" /> <Unit filename="../IopSio2.cpp" />
<Unit filename="../IopSio2.h" /> <Unit filename="../IopSio2.h" />
<Unit filename="../Ipu_fifo.h" />
<Unit filename="LnxHostSys.cpp" />
<Unit filename="LnxKeyCodes.cpp"> <Unit filename="LnxKeyCodes.cpp">
<Option compiler="gcc" use="1" buildCommand="$compiler $options $includes `pkg-config gtk+-2.0 --cflags` -c $file -o $object" /> <Option compiler="gcc" use="1" buildCommand="$compiler $options $includes `pkg-config gtk+-2.0 --cflags` -c $file -o $object" />
</Unit> </Unit>
@ -363,11 +359,10 @@
<Unit filename="../SourceLog.cpp" /> <Unit filename="../SourceLog.cpp" />
<Unit filename="../Stats.cpp" /> <Unit filename="../Stats.cpp" />
<Unit filename="../Stats.h" /> <Unit filename="../Stats.h" />
<Unit filename="../StringUtils.h" />
<Unit filename="../SysForwardDefs.h" /> <Unit filename="../SysForwardDefs.h" />
<Unit filename="../System.cpp" /> <Unit filename="../System.cpp" />
<Unit filename="../System.h" /> <Unit filename="../System.h" />
<Unit filename="../System/PageFaultSource.h" /> <Unit filename="../System/RecTypes.h" />
<Unit filename="../System/SysCoreThread.cpp" /> <Unit filename="../System/SysCoreThread.cpp" />
<Unit filename="../System/SysThreadBase.cpp" /> <Unit filename="../System/SysThreadBase.cpp" />
<Unit filename="../System/SysThreads.h" /> <Unit filename="../System/SysThreads.h" />
@ -421,7 +416,6 @@
<Unit filename="../gui/AppRes.cpp" /> <Unit filename="../gui/AppRes.cpp" />
<Unit filename="../gui/AppSaveStates.h" /> <Unit filename="../gui/AppSaveStates.h" />
<Unit filename="../gui/ApplyState.h" /> <Unit filename="../gui/ApplyState.h" />
<Unit filename="../gui/CheckedStaticBox.h" />
<Unit filename="../gui/ConsoleLogger.cpp" /> <Unit filename="../gui/ConsoleLogger.cpp" />
<Unit filename="../gui/ConsoleLogger.h" /> <Unit filename="../gui/ConsoleLogger.h" />
<Unit filename="../gui/CpuUsageProvider.cpp" /> <Unit filename="../gui/CpuUsageProvider.cpp" />
@ -449,7 +443,6 @@
<Unit filename="../gui/Dialogs/StuckThreadDialog.cpp" /> <Unit filename="../gui/Dialogs/StuckThreadDialog.cpp" />
<Unit filename="../gui/Dialogs/SysConfigDialog.cpp" /> <Unit filename="../gui/Dialogs/SysConfigDialog.cpp" />
<Unit filename="../gui/ExecutorThread.cpp" /> <Unit filename="../gui/ExecutorThread.cpp" />
<Unit filename="../gui/ExecutorThread.h" />
<Unit filename="../gui/FrameForGS.cpp" /> <Unit filename="../gui/FrameForGS.cpp" />
<Unit filename="../gui/GlobalCommands.cpp" /> <Unit filename="../gui/GlobalCommands.cpp" />
<Unit filename="../gui/IsoDropTarget.cpp" /> <Unit filename="../gui/IsoDropTarget.cpp" />
@ -466,7 +459,6 @@
<Unit filename="../gui/MessageBoxes.cpp" /> <Unit filename="../gui/MessageBoxes.cpp" />
<Unit filename="../gui/Panels/AudioPanel.cpp" /> <Unit filename="../gui/Panels/AudioPanel.cpp" />
<Unit filename="../gui/Panels/BaseApplicableConfigPanel.cpp" /> <Unit filename="../gui/Panels/BaseApplicableConfigPanel.cpp" />
<Unit filename="../gui/Panels/BaseConfigPanel.h" />
<Unit filename="../gui/Panels/BiosSelectorPanel.cpp" /> <Unit filename="../gui/Panels/BiosSelectorPanel.cpp" />
<Unit filename="../gui/Panels/ConfigurationPanels.h" /> <Unit filename="../gui/Panels/ConfigurationPanels.h" />
<Unit filename="../gui/Panels/CpuPanel.cpp" /> <Unit filename="../gui/Panels/CpuPanel.cpp" />
@ -572,10 +564,8 @@
<Unit filename="../gui/Saveslots.cpp" /> <Unit filename="../gui/Saveslots.cpp" />
<Unit filename="../gui/SysState.cpp" /> <Unit filename="../gui/SysState.cpp" />
<Unit filename="../gui/UpdateUI.cpp" /> <Unit filename="../gui/UpdateUI.cpp" />
<Unit filename="../gui/gsFrame.h" />
<Unit filename="../gui/i18n.cpp" /> <Unit filename="../gui/i18n.cpp" />
<Unit filename="../gui/i18n.h" /> <Unit filename="../gui/i18n.h" />
<Unit filename="../gui/pxEvtThread.h" />
<Unit filename="../gui/pxLogTextCtrl.cpp" /> <Unit filename="../gui/pxLogTextCtrl.cpp" />
<Unit filename="../ps2/BiosTools.cpp" /> <Unit filename="../ps2/BiosTools.cpp" />
<Unit filename="../ps2/BiosTools.h" /> <Unit filename="../ps2/BiosTools.h" />
@ -647,7 +637,6 @@
<Unit filename="../x86/microVU_Tables.inl" /> <Unit filename="../x86/microVU_Tables.inl" />
<Unit filename="../x86/microVU_Upper.inl" /> <Unit filename="../x86/microVU_Upper.inl" />
<Unit filename="../x86/newVif.h" /> <Unit filename="../x86/newVif.h" />
<Unit filename="../x86/newVif_BlockBuffer.h" />
<Unit filename="../x86/newVif_Dynarec.cpp" /> <Unit filename="../x86/newVif_Dynarec.cpp" />
<Unit filename="../x86/newVif_HashBucket.h" /> <Unit filename="../x86/newVif_HashBucket.h" />
<Unit filename="../x86/newVif_Unpack.cpp" /> <Unit filename="../x86/newVif_Unpack.cpp" />

View File

@ -40,11 +40,12 @@ BIOS
#include "IopCommon.h" #include "IopCommon.h"
#include "VUmicro.h" #include "VUmicro.h"
#include "GS.h" #include "GS.h"
#include "System/PageFaultSource.h"
#include "ps2/HwInternal.h" #include "ps2/HwInternal.h"
#include "ps2/BiosTools.h" #include "ps2/BiosTools.h"
#include "Utilities/PageFaultSource.h"
#ifdef ENABLECACHE #ifdef ENABLECACHE
#include "Cache.h" #include "Cache.h"
#endif #endif
@ -91,7 +92,6 @@ static vtlbHandler
null_handler, null_handler,
tlb_fallback_0, tlb_fallback_0,
tlb_fallback_1,
tlb_fallback_2, tlb_fallback_2,
tlb_fallback_3, tlb_fallback_3,
tlb_fallback_4, tlb_fallback_4,
@ -137,9 +137,9 @@ void memMapVUmicro()
void memMapPhy() void memMapPhy()
{ {
// Main memory // 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 // 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) // Various ROMs (all read-only)
vtlb_MapBlock(eeMem->ROM, 0x1fc00000,Ps2MemSize::Rom); vtlb_MapBlock(eeMem->ROM, 0x1fc00000,Ps2MemSize::Rom);
@ -153,14 +153,14 @@ void memMapPhy()
vtlb_MapBlock(iopMem->Main,0x1c000000,0x00800000); vtlb_MapBlock(iopMem->Main,0x1c000000,0x00800000);
// Generic Handlers; These fallback to mem* stuff... // Generic Handlers; These fallback to mem* stuff...
vtlb_MapHandler(tlb_fallback_7,0x14000000,0x10000); vtlb_MapHandler(tlb_fallback_7,0x14000000, _64kb);
vtlb_MapHandler(tlb_fallback_4,0x18000000,0x10000); vtlb_MapHandler(tlb_fallback_4,0x18000000, _64kb);
vtlb_MapHandler(tlb_fallback_5,0x1a000000,0x10000); vtlb_MapHandler(tlb_fallback_5,0x1a000000, _64kb);
vtlb_MapHandler(tlb_fallback_6,0x12000000,0x10000); vtlb_MapHandler(tlb_fallback_6,0x12000000, _64kb);
vtlb_MapHandler(tlb_fallback_8,0x1f000000,0x10000); vtlb_MapHandler(tlb_fallback_8,0x1f000000, _64kb);
vtlb_MapHandler(tlb_fallback_3,0x1f400000,0x10000); vtlb_MapHandler(tlb_fallback_3,0x1f400000, _64kb);
vtlb_MapHandler(tlb_fallback_2,0x1f800000,0x10000); vtlb_MapHandler(tlb_fallback_2,0x1f800000, _64kb);
vtlb_MapHandler(tlb_fallback_8,0x1f900000,0x10000); vtlb_MapHandler(tlb_fallback_8,0x1f900000, _64kb);
// Hardware Register Handlers : specialized/optimized per-page handling of HW register accesses // 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) // (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 //lower 512 mb: direct map
//vtlb_VMap(0x00000000,0x00000000,0x20000000); //vtlb_VMap(0x00000000,0x00000000,0x20000000);
//0x8* mirror //0x8* mirror
vtlb_VMap(0x80000000,0x00000000,0x20000000); vtlb_VMap(0x80000000, 0x00000000, _1mb*512);
//0xa* mirror //0xa* mirror
vtlb_VMap(0xA0000000,0x00000000,0x20000000); vtlb_VMap(0xA0000000, 0x00000000, _1mb*512);
} }
//what do do with these ? //what do do with these ?
@ -578,35 +578,15 @@ void memClearPageAddr(u32 vaddr)
class mmap_PageFaultHandler : public EventListener_PageFault class mmap_PageFaultHandler : public EventListener_PageFault
{ {
protected: public:
void OnPageFaultEvent( const PageFaultInfo& info, bool& handled ); void OnPageFaultEvent( const PageFaultInfo& info, bool& handled );
}; };
static mmap_PageFaultHandler mmap_faultHandler; static mmap_PageFaultHandler* mmap_faultHandler = NULL;
EEVM_MemoryAllocMess* eeMem = NULL; EEVM_MemoryAllocMess* eeMem = NULL;
__pagealigned u8 eeHw[Ps2MemSize::Hardware]; __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() 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 // 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 // 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 // rest of the emu is not really set up to support a "soft" reset of that sort
// we opt for the hard/safe version. // we opt for the hard/safe version.
pxAssume( eeMem != NULL ); pxAssume( eeMem );
memzero( *eeMem );
#ifdef ENABLECACHE #ifdef ENABLECACHE
memset(pCache,0,sizeof(_cacheS)*64); memset(pCache,0,sizeof(_cacheS)*64);
@ -761,9 +766,24 @@ void memReset()
LoadBIOS(); LoadBIOS();
} }
////////////////////////////////////////////////////////////////////////////////////////// void eeMemoryReserve::Decommit()
// Memory Protection and Block Checking, vtlb Style! {
// _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 // 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 // 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 // protection causes an *exception* to be raised (signal in Linux), which is handled by
@ -796,15 +816,17 @@ enum vtlb_ProtectionMode
struct vtlb_PageProtectionInfo struct vtlb_PageProtectionInfo
{ {
// Ram De-mapping -- used to convert fully translated/mapped offsets into psM back // Ram De-mapping -- used to convert fully translated/mapped offsets (which reside with
// into their originating ps2 physical ram address. Values are assigned when pages // in the eeMem->Main block) back into their originating ps2 physical ram address.
// are marked for protection. // 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; u32 ReverseRamMap;
vtlb_ProtectionMode Mode; vtlb_ProtectionMode Mode;
}; };
static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::Base >> 12]; static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::MainRam >> 12];
// returns: // returns:
@ -815,28 +837,33 @@ static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::Base >>
// //
int mmap_GetRamPageInfo( u32 paddr ) int mmap_GetRamPageInfo( u32 paddr )
{ {
pxAssume( eeMem );
paddr &= ~0xfff; paddr &= ~0xfff;
uptr ptr = (uptr)PSM( paddr ); uptr ptr = (uptr)PSM( paddr );
uptr rampage = ptr - (uptr)eeMem->Main; uptr rampage = ptr - (uptr)eeMem->Main;
if (rampage >= Ps2MemSize::Base) if (rampage >= Ps2MemSize::MainRam)
return -1; //not in ram, no tracking done ... return -1; //not in ram, no tracking done ...
rampage >>= 12; rampage >>= 12;
return ( m_PageProtectInfo[rampage].Mode == ProtMode_Manual ) ? 1 : 0; return ( m_PageProtectInfo[rampage].Mode == ProtMode_Manual ) ? 1 : 0;
} }
// paddr - physically mapped address // paddr - physically mapped PS2 address
void mmap_MarkCountedRamPage( u32 paddr ) void mmap_MarkCountedRamPage( u32 paddr )
{ {
pxAssume( eeMem );
paddr &= ~0xfff; paddr &= ~0xfff;
uptr ptr = (uptr)PSM( paddr ); uptr ptr = (uptr)PSM( paddr );
int rampage = (ptr - (uptr)eeMem->Main) >> 12; int rampage = (ptr - (uptr)eeMem->Main) >> 12;
// Important: reassign paddr here, since TLB changes could alter the paddr->psM mapping // Important: Update the ReverseRamMap here because TLB changes could alter the paddr
// (and clear blocks accordingly), but don't necessarily clear the protection status. // mapping into eeMem->Main.
m_PageProtectInfo[rampage].ReverseRamMap = paddr; m_PageProtectInfo[rampage].ReverseRamMap = paddr;
if( m_PageProtectInfo[rampage].Mode == ProtMode_Write ) if( m_PageProtectInfo[rampage].Mode == ProtMode_Write )
@ -848,7 +875,7 @@ void mmap_MarkCountedRamPage( u32 paddr )
); );
m_PageProtectInfo[rampage].Mode = ProtMode_Write; 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. // 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. // from code residing in this page will use manual protection.
static __fi void mmap_ClearCpuBlock( uint offset ) static __fi void mmap_ClearCpuBlock( uint offset )
{ {
pxAssume( eeMem );
int rampage = offset >> 12; int rampage = offset >> 12;
// Assertion: This function should never be run on a block that's already under // 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, pxAssertMsg( m_PageProtectInfo[rampage].Mode != ProtMode_Manual,
"Attempted to clear a block that is already under manual protection." ); "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; m_PageProtectInfo[rampage].Mode = ProtMode_Manual;
Cpu->Clear( m_PageProtectInfo[rampage].ReverseRamMap, 0x400 ); Cpu->Clear( m_PageProtectInfo[rampage].ReverseRamMap, 0x400 );
} }
void mmap_PageFaultHandler::OnPageFaultEvent( const PageFaultInfo& info, bool& handled ) void mmap_PageFaultHandler::OnPageFaultEvent( const PageFaultInfo& info, bool& handled )
{ {
pxAssume( eeMem );
// get bad virtual address // get bad virtual address
uptr offset = info.addr - (uptr)eeMem->Main; uptr offset = info.addr - (uptr)eeMem->Main;
if( offset >= Ps2MemSize::Base ) return; if( offset >= Ps2MemSize::MainRam ) return;
mmap_ClearCpuBlock( offset ); mmap_ClearCpuBlock( offset );
handled = true; handled = true;
@ -886,5 +917,5 @@ void mmap_ResetBlockTracking()
{ {
//DbgCon.WriteLn( "vtlb/mmap: Block Tracking reset..." ); //DbgCon.WriteLn( "vtlb/mmap: Block Tracking reset..." );
memzero( m_PageProtectInfo ); memzero( m_PageProtectInfo );
HostSys::MemProtect( eeMem->Main, Ps2MemSize::Base, Protect_ReadWrite ); if (eeMem) HostSys::MemProtect( eeMem->Main, Ps2MemSize::MainRam, PageAccess_ReadWrite() );
} }

View File

@ -24,6 +24,10 @@
#include <xmmintrin.h> #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 ) static __fi void CopyQWC( void* dest, const void* src )
{ {
_mm_store_ps( (float*)dest, _mm_load_ps((const float*)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 psSu64(mem) (*(u64 *)&eeMem->Scratch[(mem) & 0x3fff])
#define psSu128(mem) (*(u128*)&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 memSetKernelMode();
//extern void memSetSupervisorMode(); //extern void memSetSupervisorMode();
extern void memSetUserMode(); extern void memSetUserMode();

View File

@ -17,18 +17,18 @@
namespace Ps2MemSize namespace Ps2MemSize
{ {
static const uint Base = 0x02000000; // 32 MB main memory! static const uint MainRam = _32mb; // 32 MB main memory!
static const uint Rom = 0x00400000; // 4 MB main rom static const uint Rom = _1mb * 4; // 4 MB main rom
static const uint Rom1 = 0x00040000; // DVD player static const uint Rom1 = 0x00040000; // DVD player
static const uint Rom2 = 0x00080000; // Chinese rom extension (?) static const uint Rom2 = 0x00080000; // Chinese rom extension (?)
static const uint ERom = 0x001C0000; // DVD player extensions (?) static const uint ERom = 0x001C0000; // DVD player extensions (?)
static const uint Hardware = 0x00010000; static const uint Hardware = _64kb;
static const uint Scratch = 0x00004000; static const uint Scratch = _16kb;
static const uint IopRam = 0x00200000; // 2MB main ram on the IOP. static const uint IopRam = _1mb * 2; // 2MB main ram on the IOP.
static const uint IopHardware = 0x00010000; 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; 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 // 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. // 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 #define VTLB_UsePageFaulting 0
#if VTLB_UsePageFaulting #if VTLB_UsePageFaulting
@ -61,9 +64,9 @@ typedef u128 mem128_t;
// full breadth of PS2 RAM and ROM mappings are directly supported. // full breadth of PS2 RAM and ROM mappings are directly supported.
struct EEVM_MemoryAllocMess 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 (&ROM1)[Ps2MemSize::Rom1]; // DVD player
u8 _padding2[0x1e040000-(0x1e000000+Ps2MemSize::Rom1)] u8 _padding2[0x1e040000-(0x1e000000+Ps2MemSize::Rom1)]
@ -80,8 +83,8 @@ struct EEVM_MemoryAllocMess
struct EEVM_MemoryAllocMess struct EEVM_MemoryAllocMess
{ {
u8 Main[Ps2MemSize::MainRam]; // Main memory (hard-wired to 32MB)
u8 Scratch[Ps2MemSize::Scratch]; // Scratchpad! u8 Scratch[Ps2MemSize::Scratch]; // Scratchpad!
u8 Main[Ps2MemSize::Base]; // Main memory (hard-wired to 32MB)
u8 ROM[Ps2MemSize::Rom]; // Boot rom (4MB) u8 ROM[Ps2MemSize::Rom]; // Boot rom (4MB)
u8 ROM1[Ps2MemSize::Rom1]; // DVD player u8 ROM1[Ps2MemSize::Rom1]; // DVD player
u8 ROM2[Ps2MemSize::Rom2]; // Chinese extensions u8 ROM2[Ps2MemSize::Rom2]; // Chinese extensions
@ -101,7 +104,7 @@ struct EEVM_MemoryAllocMess
struct IopVM_MemoryAllocMess struct IopVM_MemoryAllocMess
{ {
u8 Main[Ps2MemSize::IopRam]; // Main memory (hard-wired to 2MB) 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) u8 Sif[0x100]; // a few special SIF/SBUS registers (likely not needed)
}; };

View File

@ -674,18 +674,34 @@ SysCorePlugins *g_plugins = NULL;
// Plugin-related Exception Implementations // 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 ) Exception::PluginOpenError::PluginOpenError( PluginsEnum_t pid )
{ {
PluginId = pid; PluginId = pid;
m_message_diag = L"%s plugin failed to open!"; 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 ) Exception::PluginInitError::PluginInitError( PluginsEnum_t pid )
{ {
PluginId = pid; PluginId = pid;
m_message_diag = L"%s plugin initialization failed!"; 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 ) Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid )
@ -695,29 +711,29 @@ Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid )
wxString Exception::PluginLoadError::FormatDiagnosticMessage() const 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; L"\n\n" + StreamName;
} }
wxString Exception::PluginLoadError::FormatDisplayMessage() const 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; L"\n\n" + StreamName;
} }
wxString Exception::PluginError::FormatDiagnosticMessage() const 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 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 wxString Exception::FreezePluginFailure::FormatDiagnosticMessage() const
{ {
return wxsFormat( return pxsFmt(
L"%s plugin returned an error while saving the state.\n\n", L"%s plugin returned an error while saving the state.\n\n",
tbl_PluginInfo[PluginId].shortname tbl_PluginInfo[PluginId].shortname
); );
@ -731,7 +747,7 @@ wxString Exception::FreezePluginFailure::FormatDisplayMessage() const
wxString Exception::ThawPluginFailure::FormatDiagnosticMessage() const wxString Exception::ThawPluginFailure::FormatDiagnosticMessage() const
{ {
return wxsFormat( return pxsFmt(
L"%s plugin returned an error while loading the state.\n\n", L"%s plugin returned an error while loading the state.\n\n",
tbl_PluginInfo[PluginId].shortname tbl_PluginInfo[PluginId].shortname
); );
@ -1262,7 +1278,7 @@ void SysCorePlugins::Init( PluginsEnum_t pid )
if( !m_info[pid] || m_info[pid]->IsInitialized ) return; if( !m_info[pid] || m_info[pid]->IsInitialized ) return;
Console.Indent().WriteLn( "Init %s", tbl_PluginInfo[pid].shortname ); 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 ); throw Exception::PluginInitError( pid );
m_info[pid]->IsInitialized = true; m_info[pid]->IsInitialized = true;

View File

@ -57,12 +57,15 @@ namespace Exception
// Exception thrown when a corrupted or truncated savestate is encountered. // Exception thrown when a corrupted or truncated savestate is encountered.
class SaveStateLoadError : public BadStream 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 class PluginError : public RuntimeError
{ {
DEFINE_RUNTIME_EXCEPTION( PluginError, RuntimeError, L"Generic plugin error") DEFINE_RUNTIME_EXCEPTION( PluginError, RuntimeError, L"Generic plugin error!" )
public: public:
PluginsEnum_t PluginId; PluginsEnum_t PluginId;

View File

@ -102,14 +102,9 @@ typedef int BOOL;
typedef void FnType_Void(); typedef void FnType_Void();
typedef FnType_Void* Fnptr_Void; typedef FnType_Void* Fnptr_Void;
static const s64 _1mb = 0x100000; // --------------------------------------------------------------------------------------
static const s64 _8mb = _1mb * 8; // Compiler/OS specific macros and defines
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
// Linux isn't set up for svn version numbers yet. // Linux isn't set up for svn version numbers yet.
#ifdef __LINUX__ #ifdef __LINUX__

View File

@ -178,16 +178,20 @@ extern bool iopEventTestIsActive;
// Branching status used when throwing exceptions. // Branching status used when throwing exceptions.
extern bool iopIsDelaySlot; extern bool iopIsDelaySlot;
//////////////////////////////////////////////////////////////////// // --------------------------------------------------------------------------------------
// R3000A Public Interface / API // R3000Acpu
// --------------------------------------------------------------------------------------
struct R3000Acpu { struct R3000Acpu {
void (*Allocate)(); void (*Reserve)();
void (*Reset)(); void (*Reset)();
void (*Execute)(); void (*Execute)();
s32 (*ExecuteBlock)( s32 eeCycles ); // executes the given number of EE cycles. s32 (*ExecuteBlock)( s32 eeCycles ); // executes the given number of EE cycles.
void (*Clear)(u32 Addr, u32 Size); void (*Clear)(u32 Addr, u32 Size);
void (*Shutdown)(); void (*Shutdown)();
uint (*GetCacheReserve)();
void (*SetCacheReserve)( uint reserveInMegs );
}; };
extern R3000Acpu *psxCpu; extern R3000Acpu *psxCpu;

View File

@ -150,10 +150,14 @@ static void doBranch(s32 tar) {
iopEventTest(); iopEventTest();
} }
static void intReserve() {
}
static void intAlloc() { static void intAlloc() {
} }
static void intReset() { static void intReset() {
intAlloc();
} }
static void intExecute() { static void intExecute() {
@ -180,11 +184,23 @@ static void intClear(u32 Addr, u32 Size) {
static void intShutdown() { static void intShutdown() {
} }
static void intSetCacheReserve( uint reserveInMegs )
{
}
static uint intGetCacheReserve()
{
return 0;
}
R3000Acpu psxInt = { R3000Acpu psxInt = {
intAlloc, intReserve,
intReset, intReset,
intExecute, intExecute,
intExecuteBlock, intExecuteBlock,
intClear, intClear,
intShutdown intShutdown,
intGetCacheReserve,
intSetCacheReserve
}; };

View File

@ -32,7 +32,6 @@
#include "CDVD/CDVD.h" #include "CDVD/CDVD.h"
#include "Patch.h" #include "Patch.h"
#include "GameDatabase.h" #include "GameDatabase.h"
#include "SamplProf.h"
using namespace R5900; // for R5900 disasm tools using namespace R5900; // for R5900 disasm tools
@ -51,14 +50,14 @@ static const uint eeWaitCycles = 3072;
bool eeEventTestIsActive = false; bool eeEventTestIsActive = false;
extern SysMainMemory& GetVmMemory();
void cpuReset() void cpuReset()
{ {
if( GetMTGS().IsOpen() ) if (GetMTGS().IsOpen())
GetMTGS().WaitGS(); // GS better be done processing before we reset the EE, just in case. GetMTGS().WaitGS(); // GS better be done processing before we reset the EE, just in case.
memReset(); GetVmMemory().ResetAll();
psxMemReset();
vuMicroMemReset();
memzero(cpuRegs); memzero(cpuRegs);
memzero(fpuRegs); memzero(fpuRegs);

View File

@ -273,25 +273,25 @@ extern void __fastcall eeloadReplaceOSDSYS();
struct R5900cpu struct R5900cpu
{ {
// Memory allocation function, for allocating virtual memory spaces needed by // Memory allocation function, for allocating virtual memory spaces needed by
// the emulator. (ints/recs are free to allocate additional memory while running // the virtual cpu provider. Allocating additional heap memory from this method is
// code, however any virtual mapped memory should always be allocated as soon // NOT recommended. Heap allocations should be performed by Reset only. This
// as possible, to claim the memory before some plugin does..) // maximizes the likeliness of reservations claiming addresses they prefer.
// //
// Thread Affinity: // Thread Affinity:
// Can be called from any thread. Execute status must be suspended or stopped // Called from the main/UI thread only. Cpu execution status is guaranteed to
// to prevent multi-thread race conditions. // be inactive. No locking is necessary.
// //
// Exception Throws: // 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 // OutOfMemory - Not enough memory, or the memory areas required were already
// reserved. // reserved.
// void (*Reserve)();
void (*Allocate)();
// 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: // Thread Affinity:
// Can be called from any thread. Execute status must be suspended or stopped // Called from the main/UI thread only. Cpu execution status is guaranteed to
// to prevent multi-thread race conditions. // be inactive. No locking is necessary.
// //
// Exception Throws: None. This function is a destructor, and should not throw. // 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. // rely on the CPU/VM states almost entirely.
// //
// Thread Affinity: // Thread Affinity:
// Can be called from any thread. Execute status must be suspended or stopped // Can be called from any thread. CPU execution status is indeterminate and may
// to prevent multi-thread race conditions. // 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 // Exception Throws: Emulator-defined. Common exception types to expect are
// OutOfMemory, Stream Exceptions // OutOfMemory, Stream Exceptions
@ -365,7 +367,7 @@ struct R5900cpu
// better off replaced with some generic API callbacks from VTLB block protection. // 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 // 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 // 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: // Thread Affinity Rule:
// Can be called from any thread (namely for being called from debugging threads) // 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. ;) // doesn't matter if we're stripping it out soon. ;)
// //
void (*Clear)(u32 Addr, u32 Size); void (*Clear)(u32 Addr, u32 Size);
uint (*GetCacheReserve)();
void (*SetCacheReserve)( uint reserveInMegs );
}; };
extern R5900cpu *Cpu; extern R5900cpu *Cpu;

View File

@ -30,6 +30,10 @@ void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz);
void ProfilerRegisterSource(const char* Name, const void* function); void ProfilerRegisterSource(const char* Name, const void* function);
void ProfilerTerminateSource( const char* Name ); 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 #else
// Disables the profiler in Debug & Linux builds. // Disables the profiler in Debug & Linux builds.

View File

@ -48,7 +48,7 @@ static void PostLoadPrep()
wxString SaveStateBase::GetFilename( int slot ) wxString SaveStateBase::GetFilename( int slot )
{ {
return (g_Conf->Folders.Savestates + 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 ) SaveStateBase::SaveStateBase( SafeArray<u8>& memblock )
@ -142,7 +142,7 @@ void SaveStateBase::FreezeBios()
} }
static const int MainMemorySizeInBytes = static const int MainMemorySizeInBytes =
Ps2MemSize::Base + Ps2MemSize::Scratch + Ps2MemSize::Hardware + Ps2MemSize::MainRam + Ps2MemSize::Scratch + Ps2MemSize::Hardware +
Ps2MemSize::IopRam + Ps2MemSize::IopHardware + 0x0100; Ps2MemSize::IopRam + Ps2MemSize::IopHardware + 0x0100;
void SaveStateBase::FreezeMainMemory() void SaveStateBase::FreezeMainMemory()
@ -152,7 +152,7 @@ void SaveStateBase::FreezeMainMemory()
// First Block - Memory Dumps // 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(eeMem->Scratch, Ps2MemSize::Scratch); // scratch pad
FreezeMem(eeHw, Ps2MemSize::Hardware); // hardware memory FreezeMem(eeHw, Ps2MemSize::Hardware); // hardware memory

View File

@ -16,44 +16,144 @@
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#include "Common.h" #include "Common.h"
#include "IopCommon.h" #include "IopCommon.h"
#include "VUmicro.h"
#include "newVif.h"
#include "System/PageFaultSource.h" #include "SamplProf.h"
#include "Utilities/EventSource.inl"
// Includes needed for cleanup, since we don't have a good system (yet) for // Includes needed for cleanup, since we don't have a good system (yet) for
// cleaning up these things. // cleaning up these things.
#include "sVU_zerorec.h"
#include "GameDatabase.h" #include "GameDatabase.h"
#include "Elfheader.h" #include "Elfheader.h"
extern void closeNewVif(int idx); #include "System/RecTypes.h"
extern void resetNewVif(int idx);
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; if (m_profiler_name.IsEmpty() || !IsOk()) return;
_parent::Dispatch( params ); 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 { if (m_profiler_registered)
(*iter)->DispatchEvent( evt, m_handled ); ProfilerTerminateSource( m_profiler_name );
} while( (++iter != iend) && !m_handled ); }
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 { try {
MyCpu = new CpuType(); MyCpu = new CpuType();
MyCpu->Allocate(); MyCpu->Reserve();
} }
catch( Exception::RuntimeError& ex ) catch( Exception::RuntimeError& ex )
{ {
@ -209,7 +309,7 @@ CpuInitializer< CpuType >::CpuInitializer()
template< typename CpuType > template< typename CpuType >
CpuInitializer< CpuType >::~CpuInitializer() throw() CpuInitializer< CpuType >::~CpuInitializer() throw()
{ {
if( MyCpu ) if (MyCpu)
MyCpu->Shutdown(); 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 ReleaseAll();
{
vuMicroMemShutdown();
psxMemShutdown();
memShutdown();
vtlb_Core_Shutdown();
}
DESTRUCTOR_CATCHALL
} }
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 (implementations)
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
SysCpuProviderPack::SysCpuProviderPack() SysCpuProviderPack::SysCpuProviderPack()
{ {
Console.WriteLn( "Allocating memory for recompilers..." ); Console.WriteLn( Color_StrongBlue, "Reserving memory for recompilers..." );
ConsoleIndentScope indent(1);
CpuProviders = new CpuInitializerSet(); CpuProviders = new CpuInitializerSet();
try { try {
recCpu.Allocate(); recCpu.Reserve();
} }
catch( Exception::RuntimeError& ex ) catch( Exception::RuntimeError& ex )
{ {
m_RecExceptionEE = ex.Clone(); 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(); recCpu.Shutdown();
} }
try { try {
psxRec.Allocate(); psxRec.Reserve();
} }
catch( Exception::RuntimeError& ex ) catch( Exception::RuntimeError& ex )
{ {
m_RecExceptionIOP = ex.Clone(); 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(); psxRec.Shutdown();
} }
// hmm! : VU0 and VU1 pre-allocations should do sVU and mVU separately? Sounds complicated. :( // 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(); } bool SysCpuProviderPack::IsRecAvailable_MicroVU0() const { return CpuProviders->microVU0.IsAvailable(); }
@ -353,12 +485,6 @@ void SysCpuProviderPack::CleanupMess() throw()
{ {
try try
{ {
closeNewVif(0);
closeNewVif(1);
// Special SuperVU "complete" terminator (stupid hacky recompiler)
SuperVUDestroy( -1 );
psxRec.Shutdown(); psxRec.Shutdown();
recCpu.Shutdown(); recCpu.Shutdown();
} }
@ -418,15 +544,13 @@ void SysClearExecutionCache()
{ {
GetCpuProviders().ApplyConfig(); 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(); Cpu->Reset();
psxCpu->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) if (CHECK_EEREC)
((BaseVUmicroCPU*)GetCpuProviders().CpuProviders->microVU0)->Reset(); ((BaseVUmicroCPU*)GetCpuProviders().CpuProviders->microVU0)->Reset();
CpuVU0->Reset(); CpuVU0->Reset();
CpuVU1->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( (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 ); 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 // Let's try again at an OS-picked memory area, and then hope it meets needed
// with NULL (let the OS pick something for us). // boundschecking criteria below.
SafeSysMunmap( Mem, size ); SafeSysMunmap( Mem, size );
Mem = (u8*)HostSys::Mmap( 0, size );
Mem = (u8*)HostSys::Mmap( NULL, 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 ); DevCon.Warning( "Second try failed allocating %s, block ptr 0x%x does not meet required criteria.", caller, Mem );
SafeSysMunmap( Mem, size ); SafeSysMunmap( Mem, size );
@ -481,5 +603,5 @@ wxString SysGetDiscID()
// region and revision). // region and revision).
} }
return wxsFormat( L"%8.8x", ElfCRC ); return pxsFmt( L"%08x", ElfCRC );
} }

View File

@ -21,8 +21,81 @@
#include "Utilities/Threading.h" // to use threading stuff, include the Threading namespace in your file. #include "Utilities/Threading.h" // to use threading stuff, include the Threading namespace in your file.
#include "CDVD/CDVDaccess.h" #include "CDVD/CDVDaccess.h"
#include "vtlb.h"
typedef SafeArray<u8> VmStateBuffer; typedef SafeArray<u8> VmStateBuffer;
class BaseVUmicroCPU; 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 // SysAllocVM
@ -83,6 +156,7 @@ extern SysCpuProviderPack& GetCpuProviders();
extern void SysLogMachineCaps(); // Detects cpu type and fills cpuInfo structs. extern void SysLogMachineCaps(); // Detects cpu type and fills cpuInfo structs.
extern void SysClearExecutionCache(); // clears recompiled execution caches! 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 u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed");
extern void vSyncDebugStuff( uint frame ); extern void vSyncDebugStuff( uint frame );
@ -90,6 +164,8 @@ extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true );
extern wxString SysGetDiscID(); extern wxString SysGetDiscID();
extern SysMainMemory& GetVmMemory();
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// PCSX2_SEH - Defines existence of "built in" Structured Exception Handling support. // PCSX2_SEH - Defines existence of "built in" Structured Exception Handling support.
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------

View File

@ -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;

68
pcsx2/System/RecTypes.h Normal file
View File

@ -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;
};

View File

@ -22,9 +22,9 @@
#include "GS.h" #include "GS.h"
#include "Elfheader.h" #include "Elfheader.h"
#include "Patch.h" #include "Patch.h"
#include "PageFaultSource.h"
#include "SysThreads.h" #include "SysThreads.h"
#include "Utilities/PageFaultSource.h"
#include "Utilities/TlsVariable.inl" #include "Utilities/TlsVariable.inl"
#ifdef __WXMSW__ #ifdef __WXMSW__
@ -111,13 +111,24 @@ void SysCoreThread::SetElfOverride( const wxString& elf )
Hle_SetElfPath(elf.ToUTF8()); 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(); Suspend();
m_resetVirtualMachine = true; m_resetVirtualMachine = true;
m_hasActiveMachine = false; m_hasActiveMachine = false;
} }
void SysCoreThread::Reset()
{
ResetQuick();
GetVmMemory().DecommitAll();
SysClearExecutionCache();
}
// Applies a full suite of new settings, which will automatically facilitate the necessary // 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 // 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 // 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 // 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 // resets aren't in fact *needed* ... yet. But might as well, no harm. --air
GetVmMemory().CommitAll();
if( m_resetVirtualMachine || m_resetRecompilers || m_resetProfilers ) if( m_resetVirtualMachine || m_resetRecompilers || m_resetProfilers )
{ {
SysClearExecutionCache(); SysClearExecutionCache();

View File

@ -184,6 +184,7 @@ public:
virtual void OnResumeReady(); virtual void OnResumeReady();
virtual void Reset(); virtual void Reset();
virtual void ResetQuick();
virtual void Cancel( bool isBlocking=true ); virtual void Cancel( bool isBlocking=true );
virtual bool Cancel( const wxTimeSpan& timeout ); virtual bool Cancel( const wxTimeSpan& timeout );

View File

@ -19,15 +19,15 @@
#include "VUops.h" #include "VUops.h"
#include "R5900.h" #include "R5900.h"
static const uint VU0_MEMSIZE = 0x1000; static const uint VU0_MEMSIZE = 0x1000; // 4kb
static const uint VU0_PROGSIZE = 0x1000; static const uint VU0_PROGSIZE = 0x1000; // 4kb
static const uint VU1_MEMSIZE = 0x4000; static const uint VU1_MEMSIZE = 0x4000; // 16kb
static const uint VU1_PROGSIZE = 0x4000; static const uint VU1_PROGSIZE = 0x4000; // 16kb
static const uint VU0_MEMMASK = VU0_MEMSIZE-1; static const uint VU0_MEMMASK = VU0_MEMSIZE-1;
static const uint VU0_PROGMASK = VU0_PROGSIZE-1; static const uint VU0_PROGMASK = VU0_PROGSIZE-1;
static const uint VU1_MEMMASK = VU1_MEMSIZE-1; static const uint VU1_MEMMASK = VU1_MEMSIZE-1;
static const uint VU1_PROGMASK = VU1_PROGSIZE-1; static const uint VU1_PROGMASK = VU1_PROGSIZE-1;
#define vuRunCycles (512*12) // Cycles to run ExecuteBlockJIT() for (called from within recs) #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 #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 class BaseCpuProvider
{ {
protected: protected:
// allocation counter for multiple init/shutdown calls // allocation counter for multiple calls to Reserve. Most implementations should utilize
// (most or all implementations will need this!) // this variable for sake of robustness.
int m_AllocCount; u32 m_Reserved;
public: public:
// this boolean indicates to some generic logging facilities if the VU's registers // this boolean indicates to some generic logging facilities if the VU's registers
@ -60,19 +60,27 @@ public:
public: public:
BaseCpuProvider() BaseCpuProvider()
{ {
m_AllocCount = 0; m_Reserved = 0;
} }
virtual ~BaseCpuProvider() throw() virtual ~BaseCpuProvider() throw()
{ {
if( m_AllocCount != 0 ) if( m_Reserved != 0 )
Console.Warning( "Cleanup miscount detected on CPU provider. Count=%d", m_AllocCount ); Console.Warning( "Cleanup miscount detected on CPU provider. Count=%d", m_Reserved );
} }
virtual const char* GetShortName() const=0; virtual const char* GetShortName() const=0;
virtual wxString GetLongName() 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 Shutdown()=0;
virtual void Reset()=0; virtual void Reset()=0;
virtual void Execute(u32 cycles)=0; virtual void Execute(u32 cycles)=0;
@ -88,6 +96,15 @@ public:
{ {
cpu->Execute(1024); 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"; } const char* GetShortName() const { return "intVU0"; }
wxString GetLongName() const { return L"VU0 Interpreter"; } wxString GetLongName() const { return L"VU0 Interpreter"; }
void Allocate() { } void Reserve() { }
void Shutdown() throw() { } void Shutdown() throw() { }
void Reset() { } void Reset() { }
void Step(); void Step();
void Execute(u32 cycles); void Execute(u32 cycles);
void Clear(u32 addr, u32 size) {} void Clear(u32 addr, u32 size) {}
uint GetCacheReserve() const { return 0; }
void SetCacheReserve( uint reserveInMegs ) const {}
}; };
class InterpVU1 : public BaseVUmicroCPU class InterpVU1 : public BaseVUmicroCPU
@ -167,13 +187,16 @@ public:
const char* GetShortName() const { return "intVU1"; } const char* GetShortName() const { return "intVU1"; }
wxString GetLongName() const { return L"VU1 Interpreter"; } wxString GetLongName() const { return L"VU1 Interpreter"; }
void Allocate() { } void Reserve() { }
void Shutdown() throw() { } void Shutdown() throw() { }
void Reset() { } void Reset() { }
void Step(); void Step();
void Execute(u32 cycles); void Execute(u32 cycles);
void Clear(u32 addr, u32 size) {} 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"; } const char* GetShortName() const { return "mVU0"; }
wxString GetLongName() const { return L"microVU0 Recompiler"; } wxString GetLongName() const { return L"microVU0 Recompiler"; }
void Allocate(); void Reserve();
void Shutdown() throw(); void Shutdown() throw();
void Reset(); void Reset();
void Execute(u32 cycles); void Execute(u32 cycles);
void Clear(u32 addr, u32 size); void Clear(u32 addr, u32 size);
void Vsync() throw(); void Vsync() throw();
uint GetCacheReserve() const;
void SetCacheReserve( uint reserveInMegs ) const;
}; };
class recMicroVU1 : public BaseVUmicroCPU class recMicroVU1 : public BaseVUmicroCPU
@ -206,12 +232,15 @@ public:
const char* GetShortName() const { return "mVU1"; } const char* GetShortName() const { return "mVU1"; }
wxString GetLongName() const { return L"microVU1 Recompiler"; } wxString GetLongName() const { return L"microVU1 Recompiler"; }
void Allocate(); void Reserve();
void Shutdown() throw(); void Shutdown() throw();
void Reset(); void Reset();
void Execute(u32 cycles); void Execute(u32 cycles);
void Clear(u32 addr, u32 size); void Clear(u32 addr, u32 size);
void Vsync() throw(); void Vsync() throw();
uint GetCacheReserve() const;
void SetCacheReserve( uint reserveInMegs ) const;
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -226,11 +255,14 @@ public:
const char* GetShortName() const { return "sVU0"; } const char* GetShortName() const { return "sVU0"; }
wxString GetLongName() const { return L"SuperVU0 Recompiler"; } wxString GetLongName() const { return L"SuperVU0 Recompiler"; }
void Allocate(); void Reserve();
void Shutdown() throw(); void Shutdown() throw();
void Reset(); void Reset();
void Execute(u32 cycles); void Execute(u32 cycles);
void Clear(u32 Addr, u32 Size); void Clear(u32 Addr, u32 Size);
uint GetCacheReserve() const;
void SetCacheReserve( uint reserveInMegs ) const;
}; };
class recSuperVU1 : public BaseVUmicroCPU class recSuperVU1 : public BaseVUmicroCPU
@ -241,21 +273,20 @@ public:
const char* GetShortName() const { return "sVU1"; } const char* GetShortName() const { return "sVU1"; }
wxString GetLongName() const { return L"SuperVU1 Recompiler"; } wxString GetLongName() const { return L"SuperVU1 Recompiler"; }
void Allocate(); void Reserve();
void Shutdown() throw(); void Shutdown() throw();
void Reset(); void Reset();
void Execute(u32 cycles); void Execute(u32 cycles);
void Clear(u32 Addr, u32 Size); void Clear(u32 Addr, u32 Size);
uint GetCacheReserve() const;
void SetCacheReserve( uint reserveInMegs ) const;
}; };
extern BaseVUmicroCPU* CpuVU0; extern BaseVUmicroCPU* CpuVU0;
extern BaseVUmicroCPU* CpuVU1; extern BaseVUmicroCPU* CpuVU1;
extern void vuMicroMemAlloc();
extern void vuMicroMemShutdown();
extern void vuMicroMemReset();
// VU0 // VU0
extern void vu0ResetRegs(); extern void vu0ResetRegs();
extern void __fastcall vu0ExecMicro(u32 addr); extern void __fastcall vu0ExecMicro(u32 addr);

View File

@ -18,43 +18,41 @@
#include "Common.h" #include "Common.h"
#include "VUmicro.h" #include "VUmicro.h"
__aligned16 VURegs vuRegs[2]; __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 ); u8* curpos = m_reserve.GetPtr();
m_vuAllMem = NULL; 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 ); _parent::Release();
pxAssume( VU1.Mem != NULL );
VU0.Micro = VU0.Mem = NULL;
VU1.Micro = VU1.Mem = NULL;
}
void vuMemoryReserve::Reset()
{
_parent::Reset();
pxAssume( VU0.Mem );
pxAssume( VU1.Mem );
memMapVUmicro(); memMapVUmicro();
@ -67,8 +65,6 @@ void vuMicroMemReset()
VU0.VF[0].f.z = 0.0f; VU0.VF[0].f.z = 0.0f;
VU0.VF[0].f.w = 1.0f; VU0.VF[0].f.w = 1.0f;
VU0.VI[0].UL = 0; VU0.VI[0].UL = 0;
memzero_ptr<4*1024>(VU0.Mem);
memzero_ptr<4*1024>(VU0.Micro);
// === VU1 Initialization === // === VU1 Initialization ===
memzero(VU1.ACC); memzero(VU1.ACC);
@ -79,8 +75,6 @@ void vuMicroMemReset()
VU1.VF[0].f.z = 0.0f; VU1.VF[0].f.z = 0.0f;
VU1.VF[0].f.w = 1.0f; VU1.VF[0].f.w = 1.0f;
VU1.VI[0].UL = 0; VU1.VI[0].UL = 0;
memzero_ptr<16*1024>(VU1.Mem);
memzero_ptr<16*1024>(VU1.Micro);
} }
void SaveStateBase::vuMicroFreeze() void SaveStateBase::vuMicroFreeze()

View File

@ -107,6 +107,7 @@ enum MenuIdentifiers
MenuId_Config_SysSettings, MenuId_Config_SysSettings,
MenuId_Config_McdSettings, MenuId_Config_McdSettings,
MenuId_Config_AppSettings, MenuId_Config_AppSettings,
MenuId_Config_GameDatabase,
MenuId_Config_BIOS, MenuId_Config_BIOS,
// Plugin ID order is important. Must match the order in tbl_PluginInfo. // Plugin ID order is important. Must match the order in tbl_PluginInfo.
@ -475,7 +476,7 @@ public:
// blocked threads stalling the GUI. // blocked threads stalling the GUI.
ExecutorThread SysExecutorThread; ExecutorThread SysExecutorThread;
ScopedPtr<SysCpuProviderPack> m_CpuProviders; ScopedPtr<SysCpuProviderPack> m_CpuProviders;
ScopedPtr<SysAllocVM> m_VmAllocs; ScopedPtr<SysMainMemory> m_VmReserve;
protected: protected:
wxWindowID m_id_MainFrame; wxWindowID m_id_MainFrame;
@ -497,6 +498,8 @@ public:
void SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override=wxEmptyString ); void SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override=wxEmptyString );
void LogicalVsync(); void LogicalVsync();
SysMainMemory& GetVmReserve();
GSFrame& GetGsFrame() const; GSFrame& GetGsFrame() const;
MainEmuFrame& GetMainFrame() const; MainEmuFrame& GetMainFrame() const;
@ -526,8 +529,6 @@ public:
void StartPendingSave(); void StartPendingSave();
void ClearPendingSave(); void ClearPendingSave();
void AllocateVM();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// App-wide Resources // App-wide Resources
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------

View File

@ -19,89 +19,80 @@
#include <wx/stackwalk.h> #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 ) static wxString pxGetStackTrace( const FnChar_t* calledFrom )
{ {
wxString stackTrace; StackDump dump( calledFrom );
dump.Walk( 3 );
class StackDump : public wxStackWalker return dump.GetStackTrace();
{
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();
} }
#ifdef __WXDEBUG__ #ifdef __WXDEBUG__

View File

@ -109,6 +109,17 @@ void AppCoreThread::Reset()
_parent::Reset(); _parent::Reset();
} }
void AppCoreThread::ResetQuick()
{
if( !GetSysExecutorThread().IsSelf() )
{
GetSysExecutorThread().PostEvent( SysExecEvent_InvokeCoreThreadMethod(&AppCoreThread::ResetQuick) );
return;
}
_parent::ResetQuick();
}
ExecutorThread& GetSysExecutorThread() ExecutorThread& GetSysExecutorThread()
{ {
return wxGetApp().SysExecutorThread; return wxGetApp().SysExecutorThread;
@ -183,7 +194,6 @@ void Pcsx2App::SysApplySettings()
void AppCoreThread::OnResumeReady() void AppCoreThread::OnResumeReady()
{ {
wxGetApp().SysApplySettings(); wxGetApp().SysApplySettings();
wxGetApp().AllocateVM();
wxGetApp().PostMethod( AppSaveSettings ); wxGetApp().PostMethod( AppSaveSettings );
_parent::OnResumeReady(); _parent::OnResumeReady();
} }

View File

@ -134,6 +134,7 @@ public:
virtual void Suspend( bool isBlocking=false ); virtual void Suspend( bool isBlocking=false );
virtual void Resume(); virtual void Resume();
virtual void Reset(); virtual void Reset();
virtual void ResetQuick();
virtual void Cancel( bool isBlocking=true ); virtual void Cancel( bool isBlocking=true );
virtual bool StateCheckInThread(); virtual bool StateCheckInThread();
virtual void ChangeCdvdSource(); virtual void ChangeCdvdSource();

View File

@ -163,6 +163,12 @@ public:
// this second layer class to act as a bridge between the event system and the class's // this second layer class to act as a bridge between the event system and the class's
// handler implementations. // 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 > template< typename TypeToDispatchTo >
class EventListenerHelper_CoreThread : public EventListener_CoreThread class EventListenerHelper_CoreThread : public EventListener_CoreThread
@ -212,9 +218,9 @@ public:
protected: protected:
void CorePlugins_OnLoaded() { Owner.OnCorePlugins_Loaded(); } void CorePlugins_OnLoaded() { Owner.OnCorePlugins_Loaded(); }
void CorePlugins_OnInit() { Owner.OnCorePlugins_Init(); } 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_OnOpened() { Owner.OnCorePlugins_Opened(); }
void CorePlugins_OnClosing() { Owner.OnCorePlugins_Closing(); } void CorePlugins_OnClosing() { Owner.OnCorePlugins_Closing(); }
void CorePlugins_OnClosed() { Owner.OnCorePlugins_Closed(); } void CorePlugins_OnClosed() { Owner.OnCorePlugins_Closed(); }
void CorePlugins_OnShutdown() { Owner.OnCorePlugins_Shutdown(); } void CorePlugins_OnShutdown() { Owner.OnCorePlugins_Shutdown(); }
void CorePlugins_OnUnloaded() { Owner.OnCorePlugins_Unloaded(); } void CorePlugins_OnUnloaded() { Owner.OnCorePlugins_Unloaded(); }

View File

@ -238,12 +238,6 @@ void Pcsx2App::OpenProgramLog()
if( m_current_focus ) m_current_focus->SetFocus(); if( m_current_focus ) m_current_focus->SetFocus();
} }
void Pcsx2App::AllocateVM()
{
if (m_VmAllocs) return;
m_VmAllocs = new SysAllocVM();
}
void Pcsx2App::AllocateCoreStuffs() void Pcsx2App::AllocateCoreStuffs()
{ {
if( AppRpc_TryInvokeAsync( &Pcsx2App::AllocateCoreStuffs ) ) return; if( AppRpc_TryInvokeAsync( &Pcsx2App::AllocateCoreStuffs ) ) return;
@ -252,6 +246,8 @@ void Pcsx2App::AllocateCoreStuffs()
SysLogMachineCaps(); SysLogMachineCaps();
AppApplySettings(); AppApplySettings();
GetVmReserve().ReserveAll();
if( !m_CpuProviders ) if( !m_CpuProviders )
{ {
// FIXME : Some or all of SysCpuProviderPack should be run from the SysExecutor thread, // 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() ) 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; recOps.EnableEE = false;
} }
if( BaseException* ex = m_CpuProviders->GetException_IOP() ) 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; recOps.EnableIOP = false;
} }
if( BaseException* ex = m_CpuProviders->GetException_MicroVU0() ) 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.UseMicroVU0 = false;
recOps.EnableVU0 = recOps.EnableVU0 && m_CpuProviders->IsRecAvailable_SuperVU0(); recOps.EnableVU0 = recOps.EnableVU0 && m_CpuProviders->IsRecAvailable_SuperVU0();
} }
if( BaseException* ex = m_CpuProviders->GetException_MicroVU1() ) 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.UseMicroVU1 = false;
recOps.EnableVU1 = recOps.EnableVU1 && m_CpuProviders->IsRecAvailable_SuperVU1(); recOps.EnableVU1 = recOps.EnableVU1 && m_CpuProviders->IsRecAvailable_SuperVU1();
} }
if( BaseException* ex = m_CpuProviders->GetException_SuperVU0() ) 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.UseMicroVU0 = m_CpuProviders->IsRecAvailable_MicroVU0();
recOps.EnableVU0 = recOps.EnableVU0 && recOps.UseMicroVU0; recOps.EnableVU0 = recOps.EnableVU0 && recOps.UseMicroVU0;
} }
if( BaseException* ex = m_CpuProviders->GetException_SuperVU1() ) 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.UseMicroVU1 = m_CpuProviders->IsRecAvailable_MicroVU1();
recOps.EnableVU1 = recOps.EnableVU1 && recOps.UseMicroVU1; recOps.EnableVU1 = recOps.EnableVU1 && recOps.UseMicroVU1;
} }
@ -525,12 +521,15 @@ bool Pcsx2App::OnInit()
InitCPUTicks(); InitCPUTicks();
pxDoAssert = AppDoAssert; pxDoAssert = AppDoAssert;
pxDoOutOfMemory = SysOutOfMemory_EmergencyResponse;
g_Conf = new AppConfig(); g_Conf = new AppConfig();
wxInitAllImageHandlers(); wxInitAllImageHandlers();
Console.WriteLn("Begin parsing commandline..."); Console.WriteLn("Command line parsing...");
if( !_parent::OnInit() ) return false; if( !_parent::OnInit() ) return false;
Console.WriteLn("Command line parsed!");
wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() ); wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
@ -815,12 +814,12 @@ void Pcsx2App::CleanUp()
__fi wxString AddAppName( const wxChar* fmt ) __fi wxString AddAppName( const wxChar* fmt )
{ {
return wxsFormat( fmt, pxGetAppName().c_str() ); return pxsFmt( fmt, pxGetAppName().c_str() );
} }
__fi wxString AddAppName( const char* fmt ) __fi wxString AddAppName( const char* fmt )
{ {
return wxsFormat( fromUTF8(fmt), pxGetAppName().c_str() ); return pxsFmt( fromUTF8(fmt), pxGetAppName().c_str() );
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------

View File

@ -702,6 +702,12 @@ void Pcsx2App::PostIdleAppMethod( FnPtr_Pcsx2App method )
AddIdleEvent( evt ); AddIdleEvent( evt );
} }
SysMainMemory& Pcsx2App::GetVmReserve()
{
if (!m_VmReserve) m_VmReserve = new SysMainMemory();
return *m_VmReserve;
}
void Pcsx2App::OpenGsPanel() void Pcsx2App::OpenGsPanel()
{ {
if( AppRpc_TryInvoke( &Pcsx2App::OpenGsPanel ) ) return; if( AppRpc_TryInvoke( &Pcsx2App::OpenGsPanel ) ) return;
@ -851,7 +857,7 @@ protected:
DbgCon.WriteLn( Color_Gray, "(SysExecute) received." ); DbgCon.WriteLn( Color_Gray, "(SysExecute) received." );
CoreThread.Reset(); CoreThread.ResetQuick();
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso ); CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
if( m_UseCDVDsrc ) if( m_UseCDVDsrc )
@ -930,6 +936,11 @@ MainEmuFrame* GetMainFramePtr()
return wxTheApp ? wxGetApp().GetMainFramePtr() : NULL; return wxTheApp ? wxGetApp().GetMainFramePtr() : NULL;
} }
SysMainMemory& GetVmMemory()
{
return wxGetApp().GetVmReserve();
}
SysCoreThread& GetCoreThread() SysCoreThread& GetCoreThread()
{ {
return CoreThread; return CoreThread;

View File

@ -193,7 +193,7 @@ void ConsoleLogFrame::ColorArray::Create( int fontsize )
new (&m_table[Color_StrongCyan]) wxTextAttr( wxNullColour, wxNullColour, fixedB ); new (&m_table[Color_StrongCyan]) wxTextAttr( wxNullColour, wxNullColour, fixedB );
new (&m_table[Color_StrongYellow]) wxTextAttr( wxNullColour, wxNullColour, fixedB ); new (&m_table[Color_StrongYellow]) wxTextAttr( wxNullColour, wxNullColour, fixedB );
new (&m_table[Color_StrongWhite]) wxTextAttr( wxNullColour, wxNullColour, fixedB ); new (&m_table[Color_StrongWhite]) wxTextAttr( wxNullColour, wxNullColour, fixedB );
SetColorScheme_Light(); SetColorScheme_Light();
} }
@ -281,10 +281,10 @@ enum MenuIDs_t
MenuId_FontSize_Normal, MenuId_FontSize_Normal,
MenuId_FontSize_Large, MenuId_FontSize_Large,
MenuId_FontSize_Huge, MenuId_FontSize_Huge,
MenuId_ColorScheme_Light = 0x20, MenuId_ColorScheme_Light = 0x20,
MenuId_ColorScheme_Dark, MenuId_ColorScheme_Dark,
MenuId_LogSource_EnableAll = 0x30, MenuId_LogSource_EnableAll = 0x30,
MenuId_LogSource_DisableAll, MenuId_LogSource_DisableAll,
MenuId_LogSource_Devel, MenuId_LogSource_Devel,
@ -322,7 +322,7 @@ public:
} }
}; };
static ConsoleLogSource* const ConLogSources[] = static ConsoleLogSource* const ConLogSources[] =
{ {
(ConsoleLogSource*)&SysConsole.eeConsole, (ConsoleLogSource*)&SysConsole.eeConsole,
(ConsoleLogSource*)&SysConsole.iopConsole, (ConsoleLogSource*)&SysConsole.iopConsole,
@ -334,7 +334,7 @@ static ConsoleLogSource* const ConLogSources[] =
(ConsoleLogSource*)&pxConLog_Thread, (ConsoleLogSource*)&pxConLog_Thread,
}; };
static const bool ConLogDefaults[] = static const bool ConLogDefaults[] =
{ {
true, true,
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.Append( MenuId_LogSource_Devel, _("Dev/Verbose"), _("Shows PCSX2 developer logs"), wxITEM_CHECK );
menuSources.AppendSeparator(); menuSources.AppendSeparator();
uint srcnt = ArraySize(ConLogSources); uint srcnt = ArraySize(ConLogSources);
for (uint i=0; i<srcnt; ++i) 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 // 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. // include a secondary check to avoid having a colorful log spam killing gui responsiveness.
if( m_CurQueuePos > 0x100000 || m_QueueColorSection.GetLength() > 256 ) if( m_CurQueuePos > 0x100000 || m_QueueColorSection.GetLength() > 256 )
{ {
++m_WaitingThreadsForFlush; ++m_WaitingThreadsForFlush;
@ -629,7 +629,7 @@ bool ConsoleLogFrame::Write( ConsoleColors color, const wxString& text )
if( m_WaitingThreadsForFlush != 0 ) --m_WaitingThreadsForFlush; if( m_WaitingThreadsForFlush != 0 ) --m_WaitingThreadsForFlush;
} }
} }
return false; 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( 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 (!pxAssertDev( ConLogSources[srcid] != NULL, "Invalid source log index (NULL pointer [separator])" )) return;
if( wxMenuItem* item = GetMenuBar()->FindItem(evt.GetId()) ) if( wxMenuItem* item = GetMenuBar()->FindItem(evt.GetId()) )
{ {
pxAssertDev( item->IsCheckable(), "Uncheckable log source menu item? Seems fishy!" ); pxAssertDev( item->IsCheckable(), "Uncheckable log source menu item? Seems fishy!" );
@ -926,7 +926,7 @@ void ConsoleLogFrame::DoFlushQueue()
// cap at 512k for now... // cap at 512k for now...
// fixme - 512k runs well on win32 but appears to be very sluggish on linux (but that could // 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 // be a result of my using Xming + CoLinux). Might need platform dependent defaults here. --air
static const int BufferSize = 0x80000; static const int BufferSize = 0x80000;
if( (insertPoint + m_CurQueuePos) > BufferSize ) if( (insertPoint + m_CurQueuePos) > BufferSize )
{ {
@ -1040,6 +1040,8 @@ const IConsoleWriter ConsoleWriter_File =
ConsoleToFile_DoWrite, ConsoleToFile_DoWrite,
ConsoleToFile_Newline, ConsoleToFile_Newline,
ConsoleToFile_SetTitle, ConsoleToFile_SetTitle,
0
}; };
Mutex& Pcsx2App::GetProgramLogLock() Mutex& Pcsx2App::GetProgramLogLock()
@ -1111,6 +1113,8 @@ static const IConsoleWriter ConsoleWriter_Window =
ConsoleToWindow_DoWrite<ConsoleWriter_Stdout>, ConsoleToWindow_DoWrite<ConsoleWriter_Stdout>,
ConsoleToWindow_Newline<ConsoleWriter_Stdout>, ConsoleToWindow_Newline<ConsoleWriter_Stdout>,
ConsoleToWindow_SetTitle<ConsoleWriter_Stdout>, ConsoleToWindow_SetTitle<ConsoleWriter_Stdout>,
0
}; };
static const IConsoleWriter ConsoleWriter_WindowAndFile = static const IConsoleWriter ConsoleWriter_WindowAndFile =
@ -1122,6 +1126,8 @@ static const IConsoleWriter ConsoleWriter_WindowAndFile =
ConsoleToWindow_DoWrite<ConsoleWriter_File>, ConsoleToWindow_DoWrite<ConsoleWriter_File>,
ConsoleToWindow_Newline<ConsoleWriter_File>, ConsoleToWindow_Newline<ConsoleWriter_File>,
ConsoleToWindow_SetTitle<ConsoleWriter_File>, ConsoleToWindow_SetTitle<ConsoleWriter_File>,
0
}; };
void Pcsx2App::EnableAllLogging() void Pcsx2App::EnableAllLogging()

View File

@ -56,7 +56,7 @@ DefaultCpuUsageProvider::DefaultCpuUsageProvider()
void DefaultCpuUsageProvider::Reset() void DefaultCpuUsageProvider::Reset()
{ {
for( int i=0; i<QueueDepth; ++i ) for( uint i=0; i<QueueDepth; ++i )
m_queue[i].LoadWithCurrentTimes(); m_queue[i].LoadWithCurrentTimes();
} }

View File

@ -39,7 +39,7 @@ bool MsgButtons::Allows( wxWindowID id ) const
// [TODO] : maybe add in an Ignore All? // [TODO] : maybe add in an Ignore All?
case wxID_IGNORE: return HasIgnore(); case wxID_IGNORE: return HasIgnore();
case wxID_RESET: return HasReset(); case wxID_RESET: return HasReset();
case wxID_CLOSE: return HasClose(); case wxID_CLOSE: return HasClose();
} }
@ -94,7 +94,7 @@ static wxWindowID ParseThatResult( const wxString& src, const MsgButtons& validT
wxID_ANY, 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)) ) if( (validTypes.Allows( retvals[i] )) && (src == ResultToString(retvals[i], validTypes)) )
return retvals[i]; return retvals[i];

View File

@ -21,8 +21,6 @@ Dialogs::GameDatabaseDialog::GameDatabaseDialog(wxWindow* parent)
: BaseConfigurationDialog( parent, AddAppName(_("Game Database - %s")), 580 ) : BaseConfigurationDialog( parent, AddAppName(_("Game Database - %s")), 580 )
{ {
ScopedBusyCursor busy( Cursor_ReallyBusy ); ScopedBusyCursor busy( Cursor_ReallyBusy );
*this += new Panels::GameDatabasePanel(this); *this += new Panels::GameDatabasePanel(this);
AddOkCancel(); AddOkCancel();
} }

View File

@ -155,6 +155,7 @@ void MainEmuFrame::ConnectMenus()
ConnectMenu( MenuId_Config_SysSettings, Menu_SysSettings_Click ); ConnectMenu( MenuId_Config_SysSettings, Menu_SysSettings_Click );
ConnectMenu( MenuId_Config_McdSettings, Menu_McdSettings_Click ); ConnectMenu( MenuId_Config_McdSettings, Menu_McdSettings_Click );
ConnectMenu( MenuId_Config_AppSettings, Menu_WindowSettings_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_BIOS, Menu_SelectPluginsBios_Click );
ConnectMenu( MenuId_Config_ResetAll, Menu_ResetAllSettings_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_SysSettings, _("Emulation &Settings") );
m_menuConfig.Append(MenuId_Config_McdSettings, _("&Memory cards") ); 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.AppendSeparator();
m_menuConfig.Append(MenuId_Config_GS, _("&Video (GS)"), m_PluginMenuPacks[PluginId_GS]); m_menuConfig.Append(MenuId_Config_GS, _("&Video (GS)"), m_PluginMenuPacks[PluginId_GS]);

View File

@ -162,6 +162,7 @@ protected:
void Menu_SysSettings_Click(wxCommandEvent &event); void Menu_SysSettings_Click(wxCommandEvent &event);
void Menu_McdSettings_Click(wxCommandEvent &event); void Menu_McdSettings_Click(wxCommandEvent &event);
void Menu_GameDatabase_Click(wxCommandEvent &event);
void Menu_WindowSettings_Click(wxCommandEvent &event); void Menu_WindowSettings_Click(wxCommandEvent &event);
void Menu_GSSettings_Click(wxCommandEvent &event); void Menu_GSSettings_Click(wxCommandEvent &event);
void Menu_SelectPluginsBios_Click(wxCommandEvent &event); void Menu_SelectPluginsBios_Click(wxCommandEvent &event);

View File

@ -48,6 +48,11 @@ void MainEmuFrame::Menu_McdSettings_Click(wxCommandEvent &event)
AppOpenDialog<McdConfigDialog>( this ); AppOpenDialog<McdConfigDialog>( this );
} }
void MainEmuFrame::Menu_GameDatabase_Click(wxCommandEvent &event)
{
AppOpenDialog<McdConfigDialog>( this );
}
void MainEmuFrame::Menu_WindowSettings_Click(wxCommandEvent &event) void MainEmuFrame::Menu_WindowSettings_Click(wxCommandEvent &event)
{ {
wxCommandEvent evt( pxEvt_SetSettingsPage ); wxCommandEvent evt( pxEvt_SetSettingsPage );

View File

@ -1,189 +1,189 @@
/* PCSX2 - PS2 Emulator for PCs /* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team * Copyright (C) 2002-2010 PCSX2 Dev Team
* *
* PCSX2 is free software: you can redistribute it and/or modify it under the terms * 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- * 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. * 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; * 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 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details. * 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. * You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#include "App.h" #include "App.h"
#include "AppGameDatabase.h" #include "AppGameDatabase.h"
#include "ConfigurationPanels.h" #include "ConfigurationPanels.h"
extern wxString DiscSerial; extern wxString DiscSerial;
using namespace pxSizerFlags; using namespace pxSizerFlags;
#define blankLine() { \ #define blankLine() { \
sizer1+=5; sizer1+=5; sizer1+=Text(L""); sizer1+=5; sizer1+=5; \ sizer1+=5; sizer1+=5; sizer1+=Text(L""); sizer1+=5; sizer1+=5; \
} }
#define placeTextBox(wxBox, txt) { \ #define placeTextBox(wxBox, txt) { \
sizer1 += Label(_(txt)); \ sizer1 += Label(_(txt)); \
sizer1 += 5; \ sizer1 += 5; \
sizer1 += wxBox | pxCenter; \ sizer1 += wxBox | pxCenter; \
sizer1 += 5; \ sizer1 += 5; \
sizer1 += 5; \ sizer1 += 5; \
} }
wxTextCtrl* CreateMultiLineTextCtrl( wxWindow* parent, int digits, long flags = 0 ) wxTextCtrl* CreateMultiLineTextCtrl( wxWindow* parent, int digits, long flags = 0 )
{ {
wxTextCtrl* ctrl = new wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); wxTextCtrl* ctrl = new wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
pxFitToDigits(ctrl, digits); pxFitToDigits(ctrl, digits);
return ctrl; return ctrl;
} }
Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent ) Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent )
: BaseApplicableConfigPanel( parent ) : BaseApplicableConfigPanel( parent )
{ {
IGameDatabase* GameDB = AppHost_GetGameDatabase(); IGameDatabase* GameDB = AppHost_GetGameDatabase();
pxAssume( GameDB != NULL ); pxAssume( GameDB != NULL );
searchBtn = new wxButton (this, wxID_ANY, _("Search")); searchBtn = new wxButton (this, wxID_ANY, _("Search"));
serialBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT); serialBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
nameBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT); nameBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
regionBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT); regionBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
compatBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT); compatBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
commentBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT); commentBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT);
patchesBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT); patchesBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT);
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
gameFixes[i] = new pxCheckBox(this, EnumToString(i), wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER ); gameFixes[i] = new pxCheckBox(this, EnumToString(i), wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER );
*this += Heading(_("Game Database Editor")).Bold() | StdExpand(); *this += Heading(_("Game Database Editor")).Bold() | StdExpand();
*this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand(); //*this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand();
wxFlexGridSizer& sizer1(*new wxFlexGridSizer(5, StdPadding)); wxFlexGridSizer& sizer1(*new wxFlexGridSizer(5, StdPadding));
sizer1.AddGrowableCol(0); sizer1.AddGrowableCol(0);
blankLine(); blankLine();
sizer1 += Label(L"Serial: "); sizer1 += Label(L"Serial: ");
sizer1 += 5; sizer1 += 5;
sizer1 += serialBox | pxCenter; sizer1 += serialBox | pxCenter;
sizer1 += 5; sizer1 += 5;
sizer1 += searchBtn; sizer1 += searchBtn;
placeTextBox(nameBox, "Name: "); placeTextBox(nameBox, "Name: ");
placeTextBox(regionBox, "Region: "); placeTextBox(regionBox, "Region: ");
placeTextBox(compatBox, "Compatibility: "); placeTextBox(compatBox, "Compatibility: ");
placeTextBox(commentBox, "Comments: "); placeTextBox(commentBox, "Comments: ");
placeTextBox(patchesBox, "Patches: "); placeTextBox(patchesBox, "Patches: ");
blankLine(); blankLine();
wxStaticBoxSizer& sizer2 = *new wxStaticBoxSizer(wxVERTICAL, this, _("Gamefixes")); wxStaticBoxSizer& sizer2 = *new wxStaticBoxSizer(wxVERTICAL, this, _("Gamefixes"));
wxFlexGridSizer& sizer3(*new wxFlexGridSizer(3, 0, StdPadding*4)); wxFlexGridSizer& sizer3(*new wxFlexGridSizer(3, 0, StdPadding*4));
sizer3.AddGrowableCol(0); sizer3.AddGrowableCol(0);
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
sizer3 += gameFixes[i]; sizer3 += gameFixes[i];
sizer2 += sizer3 | StdCenter(); sizer2 += sizer3 | StdCenter();
*this += sizer1 | pxCenter; *this += sizer1 | pxCenter;
*this += sizer2 | pxCenter; *this += sizer2 | pxCenter;
Connect(searchBtn->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(GameDatabasePanel::Search_Click)); Connect(searchBtn->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(GameDatabasePanel::Search_Click));
PopulateFields(); PopulateFields();
} }
void Panels::GameDatabasePanel::PopulateFields( const wxString& id ) { void Panels::GameDatabasePanel::PopulateFields( const wxString& id ) {
IGameDatabase* GameDB = AppHost_GetGameDatabase(); IGameDatabase* GameDB = AppHost_GetGameDatabase();
if (!pxAssert(GameDB)) return; if (!pxAssert(GameDB)) return;
Game_Data game; Game_Data game;
if (GameDB->findGame(game, id.IsEmpty() ? SysGetDiscID() : id)) if (GameDB->findGame(game, id.IsEmpty() ? SysGetDiscID() : id))
{ {
serialBox ->SetLabel(game.getString("Serial")); serialBox ->SetLabel(game.getString("Serial"));
nameBox ->SetLabel(game.getString("Name")); nameBox ->SetLabel(game.getString("Name"));
regionBox ->SetLabel(game.getString("Region")); regionBox ->SetLabel(game.getString("Region"));
compatBox ->SetLabel(game.getString("Compat")); compatBox ->SetLabel(game.getString("Compat"));
commentBox->SetLabel(game.getString("[comments]")); commentBox->SetLabel(game.getString("[comments]"));
patchesBox->SetLabel(game.getString("[patches]")); patchesBox->SetLabel(game.getString("[patches]"));
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
{ {
wxString keyName (EnumToString(i)); keyName += L"Hack"; wxString keyName (EnumToString(i)); keyName += L"Hack";
if( game.keyExists(keyName) ) if( game.keyExists(keyName) )
gameFixes[i]->SetValue(game.getBool(keyName)); gameFixes[i]->SetValue(game.getBool(keyName));
else else
gameFixes[i]->SetIndeterminate(); gameFixes[i]->SetIndeterminate();
} }
} }
else { else {
serialBox ->SetLabel(wxEmptyString); serialBox ->SetLabel(wxEmptyString);
nameBox ->SetLabel(wxEmptyString); nameBox ->SetLabel(wxEmptyString);
regionBox ->SetLabel(wxEmptyString); regionBox ->SetLabel(wxEmptyString);
compatBox ->SetLabel(wxEmptyString); compatBox ->SetLabel(wxEmptyString);
commentBox->SetLabel(wxEmptyString); commentBox->SetLabel(wxEmptyString);
patchesBox->SetLabel(wxEmptyString); patchesBox->SetLabel(wxEmptyString);
for (int i = 0; i < GamefixId_COUNT; i++) { for (int i = 0; i < GamefixId_COUNT; i++) {
gameFixes[i]->SetValue(0); gameFixes[i]->SetValue(0);
} }
} }
} }
#define writeTextBoxToDB(_key, _value) { \ #define writeTextBoxToDB(_key, _value) { \
if (_value.IsEmpty()) GameDB->deleteKey(wxT(_key)); \ if (_value.IsEmpty()) GameDB->deleteKey(wxT(_key)); \
else GameDB->writeString(wxT(_key), _value); \ else GameDB->writeString(wxT(_key), _value); \
} }
// returns True if the database is modified, or FALSE if no changes to save. // returns True if the database is modified, or FALSE if no changes to save.
bool Panels::GameDatabasePanel::WriteFieldsToDB() { bool Panels::GameDatabasePanel::WriteFieldsToDB() {
IGameDatabase* GameDB = AppHost_GetGameDatabase(); IGameDatabase* GameDB = AppHost_GetGameDatabase();
if (!GameDB) return false; if (!GameDB) return false;
if (serialBox->GetValue().IsEmpty()) return false; if (serialBox->GetValue().IsEmpty()) return false;
Game_Data game; Game_Data game;
GameDB->findGame(game, serialBox->GetValue()); GameDB->findGame(game, serialBox->GetValue());
game.id = serialBox->GetValue(); game.id = serialBox->GetValue();
game.writeString(L"Serial", serialBox->GetValue()); game.writeString(L"Serial", serialBox->GetValue());
game.writeString(L"Name", nameBox->GetValue()); game.writeString(L"Name", nameBox->GetValue());
game.writeString(L"Region", regionBox->GetValue()); game.writeString(L"Region", regionBox->GetValue());
game.writeString(L"Compat", compatBox->GetValue()); game.writeString(L"Compat", compatBox->GetValue());
game.writeString(L"[comments]", commentBox->GetValue()); game.writeString(L"[comments]", commentBox->GetValue());
game.writeString(L"[patches]", patchesBox->GetValue()); game.writeString(L"[patches]", patchesBox->GetValue());
for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) { for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) {
wxString keyName (EnumToString(i)); keyName += L"Hack"; wxString keyName (EnumToString(i)); keyName += L"Hack";
if (gameFixes[i]->IsIndeterminate()) if (gameFixes[i]->IsIndeterminate())
game.deleteKey(keyName); game.deleteKey(keyName);
else else
game.writeBool(keyName, gameFixes[i]->GetValue()); game.writeBool(keyName, gameFixes[i]->GetValue());
} }
GameDB->updateGame(game); GameDB->updateGame(game);
return true; return true;
} }
void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) { void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) {
IGameDatabase* GameDB = AppHost_GetGameDatabase(); IGameDatabase* GameDB = AppHost_GetGameDatabase();
if( !GameDB ) return; if( !GameDB ) return;
PopulateFields( serialBox->GetValue() ); PopulateFields( serialBox->GetValue() );
evt.Skip(); evt.Skip();
} }
void Panels::GameDatabasePanel::Apply() { void Panels::GameDatabasePanel::Apply() {
AppGameDatabase* GameDB = wxGetApp().GetGameDatabase(); AppGameDatabase* GameDB = wxGetApp().GetGameDatabase();
if( WriteFieldsToDB() ) if( WriteFieldsToDB() )
{ {
Console.WriteLn("Saving changes to Game Database..."); Console.WriteLn("Saving changes to Game Database...");
GameDB->SaveToFile(); GameDB->SaveToFile();
} }
} }
void Panels::GameDatabasePanel::AppStatusEvent_OnSettingsApplied() void Panels::GameDatabasePanel::AppStatusEvent_OnSettingsApplied()
{ {
} }

View File

@ -144,10 +144,10 @@ static SysTraceLog * const traceLogList[] =
&SysTrace.EE.SPR, &SysTrace.EE.SPR,
&SysTrace.EE.VIF, &SysTrace.EE.VIF,
&SysTrace.EE.GIF, &SysTrace.EE.GIF,
// IOP Section // IOP Section
&SysTrace.IOP.Bios, &SysTrace.IOP.Bios,
&SysTrace.IOP.Memcards, &SysTrace.IOP.Memcards,
&SysTrace.IOP.PAD, &SysTrace.IOP.PAD,
@ -164,7 +164,7 @@ static SysTraceLog * const traceLogList[] =
&SysTrace.IOP.CDVD, &SysTrace.IOP.CDVD,
}; };
static const int traceLogCount = ArraySize(traceLogList); static const uint traceLogCount = ArraySize(traceLogList);
void SysTraceLog_LoadSaveSettings( IniInterface& ini ) 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"EE" ) return m_eeSection;
if( token == L"IOP" ) return m_iopSection; if( token == L"IOP" ) return m_iopSection;
return NULL; return NULL;
} }
@ -316,7 +316,7 @@ void Panels::LogOptionsPanel::Apply()
m_iopSection->Apply(); m_iopSection->Apply();
m_IsDirty = false; m_IsDirty = false;
for( uint i = 0; i<traceLogCount; ++i ) for( uint i = 0; i<traceLogCount; ++i )
{ {
if (!traceLogList[i] || !m_checks[i]) continue; if (!traceLogList[i] || !m_checks[i]) continue;

View File

@ -59,7 +59,15 @@ namespace Exception
class NotEnumerablePlugin : public BadStream class NotEnumerablePlugin : public BadStream
{ {
public: 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;
}
}; };
} }

View File

@ -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.")); .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 // gzipReader
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------

View File

@ -104,7 +104,7 @@ __fi tDMA_TAG *SPRdmaGetAddr(u32 addr, bool write)
// FIXME: Why??? DMA uses physical addresses // FIXME: Why??? DMA uses physical addresses
addr &= 0x1ffffff0; addr &= 0x1ffffff0;
if (addr < Ps2MemSize::Base) if (addr < Ps2MemSize::MainRam)
{ {
return (tDMA_TAG*)&eeMem->Main[addr]; return (tDMA_TAG*)&eeMem->Main[addr];
} }
@ -133,7 +133,7 @@ __ri tDMA_TAG *dmaGetAddr(u32 addr, bool write)
// FIXME: Why??? DMA uses physical addresses // FIXME: Why??? DMA uses physical addresses
addr &= 0x1ffffff0; addr &= 0x1ffffff0;
if (addr < Ps2MemSize::Base) if (addr < Ps2MemSize::MainRam)
{ {
return (tDMA_TAG*)&eeMem->Main[addr]; return (tDMA_TAG*)&eeMem->Main[addr];
} }

View File

@ -33,9 +33,10 @@
#include "Common.h" #include "Common.h"
#include "vtlb.h" #include "vtlb.h"
#include "COP0.h" #include "COP0.h"
#include "R5900Exceptions.h" #include "R5900Exceptions.h"
#include "Utilities/MemsetFast.inl"
using namespace R5900; using namespace R5900;
using namespace vtlb_private; using namespace vtlb_private;
@ -46,7 +47,7 @@ namespace vtlb_private
__aligned(64) MapData vtlbdata; __aligned(64) MapData vtlbdata;
} }
static vtlbHandler vtlbHandlerCount=0; static vtlbHandler vtlbHandlerCount = 0;
static vtlbHandler DefaultPhyHandler; static vtlbHandler DefaultPhyHandler;
static vtlbHandler UnmappedVirtHandler0; static vtlbHandler UnmappedVirtHandler0;
@ -78,9 +79,9 @@ DataType __fastcall vtlb_memRead(u32 addr)
switch( DataSize ) switch( DataSize )
{ {
case 8: return ((vtlbMemR8FP*)vtlbdata.RWFT[0][0][hand])(paddr); case 8: return ((vtlbMemR8FP*)vtlbdata.RWFT[0][0][hand])(paddr);
case 16: return ((vtlbMemR16FP*)vtlbdata.RWFT[1][0][hand])(paddr); case 16: return ((vtlbMemR16FP*)vtlbdata.RWFT[1][0][hand])(paddr);
case 32: return ((vtlbMemR32FP*)vtlbdata.RWFT[2][0][hand])(paddr); case 32: return ((vtlbMemR32FP*)vtlbdata.RWFT[2][0][hand])(paddr);
jNO_DEFAULT; jNO_DEFAULT;
} }
@ -147,9 +148,9 @@ void __fastcall vtlb_memWrite(u32 addr, DataType data)
switch( DataSize ) switch( DataSize )
{ {
case 8: return ((vtlbMemW8FP*)vtlbdata.RWFT[0][1][hand])(paddr, (u8)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 16: return ((vtlbMemW16FP*)vtlbdata.RWFT[1][1][hand])(paddr, (u16)data);
case 32: return ((vtlbMemW32FP*)vtlbdata.RWFT[2][1][hand])(paddr, (u32)data); case 32: return ((vtlbMemW32FP*)vtlbdata.RWFT[2][1][hand])(paddr, (u32)data);
jNO_DEFAULT; jNO_DEFAULT;
} }
@ -255,65 +256,55 @@ _tmpl(void) vtlbUnmappedPWriteLg(u32 addr,const OperandType* data) { vtlb_BusErr
static mem8_t __fastcall vtlbDefaultPhyRead8(u32 addr) static mem8_t __fastcall vtlbDefaultPhyRead8(u32 addr)
{ {
Console.Error("vtlbDefaultPhyRead8: 0x%08X", addr); pxFailDev(pxsFmt("(VTLB) Attempted read8 from unmapped physical address @ 0x%08X.", addr));
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
return 0; return 0;
} }
static mem16_t __fastcall vtlbDefaultPhyRead16(u32 addr) static mem16_t __fastcall vtlbDefaultPhyRead16(u32 addr)
{ {
Console.Error("vtlbDefaultPhyRead16: 0x%08X", addr); pxFailDev(pxsFmt("(VTLB) Attempted read16 from unmapped physical address @ 0x%08X.", addr));
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
return 0; return 0;
} }
static mem32_t __fastcall vtlbDefaultPhyRead32(u32 addr) static mem32_t __fastcall vtlbDefaultPhyRead32(u32 addr)
{ {
Console.Error("vtlbDefaultPhyRead32: 0x%08X", addr); pxFailDev(pxsFmt("(VTLB) Attempted read32 from unmapped physical address @ 0x%08X.", addr));
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
return 0; return 0;
} }
static void __fastcall vtlbDefaultPhyRead64(u32 addr, mem64_t* dest) static void __fastcall vtlbDefaultPhyRead64(u32 addr, mem64_t* dest)
{ {
Console.Error("vtlbDefaultPhyRead64: 0x%08X", addr); pxFailDev(pxsFmt("(VTLB) Attempted read64 from unmapped physical address @ 0x%08X.", addr));
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
} }
static void __fastcall vtlbDefaultPhyRead128(u32 addr, mem128_t* dest) static void __fastcall vtlbDefaultPhyRead128(u32 addr, mem128_t* dest)
{ {
Console.Error("vtlbDefaultPhyRead128: 0x%08X", addr); pxFailDev(pxsFmt("(VTLB) Attempted read128 from unmapped physical address @ 0x%08X.", addr));
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
} }
static void __fastcall vtlbDefaultPhyWrite8(u32 addr, mem8_t data) static void __fastcall vtlbDefaultPhyWrite8(u32 addr, mem8_t data)
{ {
Console.Error("vtlbDefaultPhyWrite8: 0x%08X",addr); pxFailDev(pxsFmt("(VTLB) Attempted write8 to unmapped physical address @ 0x%08X.", addr));
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
} }
static void __fastcall vtlbDefaultPhyWrite16(u32 addr, mem16_t data) static void __fastcall vtlbDefaultPhyWrite16(u32 addr, mem16_t data)
{ {
Console.Error("vtlbDefaultPhyWrite16: 0x%08X",addr); pxFailDev(pxsFmt("(VTLB) Attempted write16 to unmapped physical address @ 0x%08X.", addr));
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
} }
static void __fastcall vtlbDefaultPhyWrite32(u32 addr, mem32_t data) static void __fastcall vtlbDefaultPhyWrite32(u32 addr, mem32_t data)
{ {
Console.Error("vtlbDefaultPhyWrite32: 0x%08X",addr); pxFailDev(pxsFmt("(VTLB) Attempted write32 to unmapped physical address @ 0x%08X.", addr));
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
} }
static void __fastcall vtlbDefaultPhyWrite64(u32 addr,const mem64_t* data) static void __fastcall vtlbDefaultPhyWrite64(u32 addr,const mem64_t* data)
{ {
Console.Error("vtlbDefaultPhyWrite64: 0x%08X",addr); pxFailDev(pxsFmt("(VTLB) Attempted write64 to unmapped physical address @ 0x%08X.", addr));
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
} }
static void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data) static void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data)
{ {
Console.Error("vtlbDefaultPhyWrite128: 0x%08X",addr); pxFailDev(pxsFmt("(VTLB) Attempted write128 to unmapped physical address @ 0x%08X.", addr));
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
} }
#undef _tmpl #undef _tmpl
@ -333,6 +324,8 @@ __ri void vtlb_ReassignHandler( vtlbHandler rv,
vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128, 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 )
{ {
pxAssume(rv < VTLB_HANDLER_ITEMS);
vtlbdata.RWFT[0][0][rv] = (void*)((r8!=0) ? r8 : vtlbDefaultPhyRead8); vtlbdata.RWFT[0][0][rv] = (void*)((r8!=0) ? r8 : vtlbDefaultPhyRead8);
vtlbdata.RWFT[1][0][rv] = (void*)((r16!=0) ? r16 : vtlbDefaultPhyRead16); vtlbdata.RWFT[1][0][rv] = (void*)((r16!=0) ? r16 : vtlbDefaultPhyRead16);
vtlbdata.RWFT[2][0][rv] = (void*)((r32!=0) ? r32 : vtlbDefaultPhyRead32); vtlbdata.RWFT[2][0][rv] = (void*)((r32!=0) ? r32 : vtlbDefaultPhyRead32);
@ -348,7 +341,7 @@ __ri void vtlb_ReassignHandler( vtlbHandler rv,
vtlbHandler vtlb_NewHandler() vtlbHandler vtlb_NewHandler()
{ {
pxAssertDev( vtlbHandlerCount < 127, "VTLB allowed handler count exceeded!" ); pxAssertDev( vtlbHandlerCount < VTLB_HANDLER_ITEMS, "VTLB handler count overflow!" );
return vtlbHandlerCount++; 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. // 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, __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(); vtlbHandler rv = vtlb_NewHandler();
vtlb_ReassignHandler( rv, r8, r16, r32, r64, r128, w8, w16, w32, w64, w128 ); 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. // function.
// //
// The memory region start and size parameters must be pagesize aligned. // 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==(start&VTLB_PAGE_MASK));
verify(0==(size&VTLB_PAGE_MASK) && size>0); 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; vtlbdata.pmap[start>>VTLB_PAGE_BITS] = value;
start += VTLB_PAGE_SIZE;
start+=VTLB_PAGE_SIZE;
size-=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==(start&VTLB_PAGE_MASK));
verify(0==(size&VTLB_PAGE_MASK) && size>0); verify(0==(size&VTLB_PAGE_MASK) && size>0);
if (blocksize==0) if (!blocksize)
blocksize=size; blocksize = size;
verify(0==(blocksize&VTLB_PAGE_MASK) && blocksize>0); verify(0==(blocksize&VTLB_PAGE_MASK) && blocksize>0);
verify(0==(size%blocksize)); 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; u32 loopsz = blocksize;
s32 ptr=baseint; 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; start += VTLB_PAGE_SIZE;
ptr+=VTLB_PAGE_SIZE; ptr += VTLB_PAGE_SIZE;
blocksz-=VTLB_PAGE_SIZE; loopsz -= VTLB_PAGE_SIZE;
size-=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==(start&VTLB_PAGE_MASK));
verify(0==(size&VTLB_PAGE_MASK) && size>0); verify(0==(size&VTLB_PAGE_MASK) && size>0);
while(size>0) u32 end = start + (size-VTLB_PAGE_SIZE);
{ pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) );
vtlbdata.pmap[start>>VTLB_PAGE_BITS]=vtlbdata.pmap[new_region>>VTLB_PAGE_BITS];
start+=VTLB_PAGE_SIZE; while(start <= end)
new_region+=VTLB_PAGE_SIZE; {
size-=VTLB_PAGE_SIZE; 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 //virtual mappings
//TODO: Add invalid paddr checks //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==(vaddr&VTLB_PAGE_MASK));
verify(0==(paddr&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; s32 pme;
if (paddr>=VTLB_PMAP_SZ) if (paddr >= VTLB_PMAP_SZ)
{ {
pme=UnmappedPhyHandler0; pme = UnmappedPhyHandler0;
if (paddr&0x80000000) if (paddr & 0x80000000)
pme=UnmappedPhyHandler1; pme = UnmappedPhyHandler1;
pme|=0x80000000; pme |= 0x80000000;
pme|=paddr;// top bit is set anyway ... pme |= paddr;// top bit is set anyway ...
} }
else else
{ {
pme=vtlbdata.pmap[paddr>>VTLB_PAGE_BITS]; pme = vtlbdata.pmap[paddr>>VTLB_PAGE_BITS];
if (pme<0) 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; vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS] = pme-vaddr;
paddr+=VTLB_PAGE_SIZE; vaddr += VTLB_PAGE_SIZE;
sz-=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==(vaddr&VTLB_PAGE_MASK));
verify(0==(sz&VTLB_PAGE_MASK) && sz>0); verify(0==(size&VTLB_PAGE_MASK) && size>0);
u32 bu8=(u32)buffer;
while(sz>0) u32 bu8 = (u32)buffer;
while (size > 0)
{ {
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=bu8-vaddr; vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS] = bu8-vaddr;
vaddr+=VTLB_PAGE_SIZE; vaddr += VTLB_PAGE_SIZE;
bu8+=VTLB_PAGE_SIZE; bu8 += VTLB_PAGE_SIZE;
sz-=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==(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; u32 handl = UnmappedVirtHandler0;
if (vaddr&0x80000000) if (vaddr & 0x80000000)
{ {
handl=UnmappedVirtHandler1; handl = UnmappedVirtHandler1;
} }
handl|=vaddr; // top bit is set anyway ...
handl|=0x80000000; handl |= vaddr; // top bit is set anyway ...
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=handl-vaddr; handl |= 0x80000000;
vaddr+=VTLB_PAGE_SIZE;
sz-=VTLB_PAGE_SIZE; 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! // 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() void vtlb_Core_Alloc()
{ {
if( vtlbdata.alloc_base != NULL ) return; if (!vtlbdata.vmap)
{
vtlbdata.alloc_current = 0; vtlbdata.vmap = (s32*)_aligned_malloc( VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap), 16 );
if (!vtlbdata.vmap)
#ifdef __LINUX__ throw Exception::OutOfMemory( L"VTLB Virtual Address Translation LUT" )
vtlbdata.alloc_base = SysMmapEx( 0x16000000, VTLB_ALLOC_SIZE, 0x80000000, "Vtlb" ); .SetDiagMsg(pxsFmt("(%u megs)", VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap) / _1mb)
#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
} }
void vtlb_Core_Shutdown() void vtlb_Core_Free()
{ {
if( vtlbdata.alloc_base == NULL ) return; safe_aligned_free( vtlbdata.vmap );
#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
} }
// This function allocates memory block with are compatible with the Vtlb's requirements static wxString GetHostVmErrorMsg()
// 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 )
{ {
vtlbdata.alloc_current += align-1; return pxE(".Error:HostVmReserve",
vtlbdata.alloc_current &= ~(align-1); 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 "
int rv = vtlbdata.alloc_current; L"hogging resources."
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];
} }
// --------------------------------------------------------------------------------------
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; m_reserve.SetPageAccessOnCommit( PageAccess_ReadWrite() );
pxAssertDev( vtlbdata.alloc_current >= 0, "(vtlb_free) mismatched calls to vtlb_malloc and free detected via memory underflow." );
return;
} }
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();
}

View File

@ -17,6 +17,10 @@
#include "MemoryTypes.h" #include "MemoryTypes.h"
#include "Utilities/PageFaultSource.h"
static const uptr VTLB_AllocUpperBounds = _1gb * 2;
// Specialized function pointers for each read type // Specialized function pointers for each read type
typedef mem8_t __fastcall vtlbMemR8FP(u32 addr); typedef mem8_t __fastcall vtlbMemR8FP(u32 addr);
typedef mem16_t __fastcall vtlbMemR16FP(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; typedef u32 vtlbHandler;
extern void vtlb_Core_Alloc(); extern void vtlb_Core_Alloc();
extern void vtlb_Core_Shutdown(); extern void vtlb_Core_Free();
extern void vtlb_Init(); extern void vtlb_Init();
extern void vtlb_Reset(); extern void vtlb_Reset();
extern void vtlb_Term(); extern void vtlb_Term();
extern u8* vtlb_malloc( uint size, uint align );
extern void vtlb_free( void* pmem, uint size );
extern vtlbHandler vtlb_NewHandler(); 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_DynGenRead64_Const( u32 bits, u32 addr_const );
extern void vtlb_DynGenRead32_Const( u32 bits, bool sign, 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 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_BITS = 12;
static const uint VTLB_PAGE_MASK = 4095; static const uint VTLB_PAGE_MASK = 4095;
static const uint VTLB_PAGE_SIZE = 4096; static const uint VTLB_PAGE_SIZE = 4096;
static const uint VTLB_PMAP_ITEMS = 0x20000000 / VTLB_PAGE_SIZE; static const uint VTLB_PMAP_SZ = _1mb * 512;
static const uint VTLB_PMAP_SZ = 0x20000000; static const uint VTLB_PMAP_ITEMS = VTLB_PMAP_SZ / VTLB_PAGE_SIZE;
static const uint VTLB_VMAP_ITEMS = 0x100000000ULL / VTLB_PAGE_SIZE; static const uint VTLB_VMAP_ITEMS = _4gb / VTLB_PAGE_SIZE;
static const uint VTLB_HANDLER_ITEMS = 128;
struct MapData 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] // first indexer -- 8/16/32/64/128 bit tables [values 0-4]
// second indexer -- read/write [0 or 1] // second indexer -- read/write [0 or 1]
// third indexer -- 128 possible handlers! // 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; extern __aligned(64) MapData vtlbdata;

View File

@ -119,40 +119,47 @@ static bool _registeredName( const wxString& name )
return false; return false;
} }
void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz) void ProfilerRegisterSource(const wxString& Name, const void* buff, u32 sz)
{ {
if( ProfRunning ) if( ProfRunning )
EnterCriticalSection( &ProfModulesLock ); EnterCriticalSection( &ProfModulesLock );
wxString strName( fromUTF8(Name) ); if( !_registeredName( Name ) )
if( !_registeredName( strName ) ) ProfModules.push_back( Module( Name, buff, sz ) );
ProfModules.push_back( Module( strName, buff, sz ) );
if( ProfRunning ) if( ProfRunning )
LeaveCriticalSection( &ProfModulesLock ); 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) void ProfilerRegisterSource(const char* Name, const void* function)
{ {
if( ProfRunning ) ProfilerRegisterSource( fromUTF8(Name), function );
EnterCriticalSection( &ProfModulesLock );
wxString strName( fromUTF8(Name) );
if( !_registeredName( strName ) )
ProfModules.push_back( Module(strName,function) );
if( ProfRunning )
LeaveCriticalSection( &ProfModulesLock );
} }
void ProfilerTerminateSource( const char* Name ) void ProfilerTerminateSource( const wxString& Name )
{ {
wxString strName( fromUTF8(Name) );
for( vector<Module>::const_iterator for( vector<Module>::const_iterator
iter = ProfModules.begin(), iter = ProfModules.begin(),
end = ProfModules.end(); iter<end; ++iter ) end = ProfModules.end(); iter<end; ++iter )
{ {
if( iter->name.compare( strName ) == 0 ) if( iter->name.compare( Name ) == 0 )
{ {
ProfModules.erase( iter ); ProfModules.erase( iter );
break; break;
@ -160,6 +167,11 @@ void ProfilerTerminateSource( const char* Name )
} }
} }
void ProfilerTerminateSource( const char* Name )
{
ProfilerTerminateSource( fromUTF8(Name) );
}
static bool DispatchKnownModules( uint Eip ) static bool DispatchKnownModules( uint Eip )
{ {
bool retval = false; bool retval = false;

File diff suppressed because it is too large Load Diff

View File

@ -46,7 +46,7 @@ void StreamException_ThrowLastError( const wxString& streamname, HANDLE result )
default: 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 ); StreamException_ThrowLastError( streamname, result );
} }
catch( Exception::Stream& ex ) catch( Exception::BadStream& ex )
{ {
Console.WriteLn( Color_Yellow, L"%s: %s", action, ex.FormatDiagnosticMessage().c_str() ); Console.WriteLn( Color_Yellow, L"%s: %s", action, ex.FormatDiagnosticMessage().c_str() );
return true; return true;

View File

@ -18,18 +18,4 @@
#include <winnt.h> #include <winnt.h>
#include "Common.h" #include "Common.h"
#include "System/PageFaultSource.h" #include "Utilities/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.
}

View File

@ -1083,7 +1083,7 @@ BOOL CALLBACK BrowserProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
case IDC_SKIPMPEG: case IDC_SKIPMPEG:
{ {
u8 *p = eeMem->Main; u8 *p = eeMem->Main;
u8 *d = p + Ps2MemSize::Base; u8 *d = p + Ps2MemSize::MainRam;
d -= 16; d -= 16;
u32 *u; u32 *u;

View File

@ -59,7 +59,7 @@ bool FirstSearch;
bool FirstShow; bool FirstShow;
char olds[Ps2MemSize::Base]; char olds[Ps2MemSize::MainRam];
char tn[100]; char tn[100];
char to[100]; char to[100];

View File

@ -81,9 +81,6 @@ public:
__fi int Index (u32 startpc) const __fi int Index (u32 startpc) const
{ {
int idx = LastIndex(startpc); 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) || if ((idx == -1) || (startpc < blocks[idx].startpc) ||
((blocks[idx].size) && (startpc >= blocks[idx].startpc + blocks[idx].size * 4))) ((blocks[idx].size) && (startpc >= blocks[idx].startpc + blocks[idx].size * 4)))
return -1; return -1;
@ -139,9 +136,10 @@ public:
static void recLUT_SetPage(uptr reclut[0x10000], uptr hwlut[0x10000], static void recLUT_SetPage(uptr reclut[0x10000], uptr hwlut[0x10000],
BASEBLOCK *mapbase, uint pagebase, uint pageidx, uint mappage) BASEBLOCK *mapbase, uint pagebase, uint pageidx, uint mappage)
{ {
// this value is in 64k pages!
uint page = pagebase + pageidx; uint page = pagebase + pageidx;
jASSUME( page < 0x10000 ); pxAssume( page < 0x10000 );
reclut[page] = (uptr)&mapbase[(mappage - page) << 14]; reclut[page] = (uptr)&mapbase[(mappage - page) << 14];
if (hwlut) if (hwlut)
hwlut[page] = 0u - (pagebase << 16); hwlut[page] = 0u - (pagebase << 16);

View File

@ -22,6 +22,7 @@
#include "iR3000A.h" #include "iR3000A.h"
#include "BaseblockEx.h" #include "BaseblockEx.h"
#include "System/RecTypes.h"
#include <time.h> #include <time.h>
@ -32,7 +33,6 @@
#include "IopCommon.h" #include "IopCommon.h"
#include "iCore.h" #include "iCore.h"
#include "SamplProf.h"
#include "NakedAsm.h" #include "NakedAsm.h"
#include "AppConfig.h" #include "AppConfig.h"
@ -50,13 +50,8 @@ uptr psxhwLUT[0x10000];
#define HWADDR(mem) (psxhwLUT[mem >> 16] + (mem)) #define HWADDR(mem) (psxhwLUT[mem >> 16] + (mem))
#define MAPBASE 0x48000000 static RecompiledCodeReserve* recMem = NULL;
#define RECMEM_SIZE (8*1024*1024)
// 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 *recRAM = NULL; // and the ptr to the blocks here
static BASEBLOCK *recROM = NULL; // and here static BASEBLOCK *recROM = NULL; // and here
static BASEBLOCK *recROM1 = NULL; // also here static BASEBLOCK *recROM1 = NULL; // also here
@ -130,7 +125,7 @@ static void recEventTest()
// stackframe setup code in this function) // stackframe setup code in this function)
static void __fastcall StackFrameCheckFailed( int espORebp, int regval ) 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 ) (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() static void _DynGen_Dispatchers()
{ {
// In case init gets called multiple times: // 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). // clear the buffer to 0xcc (easier debugging).
memset_8<0xcc,__pagesize>( iopRecDispatchers ); memset_8<0xcc,__pagesize>( iopRecDispatchers );
@ -363,7 +358,7 @@ static void _DynGen_Dispatchers()
iopJITCompileInBlock = _DynGen_JITCompileInBlock(); iopJITCompileInBlock = _DynGen_JITCompileInBlock();
iopEnterRecompiledCode = _DynGen_EnterRecompiledCode(); iopEnterRecompiledCode = _DynGen_EnterRecompiledCode();
HostSys::MemProtectStatic( iopRecDispatchers, Protect_ReadOnly, true ); HostSys::MemProtectStatic( iopRecDispatchers, PageAccess_ExecOnly() );
recBlocks.SetJITCompile( iopJITCompile ); recBlocks.SetJITCompile( iopJITCompile );
} }
@ -754,23 +749,38 @@ void psxRecompileCodeConst3(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode,
noconstcode(0); noconstcode(0);
} }
static uptr m_ConfiguredCacheReserve = 32;
static u8* m_recBlockAlloc = NULL; static u8* m_recBlockAlloc = NULL;
static const uint m_recBlockAllocSize = static const uint m_recBlockAllocSize =
(((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK)); (((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() 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. // 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 // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
// always 4 bytes long). // always 4 bytes long).
@ -795,24 +805,22 @@ static void recAlloc()
if( s_pInstCache == NULL ) if( s_pInstCache == NULL )
throw Exception::OutOfMemory( L"R3000 InstCache." ); throw Exception::OutOfMemory( L"R3000 InstCache." );
ProfilerRegisterSource( "IOP Rec", recMem, RECMEM_SIZE );
_DynGen_Dispatchers(); _DynGen_Dispatchers();
} }
void recResetIOP() void recResetIOP()
{ {
// calling recResetIOP without first calling recInit is bad mojo.
pxAssert( recMem != NULL );
pxAssert( m_recBlockAlloc != NULL );
DevCon.WriteLn( "iR3000A Recompiler reset." ); DevCon.WriteLn( "iR3000A Recompiler reset." );
memset_8<0xcc,RECMEM_SIZE>( recMem ); // 0xcc is INT3 recAlloc();
recMem->Reset();
iopClearRecLUT((BASEBLOCK*)m_recBlockAlloc, iopClearRecLUT((BASEBLOCK*)m_recBlockAlloc,
(((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4))); (((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4)));
for (int i = 0; i < 0x10000; i++) for (int i = 0; i < 0x10000; i++)
recLUT_SetPage(psxRecLUT, 0, 0, 0, i, 0); recLUT_SetPage(psxRecLUT, 0, 0, 0, i, 0);
// IOP knows 64k pages, hence for the 0x10000's // IOP knows 64k pages, hence for the 0x10000's
// The bottom 2 bits of PC are always zero, so we <<14 to "compress" // 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. // We're only mapping 20 pages here in 4 places.
// 0x80 comes from : (Ps2MemSize::IopRam / 0x10000) * 4 // 0x80 comes from : (Ps2MemSize::IopRam / 0x10000) * 4
for (int i=0; i<0x80; i++) for (int i=0; i<0x80; i++)
{ {
recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0x0000, i, i & 0x1f); recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0x0000, i, i & 0x1f);
@ -847,15 +856,14 @@ void recResetIOP()
recBlocks.Reset(); recBlocks.Reset();
g_psxMaxRecMem = 0; g_psxMaxRecMem = 0;
recPtr = recMem; recPtr = *recMem;
psxbranch = 0; psxbranch = 0;
} }
static void recShutdown() static void recShutdown()
{ {
ProfilerTerminateSource( "IOPRec" ); safe_delete( recMem );
SafeSysMunmap(recMem, RECMEM_SIZE);
safe_aligned_free( m_recBlockAlloc ); safe_aligned_free( m_recBlockAlloc );
safe_free( s_pInstCache ); safe_free( s_pInstCache );
@ -1202,8 +1210,9 @@ static void __fastcall iopRecRecompile( const u32 startpc )
pxAssert( startpc ); pxAssert( startpc );
// if recPtr reached the mem limit reset whole mem // if recPtr reached the mem limit reset whole mem
if (((uptr)recPtr - (uptr)recMem) >= (RECMEM_SIZE - 0x10000)) if (recPtr >= (recMem->GetPtrEnd() - _64kb)) {
recResetIOP(); recResetIOP();
}
x86SetPtr( recPtr ); x86SetPtr( recPtr );
x86Align(16); x86Align(16);
@ -1390,12 +1399,12 @@ StartRecomp:
} }
} }
pxAssert( x86Ptr < recMem+RECMEM_SIZE ); pxAssert( xGetPtr() < recMem->GetPtrEnd() );
pxAssert(x86Ptr - recPtr < 0x10000); pxAssert(xGetPtr() - recPtr < _64kb);
s_pCurBlockEx->x86size = x86Ptr - recPtr; s_pCurBlockEx->x86size = xGetPtr() - recPtr;
recPtr = x86Ptr; recPtr = xGetPtr();
pxAssert( (g_psxHasConstReg&g_psxFlushedConstReg) == g_psxHasConstReg ); pxAssert( (g_psxHasConstReg&g_psxFlushedConstReg) == g_psxHasConstReg );
@ -1403,12 +1412,25 @@ StartRecomp:
s_pCurBlockEx = NULL; s_pCurBlockEx = NULL;
} }
static void recSetCacheReserve( uint reserveInMegs )
{
m_ConfiguredCacheReserve = reserveInMegs;
}
static uint recGetCacheReserve()
{
return m_ConfiguredCacheReserve;
}
R3000Acpu psxRec = { R3000Acpu psxRec = {
recAlloc, recReserve,
recResetIOP, recResetIOP,
recExecute, recExecute,
recExecuteBlock, recExecuteBlock,
recClearIOP, recClearIOP,
recShutdown recShutdown,
recGetCacheReserve,
recSetCacheReserve
}; };

View File

@ -21,15 +21,14 @@
#include "R5900Exceptions.h" #include "R5900Exceptions.h"
#include "R5900OpcodeTables.h" #include "R5900OpcodeTables.h"
#include "iR5900.h" #include "iR5900.h"
#include "BaseblockEx.h" #include "BaseblockEx.h"
#include "System/RecTypes.h"
#include "vtlb.h" #include "vtlb.h"
#include "SamplProf.h"
#include "Dump.h" #include "Dump.h"
#include "System/SysThreads.h" #include "System/SysThreads.h"
#include "GS.h" #include "GS.h"
#include "CDVD/CDVD.h" #include "CDVD/CDVD.h"
#include "Elfheader.h" #include "Elfheader.h"
@ -37,14 +36,18 @@
# include <csetjmp> # include <csetjmp>
#endif #endif
#include "Utilities/MemsetFast.inl"
using namespace x86Emitter; using namespace x86Emitter;
using namespace R5900; using namespace R5900;
#define PC_GETBLOCK(x) PC_GETBLOCK_(x, recLUT) #define PC_GETBLOCK(x) PC_GETBLOCK_(x, recLUT)
u32 maxrecmem = 0; u32 maxrecmem = 0;
static __aligned16 uptr recLUT[0x10000]; static __aligned16 uptr recLUT[_64kb];
static __aligned16 uptr hwLUT[0x10000]; static __aligned16 uptr hwLUT[_64kb];
#define HWADDR(mem) (hwLUT[mem >> 16] + (mem)) #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; u32 g_cpuHasConstReg = 0, g_cpuFlushedConstReg = 0;
bool g_cpuFlushedPC, g_cpuFlushedCode, g_recompilingDelaySlot, g_maySignalException; 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 // Static Private Variables - R5900 Dynarec
#define X86 #define X86
static const int RECCONSTBUF_SIZE = 16384 * 2; // 64 bit consts in 32 bit units 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 u32* recConstBuf = NULL; // 64-bit pseudo-immediates
static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here
static BASEBLOCK *recROM = NULL; // and here static BASEBLOCK *recROM = NULL; // and here
static BASEBLOCK *recROM1 = NULL; // also here static BASEBLOCK *recROM1 = NULL; // also here
static u32 *recRAMCopy = NULL;
static BaseBlocks recBlocks; static BaseBlocks recBlocks;
static u8* recPtr = NULL; static u8* recPtr = NULL;
static u32 *recConstBufPtr = NULL; static u32 *recConstBufPtr = NULL;
@ -506,7 +532,7 @@ static DynGenFunc* _DynGen_EnterRecompiledCode()
static void _DynGen_Dispatchers() static void _DynGen_Dispatchers()
{ {
// In case init gets called multiple times: // 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). // clear the buffer to 0xcc (easier debugging).
memset_8<0xcc,__pagesize>( eeRecDispatchers ); memset_8<0xcc,__pagesize>( eeRecDispatchers );
@ -523,7 +549,7 @@ static void _DynGen_Dispatchers()
JITCompileInBlock = _DynGen_JITCompileInBlock(); JITCompileInBlock = _DynGen_JITCompileInBlock();
EnterRecompiledCode = _DynGen_EnterRecompiledCode(); EnterRecompiledCode = _DynGen_EnterRecompiledCode();
HostSys::MemProtectStatic( eeRecDispatchers, Protect_ReadOnly, true ); HostSys::MemProtectStatic( eeRecDispatchers, PageAccess_ExecOnly() );
recBlocks.SetJITCompile( JITCompile ); 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); static void __fastcall dyna_block_discard(u32 start,u32 sz);
// memory allocation handle for the entire BASEBLOCK and stack allocations. static __ri void ClearRecLUT(BASEBLOCK* base, int memsize)
static u8* m_recBlockAlloc = NULL; {
for (int i = 0; i < memsize/4; i++)
base[i].SetFnptr((uptr)JITCompile);
}
static const uint m_recBlockAllocSize = void R5900LutReserve_RAM::OnCommittedBlock( void* block )
(((Ps2MemSize::Base + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK)) {
+ RECCONSTBUF_SIZE * sizeof(u32) + Ps2MemSize::Base; _parent::OnCommittedBlock(block);
ClearRecLUT((BASEBLOCK*)block, __pagesize * m_blocksize);
}
static void recThrowHardwareDeficiency( const wxChar* extFail ) static void recThrowHardwareDeficiency( const wxChar* extFail )
{ {
throw Exception::HardwareDeficiency() throw Exception::HardwareDeficiency()
.SetDiagMsg(wxsFormat( L"R5900-32 recompiler init failed: %s is not available.", extFail)) .SetDiagMsg(pxsFmt( 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 )); .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... // Hardware Requirements Check...
@ -561,99 +608,31 @@ static void recAlloc()
if ( !x86caps.hasStreamingSIMD2Extensions ) if ( !x86caps.hasStreamingSIMD2Extensions )
recThrowHardwareDeficiency( L"SSE2" ); recThrowHardwareDeficiency( L"SSE2" );
if( recMem == NULL ) recReserveCache();
{
// 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;
} }
struct ManualPageTracking static void recAlloc()
{ {
u16 page; if (!recRAMCopy)
u8 counter; {
}; 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]; BASEBLOCK* basepos = (BASEBLOCK*)recLutReserve_RAM->GetPtr();
static __aligned16 u8 manual_counter[Ps2MemSize::Base >> 12]; recRAM = basepos; basepos += (Ps2MemSize::MainRam / 4);
recROM = basepos; basepos += (Ps2MemSize::Rom / 4);
recROM1 = basepos; basepos += (Ps2MemSize::Rom1 / 4);
static u32 eeRecIsReset = false; pxAssert(recLutReserve_RAM->GetPtrEnd() == (u8*)basepos);
////////////////////////////////////////////////////
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
for (int i = 0; i < 0x10000; i++) for (int i = 0; i < 0x10000; i++)
recLUT_SetPage(recLUT, 0, 0, 0, i, 0); recLUT_SetPage(recLUT, 0, 0, 0, i, 0);
@ -684,30 +663,100 @@ void recResetEE( void )
recLUT_SetPage(recLUT, hwLUT, recROM1, 0xa000, i, i - 0x1e00); 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; recConstBufPtr = recConstBuf;
x86FpuState = FPU_STATE; x86FpuState = FPU_STATE;
branch = 0; branch = 0;
} }
static void recShutdown( void ) static void recShutdown()
{ {
ProfilerTerminateSource( "EERec" ); safe_delete( recMem );
safe_delete( recRAMCopy );
safe_delete( recLutReserve_RAM );
recBlocks.Reset(); recBlocks.Reset();
SafeSysMunmap( recMem, REC_CACHEMEM );
safe_aligned_free( m_recBlockAlloc );
recRAM = recROM = recROM1 = NULL; recRAM = recROM = recROM1 = NULL;
recConstBuf = NULL;
recRAMCopy = NULL;
safe_aligned_free( recConstBuf );
safe_free( s_pInstCache ); safe_free( s_pInstCache );
s_nInstCacheSize = 0; s_nInstCacheSize = 0;
} }
static void recResetEE()
{
if (eeCpuExecuting)
{
AtomicExchange( eeRecNeedsReset, true );
return;
}
recResetRaw();
}
void recStep( void ) void recStep( void )
{ {
} }
@ -744,8 +793,6 @@ static void recCheckExecutionState()
} }
} }
static bool m_recExecutingCode = false;
static void recExecute() static void recExecute()
{ {
// Implementation Notes: // Implementation Notes:
@ -753,12 +800,14 @@ static void recExecute()
#if PCSX2_SEH #if PCSX2_SEH
eeRecIsReset = false; eeRecIsReset = false;
ScopedBool executing(m_recExecutingCode); ScopedBool executing(eeCpuExecuting);
try { try {
EnterRecompiledCode(); EnterRecompiledCode();
} }
catch( Exception::ExitCpuExecute& ) { } catch( Exception::ExitCpuExecute& )
{
}
#else #else
@ -816,18 +865,8 @@ void R5900::Dynarec::OpcodeImpl::recBREAK( void )
//branch = 2; //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) void recClear(u32 addr, u32 size)
{ {
BASEBLOCKEX* pexblock;
BASEBLOCK* pblock;
// necessary since recompiler doesn't call femms/emms // necessary since recompiler doesn't call femms/emms
#ifdef _MSC_VER #ifdef _MSC_VER
__asm emms; __asm emms;
@ -846,14 +885,14 @@ void recClear(u32 addr, u32 size)
u32 lowerextent = (u32)-1, upperextent = 0, ceiling = (u32)-1; u32 lowerextent = (u32)-1, upperextent = 0, ceiling = (u32)-1;
pexblock = recBlocks[blockidx + 1]; BASEBLOCKEX* pexblock = recBlocks[blockidx + 1];
if (pexblock) if (pexblock)
ceiling = pexblock->startpc; ceiling = pexblock->startpc;
while (pexblock = recBlocks[blockidx]) { while (pexblock = recBlocks[blockidx]) {
u32 blockstart = pexblock->startpc; u32 blockstart = pexblock->startpc;
u32 blockend = pexblock->startpc + pexblock->size * 4; u32 blockend = pexblock->startpc + pexblock->size * 4;
pblock = PC_GETBLOCK(blockstart); BASEBLOCK* pblock = PC_GETBLOCK(blockstart);
if (pblock == s_pCurBlock) { if (pblock == s_pCurBlock) {
blockidx--; blockidx--;
@ -889,7 +928,7 @@ void recClear(u32 addr, u32 size)
} }
if (upperextent > lowerextent) 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 ); pxAssume( startpc );
// if recPtr reached the mem limit reset whole mem // if recPtr reached the mem limit reset whole mem
if ( ( (uptr)recPtr - (uptr)recMem ) >= REC_CACHEMEM-0x40000 || dumplog == 0xffffffff) { if (recPtr >= (recMem->GetPtrEnd() - _64kb)) {
recResetEE(); AtomicExchange( eeRecNeedsReset, true );
} }
if ( (recConstBufPtr - recConstBuf) >= RECCONSTBUF_SIZE - 64 ) { else if ((recConstBufPtr - recConstBuf) >= RECCONSTBUF_SIZE - 64) {
Console.WriteLn("EE recompiler stack reset"); Console.WriteLn("EE recompiler stack reset");
recResetEE(); AtomicExchange( eeRecNeedsReset, true );
} }
if (eeRecNeedsReset) recResetRaw();
xSetPtr( recPtr ); xSetPtr( recPtr );
recPtr = xGetAlignedCallTarget(); recPtr = xGetAlignedCallTarget();
if (0x8000d618 == startpc)
DbgCon.WriteLn("Compiling block @ 0x%08x", startpc);
s_pCurBlock = PC_GETBLOCK(startpc); s_pCurBlock = PC_GETBLOCK(startpc);
pxAssert(s_pCurBlock->GetFnptr() == (uptr)JITCompile pxAssert(s_pCurBlock->GetFnptr() == (uptr)JITCompile
@ -1764,7 +1808,7 @@ StartRecomp:
pxAssert( (pc-startpc)>>2 <= 0xffff ); pxAssert( (pc-startpc)>>2 <= 0xffff );
s_pCurBlockEx->size = (pc-startpc)>>2; s_pCurBlockEx->size = (pc-startpc)>>2;
if (HWADDR(pc) <= Ps2MemSize::Base) { if (HWADDR(pc) <= Ps2MemSize::MainRam) {
BASEBLOCKEX *oldBlock; BASEBLOCKEX *oldBlock;
int i; int i;
@ -1774,10 +1818,12 @@ StartRecomp:
continue; continue;
if (oldBlock->startpc >= HWADDR(pc)) if (oldBlock->startpc >= HWADDR(pc))
continue; continue;
if (oldBlock->startpc + oldBlock->size * 4 <= HWADDR(startpc)) if ((oldBlock->startpc + oldBlock->size * 4) <= HWADDR(startpc))
break; 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); recClear(startpc, (pc - startpc) / 4);
s_pCurBlockEx = recBlocks.Get(HWADDR(startpc)); s_pCurBlockEx = recBlocks.Get(HWADDR(startpc));
pxAssert(s_pCurBlockEx->startpc == 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); 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( recConstBufPtr < recConstBuf + RECCONSTBUF_SIZE );
pxAssert( x86FpuState == 0 ); pxAssert( x86FpuState == 0 );
pxAssert(xGetPtr() - recPtr < 0x10000); pxAssert(xGetPtr() - recPtr < _64kb);
s_pCurBlockEx->x86size = xGetPtr() - recPtr; s_pCurBlockEx->x86size = xGetPtr() - recPtr;
recPtr = xGetPtr(); recPtr = xGetPtr();
@ -1859,7 +1905,7 @@ static void recThrowException( const BaseR5900Exception& ex )
#if PCSX2_SEH #if PCSX2_SEH
ex.Rethrow(); ex.Rethrow();
#else #else
if (!m_recExecutingCode) ex.Rethrow(); if (!eeCpuExecuting) ex.Rethrow();
m_cpuException = ex.Clone(); m_cpuException = ex.Clone();
recExitExecution(); recExitExecution();
#endif #endif
@ -1870,15 +1916,25 @@ static void recThrowException( const BaseException& ex )
#if PCSX2_SEH #if PCSX2_SEH
ex.Rethrow(); ex.Rethrow();
#else #else
if (!m_recExecutingCode) ex.Rethrow(); if (!eeCpuExecuting) ex.Rethrow();
m_Exception = ex.Clone(); m_Exception = ex.Clone();
recExitExecution(); recExitExecution();
#endif #endif
} }
static void recSetCacheReserve( uint reserveInMegs )
{
m_ConfiguredCacheReserve = reserveInMegs;
}
static uint recGetCacheReserve()
{
return m_ConfiguredCacheReserve;
}
R5900cpu recCpu = R5900cpu recCpu =
{ {
recAlloc, recReserve,
recShutdown, recShutdown,
recResetEE, recResetEE,
@ -1889,4 +1945,7 @@ R5900cpu recCpu =
recThrowException, recThrowException,
recThrowException, recThrowException,
recClear, recClear,
recGetCacheReserve,
recSetCacheReserve,
}; };

View File

@ -287,7 +287,7 @@ void vtlb_dynarec_init()
hasBeenCalled = true; hasBeenCalled = true;
// In case init gets called multiple times: // 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). // clear the buffer to 0xcc (easier debugging).
memset_8<0xcc,0x1000>( m_IndirectDispatchers ); 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() );
} }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////

View File

@ -18,6 +18,7 @@
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#include "Common.h" #include "Common.h"
#include "microVU.h" #include "microVU.h"
#include "System/RecTypes.h"
// Include all the *.inl files (Needed because C++ sucks with templates and *.cpp files) // Include all the *.inl files (Needed because C++ sucks with templates and *.cpp files)
#include "microVU_Clamp.inl" #include "microVU_Clamp.inl"
@ -80,8 +81,20 @@ const __aligned(32) mVU_Globals mVUglob = {
static __fi void mVUthrowHardwareDeficiency(const wxChar* extFail, int vuIndex) { static __fi void mVUthrowHardwareDeficiency(const wxChar* extFail, int vuIndex) {
throw Exception::HardwareDeficiency() throw Exception::HardwareDeficiency()
.SetDiagMsg(wxsFormat(L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail)) .SetDiagMsg(pxsFmt(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 )); .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! ;) // Only run this once per VU! ;)
@ -99,22 +112,14 @@ void microVU::init(uint vuIndex) {
microMemSize = (index ? 0x4000 : 0x1000); microMemSize = (index ? 0x4000 : 0x1000);
progSize = (index ? 0x4000 : 0x1000) / 4; progSize = (index ? 0x4000 : 0x1000) / 4;
progMemMask = progSize-1; progMemMask = progSize-1;
dispCache = NULL;
cache = NULL;
cacheSize = mVUcacheSize;
regAlloc = new microRegAlloc(index);
for (u32 i = 0; i < (progSize / 2); i++) { reserveCache();
prog.prog[i] = new deque<microProgram*>();
}
dispCache = SysMmapEx(0, mVUdispCacheSize, 0, (index ? "Micro VU1 Dispatcher" : "Micro VU0 Dispatcher")); 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" ); if (!dispCache) throw Exception::OutOfMemory( index ? L"Micro VU1 Dispatcher" : L"Micro VU0 Dispatcher" );
memset(dispCache, 0xcc, mVUdispCacheSize); memset(dispCache, 0xcc, mVUdispCacheSize);
// Allocates rec-cache and calls mVUreset() regAlloc = new microRegAlloc(index);
mVUresizeCache(this, cacheSize + mVUcacheSafeZone);
//if (vuIndex) gen_memcpy_vibes();
} }
// Resets Rec Data // Resets Rec Data
@ -123,16 +128,12 @@ void microVU::reset() {
x86SetPtr(dispCache); x86SetPtr(dispCache);
mVUdispatcherA(this); mVUdispatcherA(this);
mVUdispatcherB(this); mVUdispatcherB(this);
mVUemitSearch(); mVUemitSearch();
// Clear All Program Data // Clear All Program Data
//memset(&prog, 0, sizeof(prog)); //memset(&prog, 0, sizeof(prog));
memset(&prog.lpState, 0, sizeof(prog.lpState)); memset(&prog.lpState, 0, sizeof(prog.lpState));
if (IsDevBuild) { // Release builds shouldn't need this
memset(cache, 0xcc, cacheSize);
}
// Program Variables // Program Variables
prog.cleared = 1; prog.cleared = 1;
prog.isSame = -1; prog.isSame = -1;
@ -144,9 +145,15 @@ void microVU::reset() {
u8* z = cache; u8* z = cache;
prog.x86start = z; prog.x86start = z;
prog.x86ptr = 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++) { 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()); deque<microProgram*>::iterator it(prog.prog[i]->begin());
for ( ; it != prog.prog[i]->end(); ++it) { for ( ; it != prog.prog[i]->end(); ++it) {
if (index) mVUdeleteProg<1>(it[0]); if (index) mVUdeleteProg<1>(it[0]);
@ -161,11 +168,13 @@ void microVU::reset() {
// Free Allocated Resources // Free Allocated Resources
void microVU::close() { void microVU::close() {
if (dispCache) { HostSys::Munmap(dispCache, mVUdispCacheSize); dispCache = NULL; } safe_delete(cache_reserve);
if (cache) { HostSys::Munmap(cache, cacheSize); cache = NULL; }
SafeSysMunmap(dispCache, mVUdispCacheSize);
// Delete Programs and Block Managers // Delete Programs and Block Managers
for (u32 i = 0; i < (progSize / 2); i++) { for (u32 i = 0; i < (progSize / 2); i++) {
if (!prog.prog[i]) continue;
deque<microProgram*>::iterator it(prog.prog[i]->begin()); deque<microProgram*>::iterator it(prog.prog[i]->begin());
for ( ; it != prog.prog[i]->end(); ++it) { for ( ; it != prog.prog[i]->end(); ++it) {
if (index) mVUdeleteProg<1>(it[0]); 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 // Clears Block Data in specified range
static __fi void mVUclear(mV, u32 addr, u32 size) { static __fi void mVUclear(mV, u32 addr, u32 size) {
if (!mVU->prog.cleared) { if (!mVU->prog.cleared) {
@ -323,55 +303,40 @@ _mVUt __fi void* mVUsearchProg(u32 startPC, uptr pState) {
// recMicroVU0 / recMicroVU1 // recMicroVU0 / recMicroVU1
//------------------------------------------------------------------ //------------------------------------------------------------------
static u32 mvu0_allocated = 0;
static u32 mvu1_allocated = 0;
recMicroVU0::recMicroVU0() { m_Idx = 0; IsInterpreter = false; } recMicroVU0::recMicroVU0() { m_Idx = 0; IsInterpreter = false; }
recMicroVU1::recMicroVU1() { m_Idx = 1; IsInterpreter = false; } recMicroVU1::recMicroVU1() { m_Idx = 1; IsInterpreter = false; }
void recMicroVU0::Vsync() throw() { mVUvsyncUpdate(&microVU0); } void recMicroVU0::Vsync() throw() { mVUvsyncUpdate(&microVU0); }
void recMicroVU1::Vsync() throw() { mVUvsyncUpdate(&microVU1); } void recMicroVU1::Vsync() throw() { mVUvsyncUpdate(&microVU1); }
void recMicroVU0::Allocate() { void recMicroVU0::Reserve() {
if(!m_AllocCount) { if (AtomicExchange(m_Reserved, 1) == 0)
m_AllocCount++; microVU0.init(0);
if (AtomicExchange(mvu0_allocated, 1) == 0)
microVU0.init(0);
}
} }
void recMicroVU1::Allocate() { void recMicroVU1::Reserve() {
if(!m_AllocCount) { if (AtomicExchange(m_Reserved, 1) == 0)
m_AllocCount++; microVU1.init(1);
if (AtomicExchange(mvu1_allocated, 1) == 0)
microVU1.init(1);
}
} }
void recMicroVU0::Shutdown() throw() { void recMicroVU0::Shutdown() throw() {
if (m_AllocCount > 0) { if (AtomicExchange(m_Reserved, 0) == 1)
m_AllocCount--; microVU0.close();
if (AtomicExchange(mvu0_allocated, 0) == 1)
microVU0.close();
}
} }
void recMicroVU1::Shutdown() throw() { void recMicroVU1::Shutdown() throw() {
if (m_AllocCount > 0) { if (AtomicExchange(m_Reserved, 0) == 1)
m_AllocCount--; microVU1.close();
if (AtomicExchange(mvu1_allocated, 0) == 1)
microVU1.close();
}
} }
void recMicroVU0::Reset() { 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(); microVU0.reset();
} }
void recMicroVU1::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(); microVU1.reset();
} }
void recMicroVU0::Execute(u32 cycles) { 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; 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); ((mVUrecCall)microVU0.startFunct)(VU0.VI[REG_TPC].UL, cycles);
} }
void recMicroVU1::Execute(u32 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; if(!(VU0.VI[REG_VPU_STAT].UL & 0x100)) return;
((mVUrecCall)microVU1.startFunct)(VU1.VI[REG_TPC].UL, vu1RunCycles); ((mVUrecCall)microVU1.startFunct)(VU1.VI[REG_TPC].UL, vu1RunCycles);
} }
void recMicroVU0::Clear(u32 addr, u32 size) { void recMicroVU0::Clear(u32 addr, u32 size) {
pxAssert(mvu0_allocated); // please allocate me first! :| pxAssert(m_Reserved); // please allocate me first! :|
mVUclear(&microVU0, addr, size); mVUclear(&microVU0, addr, size);
} }
void recMicroVU1::Clear(u32 addr, u32 size) { void recMicroVU1::Clear(u32 addr, u32 size) {
pxAssert(mvu1_allocated); // please allocate me first! :| pxAssert(m_Reserved); // please allocate me first! :|
mVUclear(&microVU1, addr, size); mVUclear(&microVU1, 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;
}

View File

@ -28,7 +28,6 @@ using namespace x86Emitter;
#include "iR5900.h" #include "iR5900.h"
#include "R5900OpcodeTables.h" #include "R5900OpcodeTables.h"
#include "x86emitter/x86emitter.h" #include "x86emitter/x86emitter.h"
#include "SamplProf.h"
#include "microVU_Misc.h" #include "microVU_Misc.h"
#include "microVU_IR.h" #include "microVU_IR.h"
@ -150,11 +149,8 @@ struct microProgManager {
microRegInfo lpState; // Pipeline state from where program left off (useful for continuing execution) microRegInfo lpState; // Pipeline state from where program left off (useful for continuing execution)
}; };
#define mVUdispCacheSize (0x1000) // Dispatcher Cache Size static const uint mVUdispCacheSize = __pagesize; // Dispatcher Cache Size (in bytes)
#define mVUcacheSize ((index) ? (_1mb * 17) : (_1mb * 7)) // Initial Size (Excluding Safe-Zone) static const uint mVUcacheSafeZone = 3; // Safe-Zone for program recompilation (in megabytes)
#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
struct microVU { struct microVU {
@ -171,11 +167,13 @@ struct microVU {
u32 progMemMask; // VU Micro Memory Size (in u32's) u32 progMemMask; // VU Micro Memory Size (in u32's)
u32 cacheSize; // VU Cache Size u32 cacheSize; // VU Cache Size
microProgManager prog; // Micro Program Data microProgManager prog; // Micro Program Data
ScopedPtr<microRegAlloc> regAlloc; // Reg Alloc Class ScopedPtr<microRegAlloc> regAlloc; // Reg Alloc Class
ScopedPtr<AsciiFile> logFile; // Log File Pointer 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* dispCache; // Dispatchers Cache (where startFunct and exitFunct are written to)
u8* startFunct; // Ptr Function to the Start code for recompiled programs u8* startFunct; // Ptr Function to the Start code for recompiled programs
u8* exitFunct; // Ptr Function to the Exit 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."); pxAssumeDev((prog.IRinfo.curPC & 1) == 0, "microVU recompiler: Upper instructions cannot have valid branch addresses.");
return (((prog.IRinfo.curPC + 4) + (Imm11() * 2)) & progMemMask) * 4; 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 init(uint vuIndex);
void reset(); void reset();
void close(); void close();
@ -239,7 +247,6 @@ int mVUdebugNow = 0;
// Main Functions // Main Functions
static void mVUclear(mV, u32, u32); static void mVUclear(mV, u32, u32);
static void mVUresizeCache(mV, u32);
static void* mVUblockFetch(microVU* mVU, u32 startPC, uptr pState); static void* mVUblockFetch(microVU* mVU, u32 startPC, uptr pState);
_mVUt extern void* __fastcall mVUcompileJIT(u32 startPC, uptr pState); _mVUt extern void* __fastcall mVUcompileJIT(u32 startPC, uptr pState);

View File

@ -92,7 +92,7 @@ void mVUdispatcherB(mV) {
xRET(); 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: 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: 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); //mVUprint("microVU: VI0 = %x", mVU->regs().VI[0].UL);
mVU->prog.x86ptr = x86Ptr; 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->cycles = mVU->totalCycles - mVU->cycles;
mVU->regs().cycle += mVU->cycles; mVU->regs().cycle += mVU->cycles;
cpuRegs.cycle += ((mVU->cycles < 3000) ? mVU->cycles : 3000) * EmuConfig.Speedhacks.VUCycleSteal; cpuRegs.cycle += ((mVU->cycles < 3000) ? mVU->cycles : 3000) * EmuConfig.Speedhacks.VUCycleSteal;

View File

@ -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 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 mVUsaveReg(const xmm& reg, xAddressVoid ptr, int xyzw, bool modXYZW);
extern void mVUloadReg(const xmm& reg, xAddressVoid ptr, int xyzw); extern void mVUloadReg(const xmm& reg, xAddressVoid ptr, int xyzw);

View File

@ -251,7 +251,7 @@ __fi void mVUaddrFix(mV, const x32& gprReg)
else { else {
if (IsDevBuild && !isCOP2) mVUbackupRegs(mVU, true); if (IsDevBuild && !isCOP2) mVUbackupRegs(mVU, true);
xTEST(gprReg, 0x400); 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 xAND(gprReg, 0xff); // if !(addr & 0x4000), wrap around
xForwardJump8 jmpB; xForwardJump8 jmpB;
jmpA.SetTarget(); jmpA.SetTarget();
@ -481,7 +481,7 @@ static __pagealigned u8 mVUsearchXMM[__pagesize];
// Generates a custom optimized block-search function // Generates a custom optimized block-search function
// Note: Structs must be 16-byte aligned! (GCC doesn't guarantee this) // Note: Structs must be 16-byte aligned! (GCC doesn't guarantee this)
void mVUcustomSearch() { void mVUcustomSearch() {
HostSys::MemProtectStatic(mVUsearchXMM, Protect_ReadWrite, false); HostSys::MemProtectStatic(mVUsearchXMM, PageAccess_ReadWrite());
memset_8<0xcc,__pagesize>(mVUsearchXMM); memset_8<0xcc,__pagesize>(mVUsearchXMM);
xSetPtr(mVUsearchXMM); xSetPtr(mVUsearchXMM);
@ -526,5 +526,5 @@ void mVUcustomSearch() {
exitPoint.SetTarget(); exitPoint.SetTarget();
xRET(); xRET();
HostSys::MemProtectStatic(mVUsearchXMM, Protect_ReadOnly, true); HostSys::MemProtectStatic(mVUsearchXMM, PageAccess_ExecOnly());
} }

View File

@ -19,6 +19,8 @@
#include "VU.h" #include "VU.h"
#include "x86emitter/x86emitter.h" #include "x86emitter/x86emitter.h"
#include "System/RecTypes.h"
using namespace x86Emitter; using namespace x86Emitter;
#define aMax(x, y) std::max(x,y) #define aMax(x, y) std::max(x,y)
@ -28,13 +30,14 @@ using namespace x86Emitter;
typedef u32 (__fastcall *nVifCall)(void*, const void*); typedef u32 (__fastcall *nVifCall)(void*, const void*);
typedef void (__fastcall *nVifrecCall)(uptr dest, uptr src); typedef void (__fastcall *nVifrecCall)(uptr dest, uptr src);
#include "newVif_BlockBuffer.h"
#include "newVif_HashBucket.h" #include "newVif_HashBucket.h"
extern void mVUmergeRegs(const xRegisterSSE& dest, const xRegisterSSE& src, int xyzw, bool modXYZW = 0); 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 _nVifUnpack (int idx, const u8* data, uint mode, bool isFill);
extern void dVifReserve (int idx);
extern void dVifReset (int idx); extern void dVifReset (int idx);
extern void dVifClose (int idx); extern void dVifClose (int idx);
extern void dVifRelease (int idx);
extern void VifUnpackSSE_Init(); extern void VifUnpackSSE_Init();
_vifT extern void dVifUnpack (const u8* data, bool isFill); _vifT extern void dVifUnpack (const u8* data, bool isFill);
@ -76,23 +79,25 @@ struct nVifStruct {
u32 bSize; // Size of 'buffer' u32 bSize; // Size of 'buffer'
u32 bPtr; u32 bPtr;
u32 idx; // VIF0 or VIF1 uint recReserveSizeMB; // reserve size, in megabytes.
u8* recPtr; // Cur Pos to recompile to RecompiledCodeReserve* recReserve;
u8* recEnd; // 'Safe' End of Rec Cache u8* recWritePtr; // current write pos into the reserve
BlockBuffer* vifCache; // Block Buffer
HashBucket<_tParams>* vifBlocks; // Vif Blocks HashBucket<_tParams>* vifBlocks; // Vif Blocks
int numBlocks; // # of Blocks Recompiled int numBlocks; // # of Blocks Recompiled
nVifStruct() // VIF0 or VIF1 - provided for debugging helpfulness only, and is generally unused.
{ // (templates are used for most or all VIF indexing)
vifCache = NULL; u32 idx;
vifBlocks = NULL;
numBlocks = 0; nVifStruct();
recPtr = NULL;
recEnd = NULL;
}
}; };
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 nVifStruct nVif[2];
extern __aligned16 nVifCall nVifUpk[(2*2*16)*4]; // ([USN][Masking][Unpack Type]) [curCycle] extern __aligned16 nVifCall nVifUpk[(2*2*16)*4]; // ([USN][Masking][Unpack Type]) [curCycle]
extern __aligned16 u32 nVifMask[3][4][4]; // [MaskNumber][CycleNumber][Vector] extern __aligned16 u32 nVifMask[3][4][4]; // [MaskNumber][CycleNumber][Vector]

View File

@ -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; }
};

View File

@ -22,34 +22,37 @@
static __aligned16 nVifBlock _vBlock = {0}; static __aligned16 nVifBlock _vBlock = {0};
void dVifReset(int idx) { void dVifReserve(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].recReserve)
if( nVif[idx].vifCache && (nVif[idx].vifCache->getAllocSize() > _1mb*12) ) nVif[idx].recReserve = new RecompiledCodeReserve(pxsFmt(L"VIF%u Unpack Recompiler Cache", idx));
safe_delete(nVif[idx].vifCache);
if( !nVif[idx].vifCache ) nVif[idx].recReserve->Reserve( nVif[idx].recReserveSizeMB * _1mb, idx ? HostMemoryMap::VIF1rec : HostMemoryMap::VIF0rec );
nVif[idx].vifCache = new BlockBuffer(_1mb*4); }
else
nVif[idx].vifCache->clear(); void dVifReset(int idx) {
if( !nVif[idx].vifBlocks ) if( !nVif[idx].vifBlocks )
nVif[idx].vifBlocks = new HashBucket<_tParams>(); nVif[idx].vifBlocks = new HashBucket<_tParams>();
else else
nVif[idx].vifBlocks->clear(); nVif[idx].vifBlocks->clear();
nVif[idx].numBlocks = 0; nVif[idx].recReserve->Reset();
nVif[idx].numBlocks = 0;
nVif[idx].recPtr = nVif[idx].vifCache->getBlock(); nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr();
nVif[idx].recEnd = &nVif[idx].recPtr[nVif[idx].vifCache->getAllocSize()-(_1mb/4)]; // .25mb Safe Zone
} }
void dVifClose(int idx) { void dVifClose(int idx) {
nVif[idx].numBlocks = 0; nVif[idx].numBlocks = 0;
safe_delete(nVif[idx].vifCache); nVif[idx].recReserve->Reset();
safe_delete(nVif[idx].vifBlocks); safe_delete(nVif[idx].vifBlocks);
} }
void dVifRelease(int idx) {
safe_delete(nVif[idx].recReserve);
}
VifUnpackSSE_Dynarec::VifUnpackSSE_Dynarec(const nVifStruct& vif_, const nVifBlock& vifBlock_) VifUnpackSSE_Dynarec::VifUnpackSSE_Dynarec(const nVifStruct& vif_, const nVifBlock& vifBlock_)
: v(vif_) : v(vif_)
, vB(vifBlock_) , 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 // [TODO] : Finish implementing support for VIF's growable recBlocks buffer. Currently
// it clears the buffer only. // it clears the buffer only.
static __fi void dVifRecLimit(int idx) { static __fi void dVifRecLimit(int idx) {
if (nVif[idx].recPtr > nVif[idx].recEnd) { if (nVif[idx].recWritePtr > (nVif[idx].recReserve->GetPtrEnd() - _256kb)) {
DevCon.WriteLn("nVif Rec - Out of Rec Cache! [%x > %x]", nVif[idx].recPtr, nVif[idx].recEnd); DevCon.WriteLn("nVif Recompiler Cache Reset! [0x%08x > 0x%08x]", nVif[idx].recWritePtr, nVif[idx].recReserve->GetPtrEnd());
nVif[idx].vifBlocks->clear(); nVif[idx].recReserve->Reset();
nVif[idx].recPtr = nVif[idx].vifCache->getBlock(); nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr();
nVif[idx].recEnd = &nVif[idx].recPtr[nVif[idx].vifCache->getAllocSize()-(_1mb/4)]; // .25mb Safe Zone
} }
} }
@ -277,11 +279,11 @@ _vifT __fi void dVifUnpack(const u8* data, bool isFill) {
if (dVifExecuteUnpack<idx>(data, isFill)) return; if (dVifExecuteUnpack<idx>(data, isFill)) return;
xSetPtr(v.recPtr); xSetPtr(v.recWritePtr);
_vBlock.startPtr = (uptr)xGetAlignedCallTarget(); _vBlock.startPtr = (uptr)xGetAlignedCallTarget();
v.vifBlocks->add(_vBlock); v.vifBlocks->add(_vBlock);
VifUnpackSSE_Dynarec( v, _vBlock ).CompileRoutine(); 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, // [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. // which would be safer and more memory efficient than using an 0.25 meg recEnd marker.

View File

@ -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) void resetNewVif(int idx)
{ {
// Safety Reset : Reassign all VIF structure info, just in case the VU1 pointers have // 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); if (newVifDynaRec) dVifClose(idx);
} }
void releaseNewVif(int idx) {
if (newVifDynaRec) dVifRelease(idx);
}
static __fi u8* getVUptr(uint idx, int offset) { static __fi u8* getVUptr(uint idx, int offset) {
return (u8*)(vuRegs[idx].Mem + ( offset & (idx ? 0x3ff0 : 0xff0) )); return (u8*)(vuRegs[idx].Mem + ( offset & (idx ? 0x3ff0 : 0xff0) ));
} }

View File

@ -295,7 +295,7 @@ static void nVifGen(int usn, int mask, int curCycle) {
void VifUnpackSSE_Init() void VifUnpackSSE_Init()
{ {
HostSys::MemProtectStatic(nVifUpkExec, Protect_ReadWrite, false); HostSys::MemProtectStatic(nVifUpkExec, PageAccess_ReadWrite());
memset8<0xcc>( nVifUpkExec ); memset8<0xcc>( nVifUpkExec );
xSetPtr( nVifUpkExec ); xSetPtr( nVifUpkExec );
@ -306,5 +306,5 @@ void VifUnpackSSE_Init()
nVifGen(a, b, c); nVifGen(a, b, c);
}}} }}}
HostSys::MemProtectStatic(nVifUpkExec, Protect_ReadOnly, true); HostSys::MemProtectStatic(nVifUpkExec, PageAccess_ExecOnly());
} }

View File

@ -35,9 +35,9 @@
#include "R5900.h" #include "R5900.h"
#include "iR5900.h" #include "iR5900.h"
#include "System/RecTypes.h"
#include "sVU_zerorec.h" #include "sVU_zerorec.h"
#include "SamplProf.h"
#include "NakedAsm.h" #include "NakedAsm.h"
#include "AppConfig.h" #include "AppConfig.h"
@ -72,7 +72,7 @@ extern void iDumpVU1Registers();
#define SUPERVU_CHECKCONDITION 0 // has to be 0!! #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 _Imm11_ (s32)( (vucode & 0x400) ? (0xfffffc00 | (vucode & 0x3ff)) : (vucode & 0x3ff) )
#define _UImm11_ (s32)(vucode & 0x7ff) #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 u32 s_vuInfo; // info passed into rec insts
static const u32 s_MemSize[2] = {VU0_MEMSIZE, VU1_MEMSIZE}; 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. // tables which are defined at the bottom of this massive file.
extern void (*recVU_UPPER_OPCODE[64])(VURegs* VU, s32 info); 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_listVUHeaders[2];
static list<VuFunctionHeader*>* s_plistCachedHeaders[2] = {NULL, NULL}; static list<VuFunctionHeader*>* s_plistCachedHeaders[2] = {NULL, NULL};
static VuFunctionHeader** recVUHeaders[2] = {NULL, NULL}; static VuFunctionHeader** recVUHeaders[2] = { NULL, NULL };
static VuBlockHeader* recVUBlocks[2] = {NULL, NULL}; static VuBlockHeader* recVUBlocks[2] = { NULL, NULL };
static u8* recVUStack = NULL, *recVUStackPtr = NULL; static u8* recVUStack[2] = { NULL, NULL };
static u8* recVUStackPtr[2] = { NULL, NULL };
static vector<_x86regs> s_vecRegArray(128); static vector<_x86regs> s_vecRegArray(128);
static VURegs* VU = NULL; static VURegs* VU = NULL;
@ -343,47 +347,23 @@ static void SuperVURecompile();
// allocate VU resources // allocate VU resources
static void SuperVUAlloc(int vuindex) static void SuperVUAlloc(int vuindex)
{ {
// The old -1 crap has been depreciated on this function. Please if (s_recVUMem[vuindex]) return;
// specify either 0 or 1, thanks.
pxAssert(vuindex >= 0); 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! // upper 4 bits must be zero!
if (s_recVUMem == NULL) if (!s_recVUMem[vuindex]->IsOk())
{ {
// upper 4 bits must be zero! safe_delete(s_recVUMem[vuindex]);
// Changed "first try base" to 0xf1e0000, since 0x0c000000 liked to fail a lot. (cottonvibes) throw Exception::VirtualMemoryMapConflict( s_recVUMem[vuindex]->GetName() )
s_recVUMem = SysMmapEx(0xf1e0000, VU_EXESIZE, 0x10000000, "SuperVUAlloc"); .SetDiagMsg(pxsFmt( L"SuperVU failed to allocate virtual memory below 256MB." ))
.SetUserMsg(pxE( ".Error:superVU:VirtualMemoryAlloc",
// Try again at some other random memory location... whatever. >_< L"Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory "
if( s_recVUMem == NULL ) L"ranges required, and will not be available for use. This is not a critical error, since "
s_recVUMem = SysMmapEx(0xc2b0000, VU_EXESIZE, 0x10000000, "SuperVUAlloc"); L"the sVU rec is obsolete, and you should use microVU instead anyway. :)"
));
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];
} }
} }
@ -416,72 +396,64 @@ void DestroyVUHeaders(int vuindex)
// destroy VU resources // destroy VU resources
void SuperVUDestroy(int vuindex) void SuperVUDestroy(int vuindex)
{ {
list<VuFunctionHeader*>::iterator it; pxAssumeDev(vuindex >= 0 && vuindex <= 2, "Invalid VU index parameter!");
if (vuindex < 0) safe_delete_array(recVUHeaders[vuindex]);
{ safe_delete_array(recVUBlocks[vuindex]);
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]);
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);
{
DestroyCachedHeaders(vuindex, j);
}
safe_delete_array(s_plistCachedHeaders[vuindex]);
} }
DestroyVUHeaders(vuindex); safe_delete_array(s_plistCachedHeaders[vuindex]);
} }
DestroyVUHeaders(vuindex);
safe_delete(s_recVUMem[vuindex]);
safe_delete_array(recVUStack[vuindex]);
} }
// reset VU // reset VU
void SuperVUReset(int vuindex) void SuperVUReset(int vuindex)
{ {
pxAssumeDev(vuindex >= 0 && vuindex <= 2, "Invalid VU index parameter!");
#ifdef PCSX2_DEBUG #ifdef PCSX2_DEBUG
s_vucount = 0; s_vucount = 0;
#endif #endif
if (s_recVUMem == NULL) DevCon.WriteLn("SuperVU%d: Resetting function and block lists.", vuindex);
return;
//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."); for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j)
// 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) 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 // 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) static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex)
{ {
pxAssert(vuindex < 2); pxAssert(vuindex < 2);
pxAssert(s_recVUPtr != NULL); pxAssert(s_recVUPtr[vuindex] != NULL);
//Console.WriteLn("svu%c rec: %x", '0'+vuindex, startpc); //Console.WriteLn("svu%c rec: %x", '0'+vuindex, startpc);
// if recPtr reached the mem limit reset whole mem // 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(0);
SuperVUReset(1); SuperVUReset(1);
SuperVUReset(-1);
if (s_TotalVUCycles > 0) if (s_TotalVUCycles > 0)
{ {
// already executing, so return NULL // already executing, so return NULL
@ -912,12 +883,12 @@ static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex)
#endif #endif
// code generation // code generation
x86SetPtr(s_recVUPtr); xSetPtr(s_recVUPtr[vuindex]);
branch = 0; branch = 0;
SuperVURecompile(); SuperVURecompile();
s_recVUPtr = x86Ptr; s_recVUPtr[vuindex] = xGetPtr();
// set the function's range // set the function's range
VuFunctionHeader::RANGE r; VuFunctionHeader::RANGE r;
@ -947,7 +918,7 @@ static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex)
} }
s_listBlocks.clear(); 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; return s_pFnHeader;
} }
@ -2697,18 +2668,18 @@ void SuperVUFlush(int p, int wait)
// executed only once per program // executed only once per program
static u32* SuperVUStaticAlloc(u32 size) static u32* SuperVUStaticAlloc(u32 size)
{ {
pxAssert(recVUStackPtr + size <= recVUStack + SUPERVU_STACKSIZE); pxAssert(recVUStackPtr[s_vu] + size <= recVUStack[s_vu] + SUPERVU_STACKSIZE);
// always zero // always zero
if (size == 4) *(u32*)recVUStackPtr = 0; if (size == 4) *(u32*)recVUStackPtr[s_vu] = 0;
else memset(recVUStackPtr, 0, size); else memset(recVUStackPtr[s_vu], 0, size);
recVUStackPtr += size; recVUStackPtr[s_vu] += size;
return (u32*)(recVUStackPtr - size); return (u32*)(recVUStackPtr[s_vu] - size);
} }
static void SuperVURecompile() static void SuperVURecompile()
{ {
// save cpu state // save cpu state
recVUStackPtr = recVUStack; recVUStackPtr[s_vu] = recVUStack[s_vu];
_initXMMregs(); _initXMMregs();
@ -4617,9 +4588,9 @@ recSuperVU0::recSuperVU0()
IsInterpreter = false; IsInterpreter = false;
} }
void recSuperVU0::Allocate() void recSuperVU0::Reserve()
{ {
SuperVUAlloc( 0 ); SuperVUAlloc(0);
} }
void recSuperVU0::Shutdown() throw() void recSuperVU0::Shutdown() throw()
@ -4645,6 +4616,15 @@ void recSuperVU0::Clear(u32 Addr, u32 Size)
SuperVUClear(Addr, Size, 0); SuperVUClear(Addr, Size, 0);
} }
uint recSuperVU0::GetCacheReserve() const
{
return sVU_EXESIZE / _1mb;
}
void recSuperVU0::SetCacheReserve( uint reserveInMegs ) const
{
//microVU0.cacheSize = reserveInMegs * _1mb;
}
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// recSuperVU1 Interface // recSuperVU1 Interface
@ -4655,9 +4635,9 @@ recSuperVU1::recSuperVU1()
IsInterpreter = false; IsInterpreter = false;
} }
void recSuperVU1::Allocate() void recSuperVU1::Reserve()
{ {
SuperVUAlloc( 1 ); SuperVUAlloc(1);
} }
void recSuperVU1::Shutdown() throw() void recSuperVU1::Shutdown() throw()
@ -4670,6 +4650,16 @@ void recSuperVU1::Reset()
SuperVUReset( 1 ); SuperVUReset( 1 );
} }
uint recSuperVU1::GetCacheReserve() const
{
return sVU_EXESIZE / _1mb;
}
void recSuperVU1::SetCacheReserve( uint reserveInMegs ) const
{
//microVU0.cacheSize = reserveInMegs * _1mb;
}
#if 0 #if 0
#include "sVU_Compare.h" #include "sVU_Compare.h"
#else #else

View File

@ -53,7 +53,6 @@
<Unit filename="ini.cpp" /> <Unit filename="ini.cpp" />
<Unit filename="linux.cpp" /> <Unit filename="linux.cpp" />
<Unit filename="linux.h" /> <Unit filename="linux.h" />
<Unit filename="onepad.glade" />
<Unit filename="../analog.cpp" /> <Unit filename="../analog.cpp" />
<Unit filename="../analog.h" /> <Unit filename="../analog.h" />
<Unit filename="../bitwise.h" /> <Unit filename="../bitwise.h" />
@ -68,6 +67,7 @@
<Extensions> <Extensions>
<code_completion /> <code_completion />
<debugger /> <debugger />
<envvars />
</Extensions> </Extensions>
</Project> </Project>
</CodeBlocks_project_file> </CodeBlocks_project_file>

View File

@ -132,9 +132,6 @@
</Unit> </Unit>
<Unit filename="../../Win32/Win32.h" /> <Unit filename="../../Win32/Win32.h" />
<Unit filename="../../Win32/aviUtil.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/resource.h" />
<Unit filename="../../Win32/resrc1.h" /> <Unit filename="../../Win32/resrc1.h" />
<Unit filename="../../Win32/wglext.h" /> <Unit filename="../../Win32/wglext.h" />
@ -177,6 +174,7 @@
<Extensions> <Extensions>
<code_completion /> <code_completion />
<debugger /> <debugger />
<envvars />
</Extensions> </Extensions>
</Project> </Project>
</CodeBlocks_project_file> </CodeBlocks_project_file>