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

File diff suppressed because it is too large Load Diff

View File

@ -160,7 +160,7 @@ public:
~ScopedBool() throw()
{
m_boolme = false;
*m_boolme = false;
}
};
@ -177,6 +177,21 @@ public:
#include "Pcsx2Defs.h"
static const sptr _64kb = 0x10000;
static const sptr _16kb = _64kb / 4;
static const sptr _128kb = _64kb * 2;
static const sptr _256kb = _128kb * 2;
static const s64 _1mb = 0x100000;
static const s64 _8mb = _1mb * 8;
static const s64 _16mb = _1mb * 16;
static const s64 _32mb = _1mb * 32;
static const s64 _64mb = _1mb * 64;
static const s64 _256mb = _1mb * 256;
static const s64 _1gb = _256mb * 4;
static const s64 _4gb = _1gb * 4;
// ===========================================================================================
// i18n/Translation Feature Set!
// ===========================================================================================

View File

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

View File

@ -133,14 +133,84 @@ protected:
virtual void DoDeletion();
};
enum PageProtectionMode
// --------------------------------------------------------------------------------------
// PageProtectionMode
// --------------------------------------------------------------------------------------
class PageProtectionMode
{
Protect_NoAccess = 0,
Protect_ReadOnly,
Protect_ReadWrite
protected:
bool m_read;
bool m_write;
bool m_exec;
public:
PageProtectionMode()
{
All( false );
}
PageProtectionMode& Read( bool allow=true )
{
m_read = allow;
return *this;
}
PageProtectionMode& Write( bool allow=true )
{
m_write = allow;
return *this;
}
PageProtectionMode& Execute( bool allow=true )
{
m_exec = allow;
return *this;
}
PageProtectionMode& All( bool allow=true )
{
m_read = m_write = m_exec = allow;
return *this;
}
bool CanRead() const { return m_read; }
bool CanWrite() const { return m_write; }
bool CanExecute() const { return m_exec && m_read; }
bool IsNone() const { return !m_read && !m_write; }
wxString ToString() const;
};
static __fi PageProtectionMode PageAccess_None()
{
return PageProtectionMode();
}
static __fi PageProtectionMode PageAccess_ReadOnly()
{
return PageProtectionMode().Read();
}
static __fi PageProtectionMode PageAccess_WriteOnly()
{
return PageProtectionMode().Write();
}
static __fi PageProtectionMode PageAccess_ReadWrite()
{
return PageAccess_ReadOnly().Write();
}
static __fi PageProtectionMode PageAccess_ExecOnly()
{
return PageAccess_ReadOnly().Execute();
}
static __fi PageProtectionMode PageAccess_Any()
{
return PageProtectionMode().All();
}
// --------------------------------------------------------------------------------------
// HostSys
// --------------------------------------------------------------------------------------
@ -148,22 +218,29 @@ enum PageProtectionMode
// platform prior to wxWidgets .. it should prolly be removed -- air)
namespace HostSys
{
void* MmapReserve(uptr base, size_t size);
bool MmapCommit(uptr base, size_t size, const PageProtectionMode& mode);
void MmapReset(uptr base, size_t size);
void* MmapReservePtr(void* base, size_t size);
bool MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode);
void MmapResetPtr(void* base, size_t size);
// Maps a block of memory for use as a recompiled code buffer.
// The allocated block has code execution privileges.
// Returns NULL on allocation failure.
extern void *Mmap(uptr base, u32 size);
extern void* Mmap(uptr base, size_t size);
// Unmaps a block allocated by SysMmap
extern void Munmap(uptr base, u32 size);
extern void Munmap(uptr base, size_t size);
extern void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution=false );
extern void MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode );
extern void Munmap( void* base, u32 size );
extern void Munmap( void* base, size_t size );
template< uint size >
void MemProtectStatic( u8 (&arr)[size], PageProtectionMode mode, bool allowExecution=false )
void MemProtectStatic( u8 (&arr)[size], const PageProtectionMode& mode )
{
MemProtect( arr, size, mode, allowExecution );
MemProtect( arr, size, mode );
}
}

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 ); }
wxDirName operator+( const wxDirName& right ) const { return Combine( right ); }
wxFileName operator+( const wxString& right ) const { return Combine( wxFileName(right) ); }
bool operator==(const wxDirName& filename) const { return SameAs(filename); }
bool operator!=(const wxDirName& filename) const { return !SameAs(filename); }
@ -122,7 +123,7 @@ public:
// --------------------------------------------------------------------------------------
// Cross-platform utilities for manipulation of paths and filenames. Mostly these fall
// back on wxWidgets APIs internally, but are still helpful because some of wx's file stuff
// has minor glitches, or requies sloppy wxFileName typecasting.
// has minor glitches, or requires sloppy wxFileName typecasting.
//
namespace Path
{

View File

@ -31,7 +31,8 @@ SafeArray<T>::SafeArray( const wxChar* name, T* allocated_mem, int initSize )
m_size = initSize;
if( m_ptr == NULL )
throw Exception::OutOfMemory(name + wxsFormat(L" (SafeArray::constructor) [size=%d]", initSize));
throw Exception::OutOfMemory(name)
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initSize));
}
template< typename T >
@ -79,7 +80,8 @@ SafeArray<T>::SafeArray( int initialSize, const wxChar* name )
m_size = initialSize;
if( (initialSize != 0) && (m_ptr == NULL) )
throw Exception::OutOfMemory(name + wxsFormat(L" (SafeArray::constructor) [size=%d]", initialSize));
throw Exception::OutOfMemory(name)
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initialSize));
}
// Clears the contents of the array to zero, and frees all memory allocations.
@ -106,9 +108,8 @@ void SafeArray<T>::ExactAlloc( int newsize )
m_ptr = _virtual_realloc( newsize );
if( m_ptr == NULL )
throw Exception::OutOfMemory(Name +
wxsFormat(L" (SafeArray::ExactAlloc) [oldsize=%d] [newsize=%d]", m_size, newsize)
);
throw Exception::OutOfMemory(Name)
.SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ExactAlloc' [oldsize=%d] [newsize=%d]", m_size, newsize));
m_size = newsize;
}
@ -199,9 +200,8 @@ SafeList<T>::SafeList( int initialSize, const wxChar* name )
m_ptr = (T*)malloc( initialSize * sizeof(T) );
if( m_ptr == NULL )
throw Exception::OutOfMemory(Name +
wxsFormat(L" (SafeList::Constructor) [length=%d]", m_length)
);
throw Exception::OutOfMemory(Name)
.SetDiagMsg(wxsFormat(L"called from 'SafeList::ctor' [length=%d]", m_length));
for( int i=0; i<m_allocsize; ++i )
{
@ -227,9 +227,8 @@ void SafeList<T>::MakeRoomFor( int blockSize )
const int newalloc = blockSize + ChunkSize;
m_ptr = _virtual_realloc( newalloc );
if( m_ptr == NULL )
throw Exception::OutOfMemory(Name +
wxsFormat(L" (SafeList::MakeRoomFor) [oldlen=%d] [newlen=%d]", m_length, blockSize)
);
throw Exception::OutOfMemory(Name)
.SetDiagMsg(wxsFormat(L"Called from 'SafeList::MakeRoomFor' [oldlen=%d] [newlen=%d]", m_length, blockSize));
for( ; m_allocsize<newalloc; ++m_allocsize )
{

View File

@ -60,6 +60,26 @@ extern void pcsx2_aligned_free(void* pmem);
# define _aligned_realloc pcsx2_aligned_realloc
#endif
// --------------------------------------------------------------------------------------
// pxDoOutOfMemory
// --------------------------------------------------------------------------------------
typedef void FnType_OutOfMemory( uptr blocksize );
typedef FnType_OutOfMemory* Fnptr_OutOfMemory;
// This method is meant to be assigned by applications that link against pxWex. It is called
// (invoked) prior to most pxWex built-in memory/array classes throwing exceptions, and can be
// used by an application to remove unneeded memory allocations and/or reduce internal cache
// reserves.
//
// Example: PCSX2 uses several bloated recompiler code caches. Larger caches improve performance,
// however a rouge cache growth could cause memory constraints in the operating system. If an out-
// of-memory error occurs, PCSX2's implementation of this function attempts to reset all internal
// recompiler caches. This can typically free up 100-150 megs of memory, and will allow the app
// to continue running without crashing or hanging the operating system, etc.
//
extern Fnptr_OutOfMemory pxDoOutOfMemory;
// --------------------------------------------------------------------------------------
// BaseScopedAlloc

View File

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

View File

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

View File

@ -23,6 +23,9 @@
#include <signal.h>
#endif
// for lack of a better place...
Fnptr_OutOfMemory pxDoOutOfMemory = NULL;
static wxString GetTranslation( const wxChar* msg )
{
return msg ? wxGetTranslation( msg ) : wxEmptyString;
@ -68,12 +71,6 @@ wxString DiagnosticOrigin::ToString( const wxChar* msg ) const
}
bool pxAssertImpl_LogIt( const DiagnosticOrigin& origin, const wxChar *msg )
{
wxLogError( L"%s", origin.ToString( msg ).c_str() );
return false;
}
// Because wxTrap isn't available on Linux builds of wxWidgets (non-Debug, typically)
void pxTrap()
{
@ -94,6 +91,16 @@ void pxTrap()
#endif // Win/Unix
}
bool pxAssertImpl_LogIt( const DiagnosticOrigin& origin, const wxChar *msg )
{
//wxLogError( L"%s", origin.ToString( msg ).c_str() );
wxMessageOutputDebug().Printf( L"%s", origin.ToString( msg ).c_str() );
pxTrap();
return false;
}
DEVASSERT_INLINE void pxOnAssert( const DiagnosticOrigin& origin, const wxChar* msg )
{
// Recursion guard: Allow at least one recursive call. This is useful because sometimes
@ -191,19 +198,69 @@ Exception::RuntimeError::RuntimeError( const std::exception& ex, const wxString&
Exception::OutOfMemory::OutOfMemory( const wxString& allocdesc )
{
AllocDescription = allocdesc;
m_message_diag = L"Out of memory exception, while allocating the %s.";
m_message_user = _("Memory allocation failure! Your system has insufficient memory or resources to meet PCSX2's lofty needs.");
}
wxString Exception::OutOfMemory::FormatDiagnosticMessage() const
{
return wxsFormat(m_message_diag, AllocDescription.c_str());
FastFormatUnicode retmsg;
retmsg.Write(L"Out of memory");
if (!AllocDescription.IsEmpty())
retmsg.Write(L" while allocating '%s'", AllocDescription.c_str());
if (!m_message_diag.IsEmpty())
retmsg.Write(L":\n%s", m_message_diag.c_str());
return retmsg;
}
wxString Exception::OutOfMemory::FormatDisplayMessage() const
{
if (m_message_user.IsEmpty()) return FormatDisplayMessage();
return m_message_user + pxsFmt( L"\n\nInternal allocation descriptor: %s", AllocDescription.c_str());
FastFormatUnicode retmsg;
retmsg.Write( L"%s", _("Oh noes! Out of memory!") );
if (!m_message_diag.IsEmpty())
retmsg.Write(L"\n\n%s", m_message_diag.c_str());
return retmsg;
}
// --------------------------------------------------------------------------------------
// Exception::VirtualMemoryMapConflict (implementations)
// --------------------------------------------------------------------------------------
Exception::VirtualMemoryMapConflict::VirtualMemoryMapConflict( const wxString& allocdesc )
{
AllocDescription = allocdesc;
m_message_user = _("Virtual memory mapping failure! Your system may have conflicting device drivers, services, or may simply have insufficient memory or resources to meet PCSX2's lofty needs.");
}
wxString Exception::VirtualMemoryMapConflict::FormatDiagnosticMessage() const
{
FastFormatUnicode retmsg;
retmsg.Write(L"Virtual memory map failed");
if (!AllocDescription.IsEmpty())
retmsg.Write(L" while reserving '%s'", AllocDescription.c_str());
if (!m_message_diag.IsEmpty())
retmsg.Write(L":\n%s", m_message_diag.c_str());
return retmsg;
}
wxString Exception::VirtualMemoryMapConflict::FormatDisplayMessage() const
{
FastFormatUnicode retmsg;
retmsg.Write( L"%s",
pxE( ".Error:VirtualMemoryMap",
L"There is not enough virtual memory available, or necessary virtual memory "
L"mappings have already been reserved by other processes, services, or DLLs."
)
);
if (!m_message_diag.IsEmpty())
retmsg.Write(L"\n\n%s", m_message_diag.c_str());
return retmsg;
}
@ -218,20 +275,120 @@ wxString Exception::CancelEvent::FormatDisplayMessage() const
return L"Action canceled: " + m_message_diag;
}
wxString Exception::Stream::FormatDiagnosticMessage() const
// --------------------------------------------------------------------------------------
// Exception::BadStream (implementations)
// --------------------------------------------------------------------------------------
wxString Exception::BadStream::FormatDiagnosticMessage() const
{
return pxsFmt(
L"%s\n\tFile/Object: %s",
m_message_diag.c_str(), StreamName.c_str()
);
FastFormatUnicode retval;
_formatDiagMsg(retval);
return retval;
}
wxString Exception::Stream::FormatDisplayMessage() const
wxString Exception::BadStream::FormatDisplayMessage() const
{
wxString retval( m_message_user );
if (!StreamName.IsEmpty())
retval += L"\n\n" + pxsFmt( _("Path: %s"), StreamName.c_str() );
FastFormatUnicode retval;
_formatUserMsg(retval);
return retval;
}
void Exception::BadStream::_formatDiagMsg( FastFormatUnicode& dest ) const
{
dest.Write( L"Path: " );
if (!StreamName.IsEmpty())
dest.Write( L"%s", StreamName.c_str() );
else
dest.Write( L"[Unnamed or unknown]" );
if (!m_message_diag.IsEmpty())
dest.Write(L"\n%s", m_message_diag.c_str());
}
void Exception::BadStream::_formatUserMsg( FastFormatUnicode& dest ) const
{
dest.Write( _("Path: ") );
if (!StreamName.IsEmpty())
dest.Write( L"%s", StreamName.c_str() );
else
dest.Write( _("[Unnamed or unknown]") );
if (!m_message_user.IsEmpty())
dest.Write(L"\n%s", m_message_user.c_str());
}
// --------------------------------------------------------------------------------------
// Exception::CannotCreateStream (implementations)
// --------------------------------------------------------------------------------------
wxString Exception::CannotCreateStream::FormatDiagnosticMessage() const
{
FastFormatUnicode retval;
retval.Write("File could not be created.");
_formatDiagMsg(retval);
return retval;
}
wxString Exception::CannotCreateStream::FormatDisplayMessage() const
{
FastFormatUnicode retval;
retval.Write(_("A file could not be created."));
_formatUserMsg(retval);
return retval;
}
// --------------------------------------------------------------------------------------
// Exception::FileNotFound (implementations)
// --------------------------------------------------------------------------------------
wxString Exception::FileNotFound::FormatDiagnosticMessage() const
{
FastFormatUnicode retval;
retval.Write("File not found.");
_formatDiagMsg(retval);
return retval;
}
wxString Exception::FileNotFound::FormatDisplayMessage() const
{
FastFormatUnicode retval;
retval.Write(_("File not found."));
_formatUserMsg(retval);
return retval;
}
// --------------------------------------------------------------------------------------
// Exception::AccessDenied (implementations)
// --------------------------------------------------------------------------------------
wxString Exception::AccessDenied::FormatDiagnosticMessage() const
{
FastFormatUnicode retval;
retval.Write("Permission denied to file.");
_formatDiagMsg(retval);
return retval;
}
wxString Exception::AccessDenied::FormatDisplayMessage() const
{
FastFormatUnicode retval;
retval.Write(_("Permission denied while trying to open file, likely due to insufficient user account rights."));
_formatUserMsg(retval);
return retval;
}
// --------------------------------------------------------------------------------------
// Exception::EndOfStream (implementations)
// --------------------------------------------------------------------------------------
wxString Exception::EndOfStream::FormatDiagnosticMessage() const
{
FastFormatUnicode retval;
retval.Write("Unexpected end of file or stream.");
_formatDiagMsg(retval);
return retval;
}
wxString Exception::EndOfStream::FormatDisplayMessage() const
{
FastFormatUnicode retval;
retval.Write(_("Unexpected end of file or stream encountered. File is probably truncated or corrupted."));
_formatUserMsg(retval);
return retval;
}
@ -249,7 +406,7 @@ BaseException* Exception::FromErrno( const wxString& streamname, int errcode )
{
case EINVAL:
pxFailDev( L"Invalid argument" );
return &(new Exception::Stream( streamname ))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)" );
return &(new Exception::BadStream( streamname ))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)" );
case EACCES: // Access denied!
return new Exception::AccessDenied( streamname );
@ -270,6 +427,6 @@ BaseException* Exception::FromErrno( const wxString& streamname, int errcode )
return &(new Exception::BadStream( streamname ))->SetDiagMsg(L"Bad file number");
default:
return &(new Exception::Stream( streamname ))->SetDiagMsg(pxsFmt( L"General file/stream error [errno: %d]", errcode ));
return &(new Exception::BadStream( streamname ))->SetDiagMsg(pxsFmt( L"General file/stream error [errno: %d]", errcode ));
}
}

View File

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

View File

@ -15,50 +15,204 @@
#include "../PrecompiledHeader.h"
#include "PageFaultSource.h"
#include <wx/thread.h>
#include <sys/mman.h>
#include <signal.h>
#include <errno.h>
namespace HostSys
extern void SignalExit(int sig);
static const uptr m_pagemask = getpagesize()-1;
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
static void SysPageFaultSignalFilter( int signal, siginfo_t *siginfo, void * )
{
static const uptr m_pagemask = getpagesize()-1;
// [TODO] : Add a thread ID filter to the Linux Signal handler here.
// Rationale: On windows, the __try/__except model allows per-thread specific behavior
// for page fault handling. On linux, there is a single signal handler for the whole
// process, but the handler is executed by the thread that caused the exception.
void *Mmap(uptr base, u32 size)
// Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done
// from the context of the current thread and stackframe. So long as the thread is not
// the main/ui thread, use of the px assertion system should be safe. Use of stdio should
// be safe even on the main thread.
// (in other words, stdio limitations only really apply to process-level asynchronous
// signals)
// Note: Use of stdio functions isn't safe here. Avoid console logs,
// assertions, file logs, or just about anything else useful.
Source_PageFault->Dispatch( PageFaultInfo( (uptr)siginfo->si_addr & ~m_pagemask ) );
// resumes execution right where we left off (re-executes instruction that
// caused the SIGSEGV).
if (Source_PageFault->WasHandled()) return;
if (!wxThread::IsMain())
{
u8 *Mem;
Mem = (u8*)mmap((uptr*)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
if (Mem == MAP_FAILED) Console.Warning("Mmap Failed!");
return Mem;
pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr));
}
void Munmap(uptr base, u32 size)
{
munmap((uptr*)base, size);
}
// Bad mojo! Completely invalid address.
// Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution )
wxTrap();
if (!IsDebugBuild) raise( SIGKILL );
}
void _platform_InstallSignalHandler()
{
Console.WriteLn("Installing POSIX SIGSEGV handler...");
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = SysPageFaultSignalFilter;
sigaction(SIGSEGV, &sa, NULL);
}
static __ri void PageSizeAssertionTest( size_t size )
{
pxAssertMsg( (__pagesize == getpagesize()), pxsFmt(
"Internal system error: Operating system pagesize does not match compiled pagesize.\n\t"
L"\tOS Page Size: 0x%x (%d), Compiled Page Size: 0x%x (%u)",
getpagesize(), getpagesize(), __pagesize, __pagesize )
);
pxAssertDev( (size & (__pagesize-1)) == 0, pxsFmt(
L"Memory block size must be a multiple of the target platform's page size.\n"
L"\tPage Size: 0x%x (%u), Block Size: 0x%x (%u)",
__pagesize, __pagesize, size, size )
);
}
// returns FALSE if the mprotect call fails with an ENOMEM.
// Raises assertions on other types of POSIX errors (since those typically reflect invalid object
// or memory states).
static bool _memprotect( void* baseaddr, size_t size, const PageProtectionMode& mode )
{
PageSizeAssertionTest(size);
uint lnxmode = 0;
if (mode.CanWrite()) lnxmode |= PROT_WRITE;
if (mode.CanRead()) lnxmode |= PROT_READ;
if (mode.CanExecute()) lnxmode |= PROT_EXEC | PROT_READ;
const int result = mprotect( baseaddr, size, lnxmode );
if (result == 0) return true;
switch(errno)
{
pxAssertDev( (size & (__pagesize-1)) == 0, wxsFormat(
L"Memory block size must be a multiple of the target platform's page size.\n"
L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)",
__pagesize, __pagesize, size, size )
case EINVAL:
pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)",
baseaddr, (uptr)baseaddr+size, mode.ToString().c_str())
);
break;
case EACCES:
pxFailDev(pxsFmt(L"mprotect returned EACCES @ 0x%08X -> 0x%08X (mode=%s)",
baseaddr, (uptr)baseaddr+size, mode.ToString().c_str())
);
break;
case ENOMEM:
// caller handles assertion or exception, or whatever.
break;
}
return false;
}
void* HostSys::MmapReservePtr(void* base, size_t size)
{
PageSizeAssertionTest(size);
// On linux a reserve-without-commit is performed by using mmap on a read-only
// or anonymous source, with PROT_NONE (no-access) permission. Since the mapping
// is completely inaccessible, the OS will simply reserve it and will not put it
// against the commit table.
return mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
}
bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode)
{
// In linux, reserved memory is automatically committed when its permissions are
// changed to something other than PROT_NONE. If the user is committing memory
// as PROT_NONE, then just ignore this call (memory will be committed automatically
// later when the user changes permissions to something useful via calls to MemProtect).
if (mode.IsNone()) return false;
if (_memprotect( base, size, mode )) return true;
if (!pxDoOutOfMemory) return false;
pxDoOutOfMemory(size);
return _memprotect( base, size, mode );
}
void HostSys::MmapResetPtr(void* base, size_t size)
{
// On linux the only way to reset the memory is to unmap and remap it as PROT_NONE.
// That forces linux to unload all committed pages and start from scratch.
// FIXME: Ideally this code would have some threading lock on it to prevent any other
// malloc/free code in the current process from interfering with the operation, but I
// can't think of any good way to do that. (generally it shouldn't be a problem in
// PCSX2 anyway, since MmapReset is only called when the ps2vm is suspended; so that
// pretty well stops all PCSX2 threads anyway).
Munmap(base, size);
void* result = Mmap((uptr)base, size);
pxAssertRel ((uptr)result != (uptr)base, pxsFmt(
"Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped. "
"This is likely caused by multi-thread memory contention.", base, (uptr)base+size
));
}
void* HostSys::MmapReserve(uptr base, size_t size)
{
return MmapReservePtr((void*)base, size);
}
bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode)
{
return MmapCommitPtr( (void*)base, size, mode );
}
void HostSys::MmapReset(uptr base, size_t size)
{
MmapResetPtr((void*)base, size);
}
void* HostSys::Mmap(uptr base, size_t size)
{
PageSizeAssertionTest(size);
// MAP_ANONYMOUS - means we have no associated file handle (or device).
return mmap((void*)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
}
void HostSys::Munmap(uptr base, size_t size)
{
if (!base) return;
munmap((void*)base, size);
}
void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode )
{
if (!_memprotect(baseaddr, size, mode))
{
throw Exception::OutOfMemory( L"MemProtect" )
.SetDiagMsg(pxsFmt( L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)",
baseaddr, (uptr)baseaddr+size, mode.ToString().c_str()
)
);
int lnxmode = 0;
// make sure size is aligned to the system page size:
// Check is redundant against the assertion above, but might as well...
size = (size + m_pagemask) & ~m_pagemask;
switch( mode )
{
case Protect_NoAccess: break;
case Protect_ReadOnly: lnxmode = PROT_READ; break;
case Protect_ReadWrite: lnxmode = PROT_READ | PROT_WRITE; break;
}
if( allowExecution ) lnxmode |= PROT_EXEC;
mprotect( baseaddr, size, lnxmode );
}
}

View File

@ -143,7 +143,7 @@ wxString Path::Combine( const wxDirName& srcPath, const wxFileName& srcFile )
wxString Path::Combine( const wxString& srcPath, const wxDirName& srcFile )
{
return ((wxDirName)srcPath + srcFile).ToString();
return (wxDirName( srcPath ) + srcFile).ToString();
}
// Replaces the extension of the file with the one given.

View File

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

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 "Utilities/RedtapeWindows.h"
#include "PageFaultSource.h"
#include <winnt.h>
namespace HostSys
int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
{
void *Mmap(uptr base, u32 size)
if( eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION )
return EXCEPTION_CONTINUE_SEARCH;
Source_PageFault->Dispatch( PageFaultInfo( (uptr)eps->ExceptionRecord->ExceptionInformation[1] ) );
return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
}
void _platform_InstallSignalHandler()
{
// NOP on Win32 systems -- we use __try{} __except{} instead.
}
static DWORD ConvertToWinApi( const PageProtectionMode& mode )
{
DWORD winmode = PAGE_NOACCESS;
// Windows has some really bizarre memory protection enumeration that uses bitwise
// numbering (like flags) but is in fact not a flag value. *Someone* from the early
// microsoft days wasn't a very good coder, me thinks. --air
if (mode.CanExecute())
{
return VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
}
else if (mode.CanRead())
{
winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY;
}
void Munmap(uptr base, u32 size)
return winmode;
}
void* HostSys::MmapReservePtr(void* base, size_t size)
{
return VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
}
bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode)
{
void* result = VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode));
if (result) return true;
const DWORD errcode = GetLastError();
if (errcode == ERROR_COMMITMENT_MINIMUM)
{
if( base == NULL ) return;
VirtualFree((void*)base, size, MEM_DECOMMIT);
VirtualFree((void*)base, 0, MEM_RELEASE);
Console.Warning("(MmapCommit) Received windows error %u {Virtual Memory Minimum Too Low}.", ERROR_COMMITMENT_MINIMUM);
Sleep(1000); // Cut windows some time to rework its memory...
}
else if (errcode != ERROR_NOT_ENOUGH_MEMORY && errcode != ERROR_OUTOFMEMORY)
{
pxFailDev(L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows());
return false;
}
void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution )
if (!pxDoOutOfMemory) return false;
pxDoOutOfMemory(size);
return VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)) != NULL;
}
void HostSys::MmapResetPtr(void* base, size_t size)
{
VirtualFree(base, size, MEM_DECOMMIT);
}
void* HostSys::MmapReserve(uptr base, size_t size)
{
return MmapReservePtr((void*)base, size);
}
bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode)
{
return MmapCommitPtr( (void*)base, size, mode );
}
void HostSys::MmapReset(uptr base, size_t size)
{
MmapResetPtr((void*)base, size);
}
void* HostSys::Mmap(uptr base, size_t size)
{
return VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
}
void HostSys::Munmap(uptr base, size_t size)
{
if (!base) return;
//VirtualFree((void*)base, size, MEM_DECOMMIT);
VirtualFree((void*)base, 0, MEM_RELEASE);
}
void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode )
{
pxAssertDev( ((size & (__pagesize-1)) == 0), pxsFmt(
L"Memory block size must be a multiple of the target platform's page size.\n"
L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)",
__pagesize, __pagesize, size, size )
);
DWORD OldProtect; // enjoy my uselessness, yo!
if (!VirtualProtect( baseaddr, size, ConvertToWinApi(mode), &OldProtect ))
{
pxAssertDev( ((size & (__pagesize-1)) == 0), wxsFormat(
L"Memory block size must be a multiple of the target platform's page size.\n"
L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)",
__pagesize, __pagesize, size, size )
);
Exception::WinApiError apiError;
apiError.SetDiagMsg(
pxsFmt(L"VirtualProtect failed @ 0x%08X -> 0x%08X (mode=%s)",
baseaddr, (uptr)baseaddr + size, mode.ToString().c_str()
));
DWORD winmode = 0;
switch( mode )
{
case Protect_NoAccess:
winmode = ( allowExecution ) ? PAGE_EXECUTE : PAGE_NOACCESS;
break;
case Protect_ReadOnly:
winmode = ( allowExecution ) ? PAGE_EXECUTE_READ : PAGE_READONLY;
break;
case Protect_ReadWrite:
winmode = ( allowExecution ) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
break;
}
DWORD OldProtect; // enjoy my uselessness, yo!
VirtualProtect( baseaddr, size, winmode, &OldProtect );
pxFailDev( apiError.FormatDiagnosticMessage() );
}
}

View File

@ -675,7 +675,7 @@ void wxAppWithHelpers::OnDeleteThread( wxCommandEvent& evt )
return;
}
pxThreadLog.Write(thr->GetName(), (wxString)L"Thread object deleted successfully" + (thr->HasPendingException() ? wxEmptyString : L"[exception pending!]"));
pxThreadLog.Write(thr->GetName(), (wxString)L"Thread object deleted successfully" + (thr->HasPendingException() ? L" [exception pending!]" : wxEmptyString));
thr->RethrowException();
}

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -24,48 +24,6 @@
#pragma once
#include <xmmintrin.h>
template< typename T >
__noinline void memzero_sse_a( T& dest )
{
#define MZFqwc (sizeof(dest)/16)
C_ASSERT( (sizeof(dest) & 0xf) == 0 );
__m128 zeroreg = _mm_setzero_ps();
float (*destxmm)[4] = (float(*)[4])&dest;
#define StoreDestIdx(idx) case idx: _mm_store_ps(&destxmm[idx-1][0], zeroreg)
switch( MZFqwc & 0x07 )
{
StoreDestIdx(0x07);
StoreDestIdx(0x06);
StoreDestIdx(0x05);
StoreDestIdx(0x04);
StoreDestIdx(0x03);
StoreDestIdx(0x02);
StoreDestIdx(0x01);
}
destxmm += (MZFqwc & 0x07);
for( uint i=0; i<MZFqwc / 8; ++i, destxmm+=8 )
{
_mm_store_ps(&destxmm[0][0], zeroreg);
_mm_store_ps(&destxmm[1][0], zeroreg);
_mm_store_ps(&destxmm[2][0], zeroreg);
_mm_store_ps(&destxmm[3][0], zeroreg);
_mm_store_ps(&destxmm[4][0], zeroreg);
_mm_store_ps(&destxmm[5][0], zeroreg);
_mm_store_ps(&destxmm[6][0], zeroreg);
_mm_store_ps(&destxmm[7][0], zeroreg);
}
#undef MZFqwc
};
// the IPU is fixed to 16 byte strides (128-bit / QWC resolution):
static const uint decoder_stride = 16;

View File

@ -359,11 +359,19 @@ void JALR()
} } } // end namespace R5900::Interpreter::OpcodeImpl
////////////////////////////////////////////////////////
// --------------------------------------------------------------------------------------
// R5900cpu/intCpu interface (implementations)
// --------------------------------------------------------------------------------------
static void intReserve()
{
// fixme : detect cpu for use the optimize asm code
}
static void intAlloc()
{
// fixme : detect cpu for use the optimize asm code
// Nothing to do!
}
static void intReset()
@ -419,19 +427,28 @@ static void intShutdown() {
static void intThrowException( const BaseR5900Exception& ex )
{
// No tricks needed; C++ stack unwnding shoud suffice for MSW and GCC alike.
// No tricks needed; C++ stack unwnding should suffice for MSW and GCC alike.
ex.Rethrow();
}
static void intThrowException( const BaseException& ex )
{
// No tricks needed; C++ stack unwnding shoud suffice for MSW and GCC alike.
// No tricks needed; C++ stack unwnding should suffice for MSW and GCC alike.
ex.Rethrow();
}
static void intSetCacheReserve( uint reserveInMegs )
{
}
static uint intGetCacheReserve()
{
return 0;
}
R5900cpu intCpu =
{
intAlloc,
intReserve,
intShutdown,
intReset,
@ -442,4 +459,7 @@ R5900cpu intCpu =
intThrowException,
intThrowException,
intClear,
intGetCacheReserve,
intSetCacheReserve,
};

View File

@ -24,26 +24,43 @@ IopVM_MemoryAllocMess* iopMem = NULL;
__pagealigned u8 iopHw[Ps2MemSize::IopHardware];
void psxMemAlloc()
// --------------------------------------------------------------------------------------
// iopMemoryReserve
// --------------------------------------------------------------------------------------
iopMemoryReserve::iopMemoryReserve()
: _parent( L"IOP Main Memory (2mb)", sizeof(*iopMem) )
{
if( iopMem == NULL )
iopMem = (IopVM_MemoryAllocMess*)vtlb_malloc( sizeof(*iopMem), 4096 );
}
psxMemWLUT = (uptr*)_aligned_malloc(0x2000 * sizeof(uptr) * 2, 16);
psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
void iopMemoryReserve::Reserve()
{
_parent::Reserve(HostMemoryMap::IOPmem);
//_parent::Reserve(EmuConfig.HostMap.IOP);
}
void iopMemoryReserve::Commit()
{
_parent::Commit();
iopMem = (IopVM_MemoryAllocMess*)m_reserve.GetPtr();
}
// Note! Resetting the IOP's memory state is dependent on having *all* psx memory allocated,
// which is performed by MemInit and PsxMemInit()
void psxMemReset()
void iopMemoryReserve::Reset()
{
pxAssume( psxMemWLUT != NULL );
pxAssume( iopMem != NULL );
_parent::Reset();
DbgCon.WriteLn( "IOP Resetting physical ram..." );
pxAssume( iopMem );
if (!psxMemWLUT)
{
psxMemWLUT = (uptr*)_aligned_malloc(0x2000 * sizeof(uptr) * 2, 16);
psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
}
DbgCon.WriteLn("IOP resetting main memory...");
memzero_ptr<0x2000 * sizeof(uptr) * 2>( psxMemWLUT ); // clears both allocations, RLUT and WLUT
memzero( *iopMem );
// Trick! We're accessing RLUT here through WLUT, since it's the non-const pointer.
// So the ones with a 0x2000 prefixed are RLUT tables.
@ -87,15 +104,22 @@ void psxMemReset()
//for (i=0; i<0x0008; i++) psxMemWLUT[i + 0xbfc0] = (uptr)&psR[i << 16];
}
void psxMemShutdown()
void iopMemoryReserve::Decommit()
{
vtlb_free( iopMem, sizeof(*iopMem) );
iopMem = NULL;
_parent::Decommit();
safe_aligned_free(psxMemWLUT);
psxMemRLUT = NULL;
iopMem = NULL;
}
void iopMemoryReserve::Release()
{
_parent::Release();
iopMem = NULL;
}
u8 __fastcall iopMemRead8(u32 mem)
{
mem &= 0x1fffffff;

View File

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

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/gdkx.h>
void NTFS_CompressFile( const wxString& file, bool compressStatus ) {}
// Returns a WXK_* keycode, given some kinda GDK input mess!
int TranslateGDKtoWXK( u32 keysym )
{

View File

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

View File

@ -40,11 +40,12 @@ BIOS
#include "IopCommon.h"
#include "VUmicro.h"
#include "GS.h"
#include "System/PageFaultSource.h"
#include "ps2/HwInternal.h"
#include "ps2/BiosTools.h"
#include "Utilities/PageFaultSource.h"
#ifdef ENABLECACHE
#include "Cache.h"
#endif
@ -91,7 +92,6 @@ static vtlbHandler
null_handler,
tlb_fallback_0,
tlb_fallback_1,
tlb_fallback_2,
tlb_fallback_3,
tlb_fallback_4,
@ -137,9 +137,9 @@ void memMapVUmicro()
void memMapPhy()
{
// Main memory
vtlb_MapBlock(eeMem->Main, 0x00000000,Ps2MemSize::Base);//mirrored on first 256 mb ?
vtlb_MapBlock(eeMem->Main, 0x00000000,Ps2MemSize::MainRam);//mirrored on first 256 mb ?
// High memory, uninstalled on the configuration we emulate
vtlb_MapHandler(null_handler, Ps2MemSize::Base, 0x10000000 - Ps2MemSize::Base);
vtlb_MapHandler(null_handler, Ps2MemSize::MainRam, 0x10000000 - Ps2MemSize::MainRam);
// Various ROMs (all read-only)
vtlb_MapBlock(eeMem->ROM, 0x1fc00000,Ps2MemSize::Rom);
@ -153,14 +153,14 @@ void memMapPhy()
vtlb_MapBlock(iopMem->Main,0x1c000000,0x00800000);
// Generic Handlers; These fallback to mem* stuff...
vtlb_MapHandler(tlb_fallback_7,0x14000000,0x10000);
vtlb_MapHandler(tlb_fallback_4,0x18000000,0x10000);
vtlb_MapHandler(tlb_fallback_5,0x1a000000,0x10000);
vtlb_MapHandler(tlb_fallback_6,0x12000000,0x10000);
vtlb_MapHandler(tlb_fallback_8,0x1f000000,0x10000);
vtlb_MapHandler(tlb_fallback_3,0x1f400000,0x10000);
vtlb_MapHandler(tlb_fallback_2,0x1f800000,0x10000);
vtlb_MapHandler(tlb_fallback_8,0x1f900000,0x10000);
vtlb_MapHandler(tlb_fallback_7,0x14000000, _64kb);
vtlb_MapHandler(tlb_fallback_4,0x18000000, _64kb);
vtlb_MapHandler(tlb_fallback_5,0x1a000000, _64kb);
vtlb_MapHandler(tlb_fallback_6,0x12000000, _64kb);
vtlb_MapHandler(tlb_fallback_8,0x1f000000, _64kb);
vtlb_MapHandler(tlb_fallback_3,0x1f400000, _64kb);
vtlb_MapHandler(tlb_fallback_2,0x1f800000, _64kb);
vtlb_MapHandler(tlb_fallback_8,0x1f900000, _64kb);
// Hardware Register Handlers : specialized/optimized per-page handling of HW register accesses
// (note that hw_by_page handles are assigned in memReset prior to calling this function)
@ -186,9 +186,9 @@ void memMapKernelMem()
//lower 512 mb: direct map
//vtlb_VMap(0x00000000,0x00000000,0x20000000);
//0x8* mirror
vtlb_VMap(0x80000000,0x00000000,0x20000000);
vtlb_VMap(0x80000000, 0x00000000, _1mb*512);
//0xa* mirror
vtlb_VMap(0xA0000000,0x00000000,0x20000000);
vtlb_VMap(0xA0000000, 0x00000000, _1mb*512);
}
//what do do with these ?
@ -578,35 +578,15 @@ void memClearPageAddr(u32 vaddr)
class mmap_PageFaultHandler : public EventListener_PageFault
{
protected:
public:
void OnPageFaultEvent( const PageFaultInfo& info, bool& handled );
};
static mmap_PageFaultHandler mmap_faultHandler;
static mmap_PageFaultHandler* mmap_faultHandler = NULL;
EEVM_MemoryAllocMess* eeMem = NULL;
__pagealigned u8 eeHw[Ps2MemSize::Hardware];
void memAlloc()
{
if( eeMem == NULL )
eeMem = (EEVM_MemoryAllocMess*)vtlb_malloc( sizeof(*eeMem), 4096 );
if( eeMem == NULL)
throw Exception::OutOfMemory( L"memAlloc > failed to allocate PS2's base ram/rom/scratchpad." );
Source_PageFault.Add( mmap_faultHandler );
}
void memShutdown()
{
Source_PageFault.Remove( mmap_faultHandler );
vtlb_free( eeMem, sizeof(*eeMem) );
eeMem = NULL;
vtlb_Term();
}
void memBindConditionalHandlers()
{
@ -636,19 +616,44 @@ void memBindConditionalHandlers()
}
}
// Resets memory mappings, unmaps TLBs, reloads bios roms, etc.
void memReset()
// --------------------------------------------------------------------------------------
// eeMemoryReserve (implementations)
// --------------------------------------------------------------------------------------
eeMemoryReserve::eeMemoryReserve()
: _parent( L"EE Main Memory", sizeof(*eeMem) )
{
// VTLB Protection Preparations.
//HostSys::MemProtect( m_psAllMem, m_allMemSize, Protect_ReadWrite );
}
void eeMemoryReserve::Reserve()
{
_parent::Reserve(HostMemoryMap::EEmem);
//_parent::Reserve(EmuConfig.HostMap.IOP);
}
void eeMemoryReserve::Commit()
{
_parent::Commit();
eeMem = (EEVM_MemoryAllocMess*)m_reserve.GetPtr();
}
// Resets memory mappings, unmaps TLBs, reloads bios roms, etc.
void eeMemoryReserve::Reset()
{
if (!mmap_faultHandler)
{
pxAssume(Source_PageFault);
mmap_faultHandler = new mmap_PageFaultHandler();
}
_parent::Reset();
// Note!! Ideally the vtlb should only be initialized once, and then subsequent
// resets of the system hardware would only clear vtlb mappings, but since the
// rest of the emu is not really set up to support a "soft" reset of that sort
// we opt for the hard/safe version.
pxAssume( eeMem != NULL );
memzero( *eeMem );
pxAssume( eeMem );
#ifdef ENABLECACHE
memset(pCache,0,sizeof(_cacheS)*64);
@ -761,9 +766,24 @@ void memReset()
LoadBIOS();
}
//////////////////////////////////////////////////////////////////////////////////////////
// Memory Protection and Block Checking, vtlb Style!
//
void eeMemoryReserve::Decommit()
{
_parent::Decommit();
eeMem = NULL;
}
void eeMemoryReserve::Release()
{
safe_delete(mmap_faultHandler);
_parent::Release();
eeMem = NULL;
vtlb_Term();
}
// ===========================================================================================
// Memory Protection and Block Checking, vtlb Style!
// ===========================================================================================
// For the first time code is recompiled (executed), the PS2 ram page for that code is
// protected using Virtual Memory (mprotect). If the game modifies its own code then this
// protection causes an *exception* to be raised (signal in Linux), which is handled by
@ -796,15 +816,17 @@ enum vtlb_ProtectionMode
struct vtlb_PageProtectionInfo
{
// Ram De-mapping -- used to convert fully translated/mapped offsets into psM back
// into their originating ps2 physical ram address. Values are assigned when pages
// are marked for protection.
// Ram De-mapping -- used to convert fully translated/mapped offsets (which reside with
// in the eeMem->Main block) back into their originating ps2 physical ram address.
// Values are assigned when pages are marked for protection. since pages are automatically
// cleared and reset when TLB-remapped, stale values in this table (due to on-the-fly TLB
// changes) will be re-assigned the next time the page is accessed.
u32 ReverseRamMap;
vtlb_ProtectionMode Mode;
};
static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::Base >> 12];
static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::MainRam >> 12];
// returns:
@ -815,28 +837,33 @@ static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::Base >>
//
int mmap_GetRamPageInfo( u32 paddr )
{
pxAssume( eeMem );
paddr &= ~0xfff;
uptr ptr = (uptr)PSM( paddr );
uptr rampage = ptr - (uptr)eeMem->Main;
if (rampage >= Ps2MemSize::Base)
if (rampage >= Ps2MemSize::MainRam)
return -1; //not in ram, no tracking done ...
rampage >>= 12;
return ( m_PageProtectInfo[rampage].Mode == ProtMode_Manual ) ? 1 : 0;
}
// paddr - physically mapped address
// paddr - physically mapped PS2 address
void mmap_MarkCountedRamPage( u32 paddr )
{
pxAssume( eeMem );
paddr &= ~0xfff;
uptr ptr = (uptr)PSM( paddr );
int rampage = (ptr - (uptr)eeMem->Main) >> 12;
// Important: reassign paddr here, since TLB changes could alter the paddr->psM mapping
// (and clear blocks accordingly), but don't necessarily clear the protection status.
// Important: Update the ReverseRamMap here because TLB changes could alter the paddr
// mapping into eeMem->Main.
m_PageProtectInfo[rampage].ReverseRamMap = paddr;
if( m_PageProtectInfo[rampage].Mode == ProtMode_Write )
@ -848,7 +875,7 @@ void mmap_MarkCountedRamPage( u32 paddr )
);
m_PageProtectInfo[rampage].Mode = ProtMode_Write;
HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, Protect_ReadOnly );
HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, PageAccess_ReadOnly() );
}
// offset - offset of address relative to psM.
@ -856,6 +883,8 @@ void mmap_MarkCountedRamPage( u32 paddr )
// from code residing in this page will use manual protection.
static __fi void mmap_ClearCpuBlock( uint offset )
{
pxAssume( eeMem );
int rampage = offset >> 12;
// Assertion: This function should never be run on a block that's already under
@ -863,16 +892,18 @@ static __fi void mmap_ClearCpuBlock( uint offset )
pxAssertMsg( m_PageProtectInfo[rampage].Mode != ProtMode_Manual,
"Attempted to clear a block that is already under manual protection." );
HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, Protect_ReadWrite );
HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, PageAccess_ReadWrite() );
m_PageProtectInfo[rampage].Mode = ProtMode_Manual;
Cpu->Clear( m_PageProtectInfo[rampage].ReverseRamMap, 0x400 );
}
void mmap_PageFaultHandler::OnPageFaultEvent( const PageFaultInfo& info, bool& handled )
{
pxAssume( eeMem );
// get bad virtual address
uptr offset = info.addr - (uptr)eeMem->Main;
if( offset >= Ps2MemSize::Base ) return;
if( offset >= Ps2MemSize::MainRam ) return;
mmap_ClearCpuBlock( offset );
handled = true;
@ -886,5 +917,5 @@ void mmap_ResetBlockTracking()
{
//DbgCon.WriteLn( "vtlb/mmap: Block Tracking reset..." );
memzero( m_PageProtectInfo );
HostSys::MemProtect( eeMem->Main, Ps2MemSize::Base, Protect_ReadWrite );
if (eeMem) HostSys::MemProtect( eeMem->Main, Ps2MemSize::MainRam, PageAccess_ReadWrite() );
}

View File

@ -24,6 +24,10 @@
#include <xmmintrin.h>
// [TODO] This *could* be replaced with an assignment operator on u128 that implicitly
// uses _mm_store and _mm_load internally. However, there are alignment concerns --
// u128 is not alignment strict. (we would need a u128 and u128a for types known to
// be strictly 128-bit aligned).
static __fi void CopyQWC( void* dest, const void* src )
{
_mm_store_ps( (float*)dest, _mm_load_ps((const float*)src) );
@ -103,9 +107,7 @@ static __fi void ZeroQWC( u128& dest )
#define psSu64(mem) (*(u64 *)&eeMem->Scratch[(mem) & 0x3fff])
#define psSu128(mem) (*(u128*)&eeMem->Scratch[(mem) & 0x3fff])
extern void memAlloc();
extern void memReset(); // clears PS2 ram and loads the bios. Throws Exception::FileNotFound on error.
extern void memShutdown();
extern void memSetKernelMode();
//extern void memSetSupervisorMode();
extern void memSetUserMode();

View File

@ -17,18 +17,18 @@
namespace Ps2MemSize
{
static const uint Base = 0x02000000; // 32 MB main memory!
static const uint Rom = 0x00400000; // 4 MB main rom
static const uint Rom1 = 0x00040000; // DVD player
static const uint Rom2 = 0x00080000; // Chinese rom extension (?)
static const uint ERom = 0x001C0000; // DVD player extensions (?)
static const uint Hardware = 0x00010000;
static const uint Scratch = 0x00004000;
static const uint MainRam = _32mb; // 32 MB main memory!
static const uint Rom = _1mb * 4; // 4 MB main rom
static const uint Rom1 = 0x00040000; // DVD player
static const uint Rom2 = 0x00080000; // Chinese rom extension (?)
static const uint ERom = 0x001C0000; // DVD player extensions (?)
static const uint Hardware = _64kb;
static const uint Scratch = _16kb;
static const uint IopRam = 0x00200000; // 2MB main ram on the IOP.
static const uint IopHardware = 0x00010000;
static const uint IopRam = _1mb * 2; // 2MB main ram on the IOP.
static const uint IopHardware = _64kb;
static const uint GSregs = 0x00002000; // 8k for the GS registers and stuff.
static const uint GSregs = 0x00002000; // 8k for the GS registers and stuff.
}
typedef u8 mem8_t;
@ -53,6 +53,9 @@ typedef u128 mem128_t;
// memory, such as hardware registers or scratchpad, the access will generate a page fault, the
// compiled block will be cleared and re-compiled using "full" VTLB translation logic.
//
// Note that support for this feature may not be doable under x86/32 platforms, due to the
// 2gb/3gb limit of Windows XP (the 3gb feature will make it slightly more feasible at least).
//
#define VTLB_UsePageFaulting 0
#if VTLB_UsePageFaulting
@ -61,9 +64,9 @@ typedef u128 mem128_t;
// full breadth of PS2 RAM and ROM mappings are directly supported.
struct EEVM_MemoryAllocMess
{
u8 (&Main)[Ps2MemSize::Base]; // Main memory (hard-wired to 32MB)
u8 (&Main)[Ps2MemSize::MainRam]; // Main memory (hard-wired to 32MB)
u8 _padding1[0x1e000000-Ps2MemSize::Base]
u8 _padding1[0x1e000000-Ps2MemSize::MainRam]
u8 (&ROM1)[Ps2MemSize::Rom1]; // DVD player
u8 _padding2[0x1e040000-(0x1e000000+Ps2MemSize::Rom1)]
@ -80,8 +83,8 @@ struct EEVM_MemoryAllocMess
struct EEVM_MemoryAllocMess
{
u8 Main[Ps2MemSize::MainRam]; // Main memory (hard-wired to 32MB)
u8 Scratch[Ps2MemSize::Scratch]; // Scratchpad!
u8 Main[Ps2MemSize::Base]; // Main memory (hard-wired to 32MB)
u8 ROM[Ps2MemSize::Rom]; // Boot rom (4MB)
u8 ROM1[Ps2MemSize::Rom1]; // DVD player
u8 ROM2[Ps2MemSize::Rom2]; // Chinese extensions
@ -101,7 +104,7 @@ struct EEVM_MemoryAllocMess
struct IopVM_MemoryAllocMess
{
u8 Main[Ps2MemSize::IopRam]; // Main memory (hard-wired to 2MB)
u8 P[0x00010000]; // I really have no idea what this is... --air
u8 P[_64kb]; // I really have no idea what this is... --air
u8 Sif[0x100]; // a few special SIF/SBUS registers (likely not needed)
};

View File

@ -674,18 +674,34 @@ SysCorePlugins *g_plugins = NULL;
// Plugin-related Exception Implementations
// ---------------------------------------------------------------------------------
wxString Exception::SaveStateLoadError::FormatDiagnosticMessage() const
{
FastFormatUnicode retval;
retval.Write("Savestate is corrupt or incomplete!");
_formatDiagMsg(retval);
return retval;
}
wxString Exception::SaveStateLoadError::FormatDisplayMessage() const
{
FastFormatUnicode retval;
retval.Write(_("The savestate cannot be loaded, as it appears to be corrupt or incomplete."));
_formatUserMsg(retval);
return retval;
}
Exception::PluginOpenError::PluginOpenError( PluginsEnum_t pid )
{
PluginId = pid;
m_message_diag = L"%s plugin failed to open!";
m_message_user = L"%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers.";
m_message_user = _("%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers.");
}
Exception::PluginInitError::PluginInitError( PluginsEnum_t pid )
{
PluginId = pid;
m_message_diag = L"%s plugin initialization failed!";
m_message_user = L"%s plugin failed to initialize. Your system may have insufficient memory or resources needed.";
m_message_user = _("%s plugin failed to initialize. Your system may have insufficient memory or resources needed.");
}
Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid )
@ -695,29 +711,29 @@ Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid )
wxString Exception::PluginLoadError::FormatDiagnosticMessage() const
{
return wxsFormat( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() ) +
return pxsFmt( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() ) +
L"\n\n" + StreamName;
}
wxString Exception::PluginLoadError::FormatDisplayMessage() const
{
return wxsFormat( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() ) +
return pxsFmt( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() ) +
L"\n\n" + StreamName;
}
wxString Exception::PluginError::FormatDiagnosticMessage() const
{
return wxsFormat( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() );
return pxsFmt( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() );
}
wxString Exception::PluginError::FormatDisplayMessage() const
{
return wxsFormat( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() );
return pxsFmt( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() );
}
wxString Exception::FreezePluginFailure::FormatDiagnosticMessage() const
{
return wxsFormat(
return pxsFmt(
L"%s plugin returned an error while saving the state.\n\n",
tbl_PluginInfo[PluginId].shortname
);
@ -731,7 +747,7 @@ wxString Exception::FreezePluginFailure::FormatDisplayMessage() const
wxString Exception::ThawPluginFailure::FormatDiagnosticMessage() const
{
return wxsFormat(
return pxsFmt(
L"%s plugin returned an error while loading the state.\n\n",
tbl_PluginInfo[PluginId].shortname
);
@ -1262,7 +1278,7 @@ void SysCorePlugins::Init( PluginsEnum_t pid )
if( !m_info[pid] || m_info[pid]->IsInitialized ) return;
Console.Indent().WriteLn( "Init %s", tbl_PluginInfo[pid].shortname );
if( NULL != m_info[pid]->CommonBindings.Init() )
if( 0 != m_info[pid]->CommonBindings.Init() )
throw Exception::PluginInitError( pid );
m_info[pid]->IsInitialized = true;

View File

@ -57,12 +57,15 @@ namespace Exception
// Exception thrown when a corrupted or truncated savestate is encountered.
class SaveStateLoadError : public BadStream
{
DEFINE_STREAM_EXCEPTION( SaveStateLoadError, BadStream, wxLt("The savestate appears to be corrupt or incomplete.") )
DEFINE_STREAM_EXCEPTION( SaveStateLoadError, BadStream )
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
};
class PluginError : public RuntimeError
{
DEFINE_RUNTIME_EXCEPTION( PluginError, RuntimeError, L"Generic plugin error")
DEFINE_RUNTIME_EXCEPTION( PluginError, RuntimeError, L"Generic plugin error!" )
public:
PluginsEnum_t PluginId;

View File

@ -102,14 +102,9 @@ typedef int BOOL;
typedef void FnType_Void();
typedef FnType_Void* Fnptr_Void;
static const s64 _1mb = 0x100000;
static const s64 _8mb = _1mb * 8;
static const s64 _16mb = _1mb * 16;
static const s64 _256mb = _1mb * 256;
static const s64 _1gb = _256mb * 4;
//////////////////////////////////////////////////////////////////////////////////////////
// Compiler/OS specific macros and defines -- Begin Section
// --------------------------------------------------------------------------------------
// Compiler/OS specific macros and defines
// --------------------------------------------------------------------------------------
// Linux isn't set up for svn version numbers yet.
#ifdef __LINUX__

View File

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

View File

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

View File

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

View File

@ -273,25 +273,25 @@ extern void __fastcall eeloadReplaceOSDSYS();
struct R5900cpu
{
// Memory allocation function, for allocating virtual memory spaces needed by
// the emulator. (ints/recs are free to allocate additional memory while running
// code, however any virtual mapped memory should always be allocated as soon
// as possible, to claim the memory before some plugin does..)
//
// the virtual cpu provider. Allocating additional heap memory from this method is
// NOT recommended. Heap allocations should be performed by Reset only. This
// maximizes the likeliness of reservations claiming addresses they prefer.
//
// Thread Affinity:
// Can be called from any thread. Execute status must be suspended or stopped
// to prevent multi-thread race conditions.
// Called from the main/UI thread only. Cpu execution status is guaranteed to
// be inactive. No locking is necessary.
//
// Exception Throws:
// HardwareDeficiency - The host machine's hardware does not support this CPU provider.
// OutOfMemory - Not enough memory, or the memory areas required were already
// reserved.
//
void (*Allocate)();
void (*Reserve)();
// Deallocates ram allocated by Allocate and/or by runtime code execution.
// Deallocates ram allocated by Allocate, Reserve, and/or by runtime code execution.
//
// Thread Affinity:
// Can be called from any thread. Execute status must be suspended or stopped
// to prevent multi-thread race conditions.
// Called from the main/UI thread only. Cpu execution status is guaranteed to
// be inactive. No locking is necessary.
//
// Exception Throws: None. This function is a destructor, and should not throw.
//
@ -302,8 +302,10 @@ struct R5900cpu
// rely on the CPU/VM states almost entirely.
//
// Thread Affinity:
// Can be called from any thread. Execute status must be suspended or stopped
// to prevent multi-thread race conditions.
// Can be called from any thread. CPU execution status is indeterminate and may
// already be in progress. Implementations should be sure to queue and execute
// resets at the earliest safe convenience (typically right before recompiling a
// new block of code, or after a vsync event).
//
// Exception Throws: Emulator-defined. Common exception types to expect are
// OutOfMemory, Stream Exceptions
@ -365,7 +367,7 @@ struct R5900cpu
// better off replaced with some generic API callbacks from VTLB block protection.
// Also: the calls from COP0's TLB remap code should be replaced with full recompiler
// resets, since TLB remaps affect more than just the code they contain (code that
// may reference the remaped blocks via memory loads/stores, for example).
// may reference the remapped blocks via memory loads/stores, for example).
//
// Thread Affinity Rule:
// Can be called from any thread (namely for being called from debugging threads)
@ -374,6 +376,9 @@ struct R5900cpu
// doesn't matter if we're stripping it out soon. ;)
//
void (*Clear)(u32 Addr, u32 Size);
uint (*GetCacheReserve)();
void (*SetCacheReserve)( uint reserveInMegs );
};
extern R5900cpu *Cpu;

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

View File

@ -48,7 +48,7 @@ static void PostLoadPrep()
wxString SaveStateBase::GetFilename( int slot )
{
return (g_Conf->Folders.Savestates +
wxsFormat( L"%8.8X.%3.3d", ElfCRC, slot )).GetFullPath();
pxsFmt( L"%08X.%03d", ElfCRC, slot )).GetFullPath();
}
SaveStateBase::SaveStateBase( SafeArray<u8>& memblock )
@ -142,7 +142,7 @@ void SaveStateBase::FreezeBios()
}
static const int MainMemorySizeInBytes =
Ps2MemSize::Base + Ps2MemSize::Scratch + Ps2MemSize::Hardware +
Ps2MemSize::MainRam + Ps2MemSize::Scratch + Ps2MemSize::Hardware +
Ps2MemSize::IopRam + Ps2MemSize::IopHardware + 0x0100;
void SaveStateBase::FreezeMainMemory()
@ -152,7 +152,7 @@ void SaveStateBase::FreezeMainMemory()
// First Block - Memory Dumps
// ---------------------------
FreezeMem(eeMem->Main, Ps2MemSize::Base); // 32 MB main memory
FreezeMem(eeMem->Main, Ps2MemSize::MainRam); // 32 MB main memory
FreezeMem(eeMem->Scratch, Ps2MemSize::Scratch); // scratch pad
FreezeMem(eeHw, Ps2MemSize::Hardware); // hardware memory

View File

@ -16,44 +16,144 @@
#include "PrecompiledHeader.h"
#include "Common.h"
#include "IopCommon.h"
#include "VUmicro.h"
#include "newVif.h"
#include "System/PageFaultSource.h"
#include "Utilities/EventSource.inl"
#include "SamplProf.h"
// Includes needed for cleanup, since we don't have a good system (yet) for
// cleaning up these things.
#include "sVU_zerorec.h"
#include "GameDatabase.h"
#include "Elfheader.h"
extern void closeNewVif(int idx);
extern void resetNewVif(int idx);
#include "System/RecTypes.h"
template class EventSource< IEventListener_PageFault >;
#include "Utilities/MemsetFast.inl"
SrcType_PageFault Source_PageFault;
EventListener_PageFault::EventListener_PageFault()
// --------------------------------------------------------------------------------------
// RecompiledCodeReserve (implementations)
// --------------------------------------------------------------------------------------
// Constructor!
// Parameters:
// name - a nice long name that accurately describes the contents of this reserve.
RecompiledCodeReserve::RecompiledCodeReserve( const wxString& name, uint defCommit )
: BaseVmReserveListener( name )
{
Source_PageFault.Add( *this );
m_blocksize = (1024 * 128) / __pagesize;
m_prot_mode = PageAccess_Any();
m_def_commit = defCommit / __pagesize;
m_profiler_registered = false;
}
EventListener_PageFault::~EventListener_PageFault() throw()
RecompiledCodeReserve::~RecompiledCodeReserve() throw()
{
Source_PageFault.Remove( *this );
_termProfiler();
}
void SrcType_PageFault::Dispatch( const PageFaultInfo& params )
void RecompiledCodeReserve::_registerProfiler()
{
m_handled = false;
_parent::Dispatch( params );
if (m_profiler_name.IsEmpty() || !IsOk()) return;
ProfilerRegisterSource( m_profiler_name, m_baseptr, GetReserveSizeInBytes() );
m_profiler_registered = true;
}
void SrcType_PageFault::_DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt )
void RecompiledCodeReserve::_termProfiler()
{
do {
(*iter)->DispatchEvent( evt, m_handled );
} while( (++iter != iend) && !m_handled );
if (m_profiler_registered)
ProfilerTerminateSource( m_profiler_name );
}
uint RecompiledCodeReserve::_calcDefaultCommitInBlocks() const
{
return (m_def_commit + m_blocksize - 1) / m_blocksize;
}
void* RecompiledCodeReserve::Reserve( size_t size, uptr base, uptr upper_bounds )
{
if (!_parent::Reserve(size, base, upper_bounds)) return NULL;
_registerProfiler();
return m_baseptr;
}
// Sets the abbreviated name used by the profiler. Name should be under 10 characters long.
// After a name has been set, a profiler source will be automatically registered and cleared
// in accordance with changes in the reserve area.
RecompiledCodeReserve& RecompiledCodeReserve::SetProfilerName( const wxString& shortname )
{
m_profiler_name = shortname;
_registerProfiler();
return *this;
}
void RecompiledCodeReserve::DoCommitAndProtect( uptr page )
{
CommitBlocks(page, (m_pages_commited || !m_def_commit) ? 1 : _calcDefaultCommitInBlocks() );
}
void RecompiledCodeReserve::OnCommittedBlock( void* block )
{
if (IsDevBuild)
{
// Clear the recompiled code block to 0xcc (INT3) -- this helps disasm tools show
// the assembly dump more cleanly. We don't clear the block on Release builds since
// it can add a noticeable amount of overhead to large block recompilations.
memset_sse_a<0xcc>( block, m_blocksize * __pagesize );
}
}
// This error message is shared by R5900, R3000, and microVU recompilers. It is not used by the
// SuperVU recompiler, since it has its own customized message.
void RecompiledCodeReserve::ThrowIfNotOk() const
{
if (IsOk()) return;
throw Exception::OutOfMemory(m_name)
.SetDiagMsg(pxsFmt( L"Recompiled code cache could not be mapped." ))
.SetUserMsg( pxE( ".Error:Recompiler:VirtualMemoryAlloc",
L"This recompiler was unable to reserve contiguous memory required for internal caches. "
L"This error can be caused by low virtual memory resources, such as a small or disabled swapfile, "
L"or by another program that is hogging a lot of memory. You can also try reducing the default "
L"cache sizes for all PCSX2 recompilers, found under Host Settings."
));
}
void SysOutOfMemory_EmergencyResponse(uptr blocksize)
{
// An out of memory error occurred. All we can try to do in response is reset the various
// recompiler caches (which can sometimes total over 120megs, so it can be quite helpful).
// If the user is using interpreters, or if the memory allocation failure was on a very small
// allocation, then this code could fail; but that's fine. We're already trying harder than
// 99.995% of all programs ever written. -- air
if (Cpu)
{
Cpu->SetCacheReserve( (Cpu->GetCacheReserve() * 3) / 2 );
Cpu->Reset();
}
if (CpuVU0)
{
CpuVU0->SetCacheReserve( (CpuVU0->GetCacheReserve() * 3) / 2 );
CpuVU0->Reset();
}
if (CpuVU1)
{
CpuVU1->SetCacheReserve( (CpuVU1->GetCacheReserve() * 3) / 2 );
CpuVU1->Reset();
}
if (psxCpu)
{
psxCpu->SetCacheReserve( (psxCpu->GetCacheReserve() * 3) / 2 );
psxCpu->Reset();
}
}
@ -190,7 +290,7 @@ CpuInitializer< CpuType >::CpuInitializer()
{
try {
MyCpu = new CpuType();
MyCpu->Allocate();
MyCpu->Reserve();
}
catch( Exception::RuntimeError& ex )
{
@ -209,7 +309,7 @@ CpuInitializer< CpuType >::CpuInitializer()
template< typename CpuType >
CpuInitializer< CpuType >::~CpuInitializer() throw()
{
if( MyCpu )
if (MyCpu)
MyCpu->Shutdown();
}
@ -246,96 +346,128 @@ static wxString GetMemoryErrorVM()
}
// --------------------------------------------------------------------------------------
// SysAllocVM (implementations)
// SysReserveVM (implementations)
// --------------------------------------------------------------------------------------
SysAllocVM::SysAllocVM()
SysMainMemory::SysMainMemory()
{
InstallSignalHandler();
Console.WriteLn( "Allocating memory for the PS2 virtual machine..." );
try
{
vtlb_Core_Alloc();
memAlloc();
psxMemAlloc();
vuMicroMemAlloc();
}
// ----------------------------------------------------------------------------
catch( Exception::OutOfMemory& ex )
{
ex.UserMsg() += L"\n\n" + GetMemoryErrorVM();
CleanupMess();
throw;
}
catch( std::bad_alloc& ex )
{
CleanupMess();
// re-throw std::bad_alloc as something more friendly. This is needed since
// much of the code uses new/delete internally, which throw std::bad_alloc on fail.
throw Exception::OutOfMemory()
.SetDiagMsg(
L"std::bad_alloc caught while trying to allocate memory for the PS2 Virtual Machine.\n"
L"Error Details: " + fromUTF8( ex.what() )
)
.SetUserMsg(GetMemoryErrorVM()); // translated
}
}
void SysAllocVM::CleanupMess() throw()
SysMainMemory::~SysMainMemory() throw()
{
try
{
vuMicroMemShutdown();
psxMemShutdown();
memShutdown();
vtlb_Core_Shutdown();
}
DESTRUCTOR_CATCHALL
ReleaseAll();
}
SysAllocVM::~SysAllocVM() throw()
void SysMainMemory::ReserveAll()
{
CleanupMess();
pxInstallSignalHandler();
DevCon.WriteLn( Color_StrongBlue, "Mapping host memory for virtual systems..." );
ConsoleIndentScope indent(1);
m_ee.Reserve();
m_iop.Reserve();
m_vu.Reserve();
reserveNewVif(0);
reserveNewVif(1);
}
void SysMainMemory::CommitAll()
{
vtlb_Core_Alloc();
if (m_ee.IsCommitted() && m_iop.IsCommitted() && m_vu.IsCommitted()) return;
DevCon.WriteLn( Color_StrongBlue, "Allocating host memory for virtual systems..." );
ConsoleIndentScope indent(1);
m_ee.Commit();
m_iop.Commit();
m_vu.Commit();
}
void SysMainMemory::ResetAll()
{
CommitAll();
DevCon.WriteLn( Color_StrongBlue, "Resetting host memory for virtual systems..." );
ConsoleIndentScope indent(1);
m_ee.Reset();
m_iop.Reset();
m_vu.Reset();
// Note: newVif is reset as part of other VIF structures.
}
void SysMainMemory::DecommitAll()
{
if (!m_ee.IsCommitted() && !m_iop.IsCommitted() && !m_vu.IsCommitted()) return;
Console.WriteLn( Color_Blue, "Decommitting host memory for virtual systems..." );
ConsoleIndentScope indent(1);
m_ee.Decommit();
m_iop.Decommit();
m_vu.Decommit();
closeNewVif(0);
closeNewVif(1);
vtlb_Core_Free();
}
void SysMainMemory::ReleaseAll()
{
DecommitAll();
Console.WriteLn( Color_Blue, "Releasing host memory maps for virtual systems..." );
ConsoleIndentScope indent(1);
vtlb_Core_Free(); // Just to be sure... (calling order could result in it getting missed during Decommit).
releaseNewVif(0);
releaseNewVif(1);
m_ee.Decommit();
m_iop.Decommit();
m_vu.Decommit();
safe_delete(Source_PageFault);
}
// --------------------------------------------------------------------------------------
// SysCpuProviderPack (implementations)
// --------------------------------------------------------------------------------------
SysCpuProviderPack::SysCpuProviderPack()
{
Console.WriteLn( "Allocating memory for recompilers..." );
Console.WriteLn( Color_StrongBlue, "Reserving memory for recompilers..." );
ConsoleIndentScope indent(1);
CpuProviders = new CpuInitializerSet();
try {
recCpu.Allocate();
recCpu.Reserve();
}
catch( Exception::RuntimeError& ex )
{
m_RecExceptionEE = ex.Clone();
Console.Error( L"EE Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
Console.Error( L"EE Recompiler Reservation Failed:\n" + ex.FormatDiagnosticMessage() );
recCpu.Shutdown();
}
try {
psxRec.Allocate();
psxRec.Reserve();
}
catch( Exception::RuntimeError& ex )
{
m_RecExceptionIOP = ex.Clone();
Console.Error( L"IOP Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
Console.Error( L"IOP Recompiler Reservation Failed:\n" + ex.FormatDiagnosticMessage() );
psxRec.Shutdown();
}
// hmm! : VU0 and VU1 pre-allocations should do sVU and mVU separately? Sounds complicated. :(
// If both VUrecs failed, then make sure the SuperVU is totally closed out, because it
// actually initializes everything once and then shares it between both VU recs.
if( !IsRecAvailable_SuperVU0() && !IsRecAvailable_SuperVU1() )
SuperVUDestroy( -1 );
}
bool SysCpuProviderPack::IsRecAvailable_MicroVU0() const { return CpuProviders->microVU0.IsAvailable(); }
@ -353,12 +485,6 @@ void SysCpuProviderPack::CleanupMess() throw()
{
try
{
closeNewVif(0);
closeNewVif(1);
// Special SuperVU "complete" terminator (stupid hacky recompiler)
SuperVUDestroy( -1 );
psxRec.Shutdown();
recCpu.Shutdown();
}
@ -418,15 +544,13 @@ void SysClearExecutionCache()
{
GetCpuProviders().ApplyConfig();
// SuperVUreset will do nothing is none of the recs are initialized.
// But it's needed if one or the other is initialized.
SuperVUReset(-1);
Cpu->Reset();
psxCpu->Reset();
// mVU's VU0 needs to be properly initialised for macro mode even if it's not used for micro mode!
// mVU's VU0 needs to be properly initialized for macro mode even if it's not used for micro mode!
if (CHECK_EEREC)
((BaseVUmicroCPU*)GetCpuProviders().CpuProviders->microVU0)->Reset();
CpuVU0->Reset();
CpuVU1->Reset();
@ -444,19 +568,17 @@ u8* SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller)
if( (Mem == NULL) || (bounds != 0 && (((uptr)Mem + size) > bounds)) )
{
if( base != NULL )
if( base )
{
DbgCon.Warning( "First try failed allocating %s at address 0x%x", caller, base );
// memory allocation *must* have the top bit clear, so let's try again
// with NULL (let the OS pick something for us).
// Let's try again at an OS-picked memory area, and then hope it meets needed
// boundschecking criteria below.
SafeSysMunmap( Mem, size );
Mem = (u8*)HostSys::Mmap( NULL, size );
Mem = (u8*)HostSys::Mmap( 0, size );
}
if( bounds != 0 && (((uptr)Mem + size) > bounds) )
if( (bounds != 0) && (((uptr)Mem + size) > bounds) )
{
DevCon.Warning( "Second try failed allocating %s, block ptr 0x%x does not meet required criteria.", caller, Mem );
SafeSysMunmap( Mem, size );
@ -481,5 +603,5 @@ wxString SysGetDiscID()
// region and revision).
}
return wxsFormat( L"%8.8x", ElfCRC );
return pxsFmt( L"%08x", ElfCRC );
}

View File

@ -21,8 +21,81 @@
#include "Utilities/Threading.h" // to use threading stuff, include the Threading namespace in your file.
#include "CDVD/CDVDaccess.h"
#include "vtlb.h"
typedef SafeArray<u8> VmStateBuffer;
class BaseVUmicroCPU;
class RecompiledCodeReserve;
// This is a table of default virtual map addresses for ps2vm components. These locations
// are provided and used to assist in debugging and possibly hacking; as it makes it possible
// for a programmer to know exactly where to look (consistently!) for the base address of
// the various virtual machine components. These addresses can be keyed directly into the
// debugger's disasm window to get disassembly of recompiled code, and they can be used to help
// identify recompiled code addresses in the callstack.
// All of these areas should be reserved as soon as possible during program startup, and its
// important that none of the areas overlap. In all but superVU's case, failure due to overlap
// or other conflict will result in the operating system picking a preferred address for the mapping.
namespace HostMemoryMap
{
// superVU is OLD SCHOOL, and it requires its allocation to be in the lower 256mb
// of the virtual memory space. (8mb each)
static const uptr sVU0rec = _256mb - (_8mb*3);
static const uptr sVU1rec = _256mb - (_8mb*2);
// PS2 main memory, SPR, and ROMs
static const uptr EEmem = 0x20000000;
// IOP main memory and ROMs
static const uptr IOPmem = 0x24000000;
// VU0 and VU1 memory.
static const uptr VUmem = 0x28000000;
// EE recompiler code cache area (64mb)
static const uptr EErec = 0x30000000;
// IOP recompiler code cache area (16 or 32mb)
static const uptr IOPrec = 0x34000000;
// newVif0 recompiler code cache area (16mb)
static const uptr VIF0rec = 0x36000000;
// newVif1 recompiler code cache area (32mb)
static const uptr VIF1rec = 0x38000000;
// microVU1 recompiler code cache area (32 or 64mb)
static const uptr mVU0rec = 0x3C000000;
// microVU0 recompiler code cache area (64mb)
static const uptr mVU1rec = 0x40000000;
}
// --------------------------------------------------------------------------------------
// SysMainMemory
// --------------------------------------------------------------------------------------
// This class provides the main memory for the virtual machines.
class SysMainMemory
{
protected:
eeMemoryReserve m_ee;
iopMemoryReserve m_iop;
vuMemoryReserve m_vu;
public:
SysMainMemory();
virtual ~SysMainMemory() throw();
virtual void ReserveAll();
virtual void CommitAll();
virtual void ResetAll();
virtual void DecommitAll();
virtual void ReleaseAll();
};
// --------------------------------------------------------------------------------------
// SysAllocVM
@ -83,6 +156,7 @@ extern SysCpuProviderPack& GetCpuProviders();
extern void SysLogMachineCaps(); // Detects cpu type and fills cpuInfo structs.
extern void SysClearExecutionCache(); // clears recompiled execution caches!
extern void SysOutOfMemory_EmergencyResponse(uptr blocksize);
extern u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed");
extern void vSyncDebugStuff( uint frame );
@ -90,6 +164,8 @@ extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true );
extern wxString SysGetDiscID();
extern SysMainMemory& GetVmMemory();
// --------------------------------------------------------------------------------------
// PCSX2_SEH - Defines existence of "built in" Structured Exception Handling support.
// --------------------------------------------------------------------------------------

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 "Elfheader.h"
#include "Patch.h"
#include "PageFaultSource.h"
#include "SysThreads.h"
#include "Utilities/PageFaultSource.h"
#include "Utilities/TlsVariable.inl"
#ifdef __WXMSW__
@ -111,13 +111,24 @@ void SysCoreThread::SetElfOverride( const wxString& elf )
Hle_SetElfPath(elf.ToUTF8());
}
void SysCoreThread::Reset()
// Performs a quicker reset that does not deallocate memory associated with PS2 virtual machines
// or cpu providers (recompilers).
void SysCoreThread::ResetQuick()
{
Suspend();
m_resetVirtualMachine = true;
m_hasActiveMachine = false;
}
void SysCoreThread::Reset()
{
ResetQuick();
GetVmMemory().DecommitAll();
SysClearExecutionCache();
}
// Applies a full suite of new settings, which will automatically facilitate the necessary
// resets of the core and components (including plugins, if needed). The scope of resetting
// is determined by comparing the current settings against the new settings, so that only
@ -159,6 +170,8 @@ void SysCoreThread::_reset_stuff_as_needed()
// because of changes to the TLB. We don't actually support the TLB, however, so rec
// resets aren't in fact *needed* ... yet. But might as well, no harm. --air
GetVmMemory().CommitAll();
if( m_resetVirtualMachine || m_resetRecompilers || m_resetProfilers )
{
SysClearExecutionCache();

View File

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

View File

@ -19,15 +19,15 @@
#include "VUops.h"
#include "R5900.h"
static const uint VU0_MEMSIZE = 0x1000;
static const uint VU0_PROGSIZE = 0x1000;
static const uint VU1_MEMSIZE = 0x4000;
static const uint VU1_PROGSIZE = 0x4000;
static const uint VU0_MEMSIZE = 0x1000; // 4kb
static const uint VU0_PROGSIZE = 0x1000; // 4kb
static const uint VU1_MEMSIZE = 0x4000; // 16kb
static const uint VU1_PROGSIZE = 0x4000; // 16kb
static const uint VU0_MEMMASK = VU0_MEMSIZE-1;
static const uint VU0_PROGMASK = VU0_PROGSIZE-1;
static const uint VU1_MEMMASK = VU1_MEMSIZE-1;
static const uint VU1_PROGMASK = VU1_PROGSIZE-1;
static const uint VU0_MEMMASK = VU0_MEMSIZE-1;
static const uint VU0_PROGMASK = VU0_PROGSIZE-1;
static const uint VU1_MEMMASK = VU1_MEMSIZE-1;
static const uint VU1_PROGMASK = VU1_PROGSIZE-1;
#define vuRunCycles (512*12) // Cycles to run ExecuteBlockJIT() for (called from within recs)
#define vu0RunCycles (512*12) // Cycles to run vu0 for whenever ExecuteBlock() is called
@ -47,9 +47,9 @@ static const uint VU1_PROGMASK = VU1_PROGSIZE-1;
class BaseCpuProvider
{
protected:
// allocation counter for multiple init/shutdown calls
// (most or all implementations will need this!)
int m_AllocCount;
// allocation counter for multiple calls to Reserve. Most implementations should utilize
// this variable for sake of robustness.
u32 m_Reserved;
public:
// this boolean indicates to some generic logging facilities if the VU's registers
@ -60,19 +60,27 @@ public:
public:
BaseCpuProvider()
{
m_AllocCount = 0;
m_Reserved = 0;
}
virtual ~BaseCpuProvider() throw()
{
if( m_AllocCount != 0 )
Console.Warning( "Cleanup miscount detected on CPU provider. Count=%d", m_AllocCount );
if( m_Reserved != 0 )
Console.Warning( "Cleanup miscount detected on CPU provider. Count=%d", m_Reserved );
}
virtual const char* GetShortName() const=0;
virtual wxString GetLongName() const=0;
virtual void Allocate()=0;
// returns the number of bytes committed to the working caches for this CPU
// provider (typically this refers to recompiled code caches, but could also refer
// to other optional growable allocations).
virtual size_t GetCommittedCache() const
{
return 0;
}
virtual void Reserve()=0;
virtual void Shutdown()=0;
virtual void Reset()=0;
virtual void Execute(u32 cycles)=0;
@ -88,6 +96,15 @@ public:
{
cpu->Execute(1024);
}
// Gets the current cache reserve allocated to this CPU (value returned in megabytes)
virtual uint GetCacheReserve() const=0;
// Specifies the maximum cache reserve amount for this CPU (value in megabytes).
// CPU providers are allowed to reset their reserves (recompiler resets, etc) if such is
// needed to conform to the new amount requested.
virtual void SetCacheReserve( uint reserveInMegs ) const=0;
};
// --------------------------------------------------------------------------------------
@ -149,13 +166,16 @@ public:
const char* GetShortName() const { return "intVU0"; }
wxString GetLongName() const { return L"VU0 Interpreter"; }
void Allocate() { }
void Reserve() { }
void Shutdown() throw() { }
void Reset() { }
void Step();
void Execute(u32 cycles);
void Clear(u32 addr, u32 size) {}
uint GetCacheReserve() const { return 0; }
void SetCacheReserve( uint reserveInMegs ) const {}
};
class InterpVU1 : public BaseVUmicroCPU
@ -167,13 +187,16 @@ public:
const char* GetShortName() const { return "intVU1"; }
wxString GetLongName() const { return L"VU1 Interpreter"; }
void Allocate() { }
void Reserve() { }
void Shutdown() throw() { }
void Reset() { }
void Step();
void Execute(u32 cycles);
void Clear(u32 addr, u32 size) {}
uint GetCacheReserve() const { return 0; }
void SetCacheReserve( uint reserveInMegs ) const {}
};
// --------------------------------------------------------------------------------------
@ -188,13 +211,16 @@ public:
const char* GetShortName() const { return "mVU0"; }
wxString GetLongName() const { return L"microVU0 Recompiler"; }
void Allocate();
void Reserve();
void Shutdown() throw();
void Reset();
void Execute(u32 cycles);
void Clear(u32 addr, u32 size);
void Vsync() throw();
uint GetCacheReserve() const;
void SetCacheReserve( uint reserveInMegs ) const;
};
class recMicroVU1 : public BaseVUmicroCPU
@ -206,12 +232,15 @@ public:
const char* GetShortName() const { return "mVU1"; }
wxString GetLongName() const { return L"microVU1 Recompiler"; }
void Allocate();
void Reserve();
void Shutdown() throw();
void Reset();
void Execute(u32 cycles);
void Clear(u32 addr, u32 size);
void Vsync() throw();
uint GetCacheReserve() const;
void SetCacheReserve( uint reserveInMegs ) const;
};
// --------------------------------------------------------------------------------------
@ -226,11 +255,14 @@ public:
const char* GetShortName() const { return "sVU0"; }
wxString GetLongName() const { return L"SuperVU0 Recompiler"; }
void Allocate();
void Reserve();
void Shutdown() throw();
void Reset();
void Execute(u32 cycles);
void Clear(u32 Addr, u32 Size);
uint GetCacheReserve() const;
void SetCacheReserve( uint reserveInMegs ) const;
};
class recSuperVU1 : public BaseVUmicroCPU
@ -241,21 +273,20 @@ public:
const char* GetShortName() const { return "sVU1"; }
wxString GetLongName() const { return L"SuperVU1 Recompiler"; }
void Allocate();
void Reserve();
void Shutdown() throw();
void Reset();
void Execute(u32 cycles);
void Clear(u32 Addr, u32 Size);
uint GetCacheReserve() const;
void SetCacheReserve( uint reserveInMegs ) const;
};
extern BaseVUmicroCPU* CpuVU0;
extern BaseVUmicroCPU* CpuVU1;
extern void vuMicroMemAlloc();
extern void vuMicroMemShutdown();
extern void vuMicroMemReset();
// VU0
extern void vu0ResetRegs();
extern void __fastcall vu0ExecMicro(u32 addr);

View File

@ -18,43 +18,41 @@
#include "Common.h"
#include "VUmicro.h"
__aligned16 VURegs vuRegs[2];
static u8* m_vuAllMem = NULL;
static const uint m_vuMemSize =
0x1000 + // VU0micro memory
0x4000 + // VU0 memory
0x4000 + // VU1 memory
0x4000;
void vuMicroMemAlloc()
vuMemoryReserve::vuMemoryReserve()
: _parent( L"VU0/1 on-chip memory", VU1_PROGSIZE + VU1_MEMSIZE + VU0_PROGSIZE + VU0_MEMSIZE )
{
if( m_vuAllMem == NULL )
m_vuAllMem = vtlb_malloc( m_vuMemSize, 16 );
if( m_vuAllMem == NULL )
throw Exception::OutOfMemory( L"VU0 and VU1 on-chip memory" );
u8* curpos = m_vuAllMem;
VU0.Micro = curpos; curpos += 0x1000;
VU0.Mem = curpos; curpos += 0x4000;
VU1.Micro = curpos; curpos += 0x4000;
VU1.Mem = curpos;
//curpos += 0x4000;
}
void vuMicroMemShutdown()
void vuMemoryReserve::Reserve()
{
// -- VTLB Memory Allocation --
_parent::Reserve(HostMemoryMap::VUmem);
//_parent::Reserve(EmuConfig.HostMemMap.VUmem);
vtlb_free( m_vuAllMem, m_vuMemSize );
m_vuAllMem = NULL;
u8* curpos = m_reserve.GetPtr();
VU0.Micro = curpos; curpos += VU0_PROGSIZE;
VU0.Mem = curpos; curpos += VU0_MEMSIZE;
VU1.Micro = curpos; curpos += VU1_PROGSIZE;
VU1.Mem = curpos; curpos += VU1_MEMSIZE;
}
void vuMicroMemReset()
void vuMemoryReserve::Release()
{
pxAssume( VU0.Mem != NULL );
pxAssume( VU1.Mem != NULL );
_parent::Release();
VU0.Micro = VU0.Mem = NULL;
VU1.Micro = VU1.Mem = NULL;
}
void vuMemoryReserve::Reset()
{
_parent::Reset();
pxAssume( VU0.Mem );
pxAssume( VU1.Mem );
memMapVUmicro();
@ -67,8 +65,6 @@ void vuMicroMemReset()
VU0.VF[0].f.z = 0.0f;
VU0.VF[0].f.w = 1.0f;
VU0.VI[0].UL = 0;
memzero_ptr<4*1024>(VU0.Mem);
memzero_ptr<4*1024>(VU0.Micro);
// === VU1 Initialization ===
memzero(VU1.ACC);
@ -79,8 +75,6 @@ void vuMicroMemReset()
VU1.VF[0].f.z = 0.0f;
VU1.VF[0].f.w = 1.0f;
VU1.VI[0].UL = 0;
memzero_ptr<16*1024>(VU1.Mem);
memzero_ptr<16*1024>(VU1.Micro);
}
void SaveStateBase::vuMicroFreeze()

View File

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

View File

@ -19,89 +19,80 @@
#include <wx/stackwalk.h>
class StackDump : public wxStackWalker
{
protected:
FastFormatUnicode m_stackTrace;
wxString m_srcFuncName;
bool m_ignoreDone;
int m_skipped;
public:
StackDump( const FnChar_t* src_function_name )
{
if( src_function_name != NULL )
m_srcFuncName = fromUTF8(src_function_name);
m_ignoreDone = false;
m_skipped = 0;
}
const wxChar* GetStackTrace() const { return m_stackTrace.c_str(); }
protected:
virtual void OnStackFrame(const wxStackFrame& frame)
{
/*if( m_srcFuncName.IsEmpty() || m_srcFuncName == name )
{
// FIXME: This logic isn't reliable yet.
// It's possible for our debug information to not match the function names returned by
// __pxFUNCTION__ (might happen in linux a lot, and could happen in win32 due to
// inlining on Dev aserts). The better approach is a system the queues up all the
// stacktrace info in individual wxStrings, and does a two-pass check -- first pass
// for the function name and, if not found, a second pass that just skips the first
// few stack entries.
// It's important we only walk the stack once because Linux (argh, always linux!) has
// a really god aweful slow stack walker.
// I'm not doing it right now because I've worked on this mess enough for one week. --air
m_ignoreDone = true;
}
if( !m_ignoreDone )
{
m_skipped++;
return;
}*/
m_stackTrace.Write(pxsFmt( L"[%02d]", frame.GetLevel()-m_skipped));
if (!frame.GetName().IsEmpty())
m_stackTrace.Write(pxsFmt( L" %-44s", frame.GetName().c_str() ));
else
m_stackTrace.Write(pxsFmt( L" 0x%-42p", frame.GetAddress() ));
if( frame.HasSourceLocation() )
{
wxFileName wxfn(frame.GetFileName());
wxfn.SetVolume( wxEmptyString );
for( int i=0; i<2; ++i )
wxfn.RemoveDir(0);
m_stackTrace.Write( L" %s:%d", wxfn.GetFullPath().c_str(), frame.GetLine() );
}
m_stackTrace.Write(L"\n");
}
};
static wxString pxGetStackTrace( const FnChar_t* calledFrom )
{
wxString stackTrace;
class StackDump : public wxStackWalker
{
protected:
wxString m_stackTrace;
wxString m_srcFuncName;
bool m_ignoreDone;
int m_skipped;
public:
StackDump( const FnChar_t* src_function_name )
{
if( src_function_name != NULL )
m_srcFuncName = fromUTF8(src_function_name);
m_ignoreDone = false;
m_skipped = 0;
}
const wxString& GetStackTrace() const { return m_stackTrace; }
protected:
virtual void OnStackFrame(const wxStackFrame& frame)
{
wxString name( frame.GetName() );
if( name.IsEmpty() )
{
name = wxsFormat( L"%p ", frame.GetAddress() );
}
/*else if( m_srcFuncName.IsEmpty() || m_srcFuncName == name )
{
// FIXME: This logic isn't reliable yet.
// It's possible for our debug information to not match the function names returned by
// __pxFUNCTION__ (might happen in linux a lot, and could happen in win32 due to
// inlining on Dev aserts). The better approach is a system the queues up all the
// stacktrace info in individual wxStrings, and does a two-pass check -- first pass
// for the function name and, if not found, a second pass that just skips the first
// few stack entries.
// It's important we only walk the stack once because Linux (argh, always linux!) has
// a really god aweful slow stack walker.
// I'm not doing it right now because I've worked on this mess enough for one week. --air
m_ignoreDone = true;
}
if( !m_ignoreDone )
{
m_skipped++;
return;
}*/
//wxString briefName;
wxString essenName;
if( frame.HasSourceLocation() )
{
wxFileName wxfn(frame.GetFileName());
//briefName.Printf( L"(%s:%d)", wxfn.GetFullName().c_str(), frame.GetLine() );
wxfn.SetVolume( wxEmptyString );
int count = wxfn.GetDirCount();
for( int i=0; i<2; ++i )
wxfn.RemoveDir(0);
essenName.Printf( L"%s:%d", wxfn.GetFullPath().c_str(), frame.GetLine() );
}
m_stackTrace += wxString::Format( L"[%02d] %-44s %s\n",
frame.GetLevel()-m_skipped,
name.c_str(),
essenName.c_str()
);
}
};
StackDump dump( calledFrom );
dump.Walk( 3 );
return dump.GetStackTrace();
StackDump dump( calledFrom );
dump.Walk( 3 );
return dump.GetStackTrace();
}
#ifdef __WXDEBUG__

View File

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

View File

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

View File

@ -163,6 +163,12 @@ public:
// this second layer class to act as a bridge between the event system and the class's
// handler implementations.
//
// Explained in detail: The class that wants to listen to shit will implement its expected
// virtual overrides from the listener classes (OnCoreThread_Started, for example), and then
// it adds an instance of the EventListenerHelper_CoreThread class to itself, instead of
// *inheriting* from it. Thusly, the Helper gets initialized when the class is created,
// and when events are dispatched to the listener, it forwards the event to the main class.
// --air
template< typename TypeToDispatchTo >
class EventListenerHelper_CoreThread : public EventListener_CoreThread
@ -212,9 +218,9 @@ public:
protected:
void CorePlugins_OnLoaded() { Owner.OnCorePlugins_Loaded(); }
void CorePlugins_OnInit() { Owner.OnCorePlugins_Init(); }
void CorePlugins_OnOpening() { Owner.OnCorePlugins_Opening(); }
void CorePlugins_OnOpening() { Owner.OnCorePlugins_Opening(); }
void CorePlugins_OnOpened() { Owner.OnCorePlugins_Opened(); }
void CorePlugins_OnClosing() { Owner.OnCorePlugins_Closing(); }
void CorePlugins_OnClosing() { Owner.OnCorePlugins_Closing(); }
void CorePlugins_OnClosed() { Owner.OnCorePlugins_Closed(); }
void CorePlugins_OnShutdown() { Owner.OnCorePlugins_Shutdown(); }
void CorePlugins_OnUnloaded() { Owner.OnCorePlugins_Unloaded(); }

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

@ -155,6 +155,7 @@ void MainEmuFrame::ConnectMenus()
ConnectMenu( MenuId_Config_SysSettings, Menu_SysSettings_Click );
ConnectMenu( MenuId_Config_McdSettings, Menu_McdSettings_Click );
ConnectMenu( MenuId_Config_AppSettings, Menu_WindowSettings_Click );
ConnectMenu( MenuId_Config_GameDatabase,Menu_GameDatabase_Click );
ConnectMenu( MenuId_Config_BIOS, Menu_SelectPluginsBios_Click );
ConnectMenu( MenuId_Config_ResetAll, Menu_ResetAllSettings_Click );
@ -421,7 +422,8 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title)
m_menuConfig.Append(MenuId_Config_SysSettings, _("Emulation &Settings") );
m_menuConfig.Append(MenuId_Config_McdSettings, _("&Memory cards") );
m_menuConfig.Append(MenuId_Config_BIOS, _("&Plugin/BIOS Selector...") );
m_menuConfig.Append(MenuId_Config_BIOS, _("&Plugin/BIOS Selector") );
m_menuConfig.Append(MenuId_Config_GameDatabase, _("Game Database Editor") );
m_menuConfig.AppendSeparator();
m_menuConfig.Append(MenuId_Config_GS, _("&Video (GS)"), m_PluginMenuPacks[PluginId_GS]);

View File

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

View File

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

View File

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

View File

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

View File

@ -59,7 +59,15 @@ namespace Exception
class NotEnumerablePlugin : public BadStream
{
public:
DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, BadStream, wxLt("File is not a PCSX2 plugin") );
DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, BadStream );
wxString FormatDiagnosticMessage() const
{
FastFormatUnicode retval;
retval.Write("File is not a PCSX2 plugin");
_formatDiagMsg(retval);
return retval;
}
};
}

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

View File

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

View File

@ -33,9 +33,10 @@
#include "Common.h"
#include "vtlb.h"
#include "COP0.h"
#include "R5900Exceptions.h"
#include "Utilities/MemsetFast.inl"
using namespace R5900;
using namespace vtlb_private;
@ -46,7 +47,7 @@ namespace vtlb_private
__aligned(64) MapData vtlbdata;
}
static vtlbHandler vtlbHandlerCount=0;
static vtlbHandler vtlbHandlerCount = 0;
static vtlbHandler DefaultPhyHandler;
static vtlbHandler UnmappedVirtHandler0;
@ -78,9 +79,9 @@ DataType __fastcall vtlb_memRead(u32 addr)
switch( DataSize )
{
case 8: return ((vtlbMemR8FP*)vtlbdata.RWFT[0][0][hand])(paddr);
case 16: return ((vtlbMemR16FP*)vtlbdata.RWFT[1][0][hand])(paddr);
case 32: return ((vtlbMemR32FP*)vtlbdata.RWFT[2][0][hand])(paddr);
case 8: return ((vtlbMemR8FP*)vtlbdata.RWFT[0][0][hand])(paddr);
case 16: return ((vtlbMemR16FP*)vtlbdata.RWFT[1][0][hand])(paddr);
case 32: return ((vtlbMemR32FP*)vtlbdata.RWFT[2][0][hand])(paddr);
jNO_DEFAULT;
}
@ -147,9 +148,9 @@ void __fastcall vtlb_memWrite(u32 addr, DataType data)
switch( DataSize )
{
case 8: return ((vtlbMemW8FP*)vtlbdata.RWFT[0][1][hand])(paddr, (u8)data);
case 16: return ((vtlbMemW16FP*)vtlbdata.RWFT[1][1][hand])(paddr, (u16)data);
case 32: return ((vtlbMemW32FP*)vtlbdata.RWFT[2][1][hand])(paddr, (u32)data);
case 8: return ((vtlbMemW8FP*)vtlbdata.RWFT[0][1][hand])(paddr, (u8)data);
case 16: return ((vtlbMemW16FP*)vtlbdata.RWFT[1][1][hand])(paddr, (u16)data);
case 32: return ((vtlbMemW32FP*)vtlbdata.RWFT[2][1][hand])(paddr, (u32)data);
jNO_DEFAULT;
}
@ -255,65 +256,55 @@ _tmpl(void) vtlbUnmappedPWriteLg(u32 addr,const OperandType* data) { vtlb_BusErr
static mem8_t __fastcall vtlbDefaultPhyRead8(u32 addr)
{
Console.Error("vtlbDefaultPhyRead8: 0x%08X", addr);
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
pxFailDev(pxsFmt("(VTLB) Attempted read8 from unmapped physical address @ 0x%08X.", addr));
return 0;
}
static mem16_t __fastcall vtlbDefaultPhyRead16(u32 addr)
{
Console.Error("vtlbDefaultPhyRead16: 0x%08X", addr);
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
pxFailDev(pxsFmt("(VTLB) Attempted read16 from unmapped physical address @ 0x%08X.", addr));
return 0;
}
static mem32_t __fastcall vtlbDefaultPhyRead32(u32 addr)
{
Console.Error("vtlbDefaultPhyRead32: 0x%08X", addr);
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
pxFailDev(pxsFmt("(VTLB) Attempted read32 from unmapped physical address @ 0x%08X.", addr));
return 0;
}
static void __fastcall vtlbDefaultPhyRead64(u32 addr, mem64_t* dest)
{
Console.Error("vtlbDefaultPhyRead64: 0x%08X", addr);
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
pxFailDev(pxsFmt("(VTLB) Attempted read64 from unmapped physical address @ 0x%08X.", addr));
}
static void __fastcall vtlbDefaultPhyRead128(u32 addr, mem128_t* dest)
{
Console.Error("vtlbDefaultPhyRead128: 0x%08X", addr);
pxFailDev("(VTLB) Attempted read from an unmapped physical address.");
pxFailDev(pxsFmt("(VTLB) Attempted read128 from unmapped physical address @ 0x%08X.", addr));
}
static void __fastcall vtlbDefaultPhyWrite8(u32 addr, mem8_t data)
{
Console.Error("vtlbDefaultPhyWrite8: 0x%08X",addr);
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
pxFailDev(pxsFmt("(VTLB) Attempted write8 to unmapped physical address @ 0x%08X.", addr));
}
static void __fastcall vtlbDefaultPhyWrite16(u32 addr, mem16_t data)
{
Console.Error("vtlbDefaultPhyWrite16: 0x%08X",addr);
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
pxFailDev(pxsFmt("(VTLB) Attempted write16 to unmapped physical address @ 0x%08X.", addr));
}
static void __fastcall vtlbDefaultPhyWrite32(u32 addr, mem32_t data)
{
Console.Error("vtlbDefaultPhyWrite32: 0x%08X",addr);
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
pxFailDev(pxsFmt("(VTLB) Attempted write32 to unmapped physical address @ 0x%08X.", addr));
}
static void __fastcall vtlbDefaultPhyWrite64(u32 addr,const mem64_t* data)
{
Console.Error("vtlbDefaultPhyWrite64: 0x%08X",addr);
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
pxFailDev(pxsFmt("(VTLB) Attempted write64 to unmapped physical address @ 0x%08X.", addr));
}
static void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data)
{
Console.Error("vtlbDefaultPhyWrite128: 0x%08X",addr);
pxFailDev("(VTLB) Attempted write to an unmapped physical address.");
pxFailDev(pxsFmt("(VTLB) Attempted write128 to unmapped physical address @ 0x%08X.", addr));
}
#undef _tmpl
@ -333,6 +324,8 @@ __ri void vtlb_ReassignHandler( vtlbHandler rv,
vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128 )
{
pxAssume(rv < VTLB_HANDLER_ITEMS);
vtlbdata.RWFT[0][0][rv] = (void*)((r8!=0) ? r8 : vtlbDefaultPhyRead8);
vtlbdata.RWFT[1][0][rv] = (void*)((r16!=0) ? r16 : vtlbDefaultPhyRead16);
vtlbdata.RWFT[2][0][rv] = (void*)((r32!=0) ? r32 : vtlbDefaultPhyRead32);
@ -348,7 +341,7 @@ __ri void vtlb_ReassignHandler( vtlbHandler rv,
vtlbHandler vtlb_NewHandler()
{
pxAssertDev( vtlbHandlerCount < 127, "VTLB allowed handler count exceeded!" );
pxAssertDev( vtlbHandlerCount < VTLB_HANDLER_ITEMS, "VTLB handler count overflow!" );
return vtlbHandlerCount++;
}
@ -362,7 +355,7 @@ vtlbHandler vtlb_NewHandler()
// Returns a handle for the newly created handler See vtlb_MapHandler for use of the return value.
//
__ri vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128)
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128)
{
vtlbHandler rv = vtlb_NewHandler();
vtlb_ReassignHandler( rv, r8, r16, r32, r64, r128, w8, w16, w32, w64, w128 );
@ -377,45 +370,47 @@ __ri vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMem
// function.
//
// The memory region start and size parameters must be pagesize aligned.
void vtlb_MapHandler(vtlbHandler handler,u32 start,u32 size)
void vtlb_MapHandler(vtlbHandler handler, u32 start, u32 size)
{
verify(0==(start&VTLB_PAGE_MASK));
verify(0==(size&VTLB_PAGE_MASK) && size>0);
s32 value=handler|0x80000000;
while(size>0)
s32 value = handler | 0x80000000;
u32 end = start + (size - VTLB_PAGE_SIZE);
pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) );
while (start <= end)
{
vtlbdata.pmap[start>>VTLB_PAGE_BITS]=value;
start+=VTLB_PAGE_SIZE;
size-=VTLB_PAGE_SIZE;
vtlbdata.pmap[start>>VTLB_PAGE_BITS] = value;
start += VTLB_PAGE_SIZE;
}
}
void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize)
void vtlb_MapBlock(void* base, u32 start, u32 size, u32 blocksize)
{
s32 baseint=(s32)base;
verify(0==(start&VTLB_PAGE_MASK));
verify(0==(size&VTLB_PAGE_MASK) && size>0);
if (blocksize==0)
blocksize=size;
if (!blocksize)
blocksize = size;
verify(0==(blocksize&VTLB_PAGE_MASK) && blocksize>0);
verify(0==(size%blocksize));
while(size>0)
s32 baseint = (s32)base;
u32 end = start + (size - VTLB_PAGE_SIZE);
pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) );
while (start <= end)
{
u32 blocksz=blocksize;
s32 ptr=baseint;
u32 loopsz = blocksize;
s32 ptr = baseint;
while(blocksz>0)
while (loopsz > 0)
{
vtlbdata.pmap[start>>VTLB_PAGE_BITS]=ptr;
vtlbdata.pmap[start>>VTLB_PAGE_BITS] = ptr;
start+=VTLB_PAGE_SIZE;
ptr+=VTLB_PAGE_SIZE;
blocksz-=VTLB_PAGE_SIZE;
size-=VTLB_PAGE_SIZE;
start += VTLB_PAGE_SIZE;
ptr += VTLB_PAGE_SIZE;
loopsz -= VTLB_PAGE_SIZE;
}
}
}
@ -426,13 +421,15 @@ void vtlb_Mirror(u32 new_region,u32 start,u32 size)
verify(0==(start&VTLB_PAGE_MASK));
verify(0==(size&VTLB_PAGE_MASK) && size>0);
while(size>0)
{
vtlbdata.pmap[start>>VTLB_PAGE_BITS]=vtlbdata.pmap[new_region>>VTLB_PAGE_BITS];
u32 end = start + (size-VTLB_PAGE_SIZE);
pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) );
start+=VTLB_PAGE_SIZE;
new_region+=VTLB_PAGE_SIZE;
size-=VTLB_PAGE_SIZE;
while(start <= end)
{
vtlbdata.pmap[start>>VTLB_PAGE_BITS] = vtlbdata.pmap[new_region>>VTLB_PAGE_BITS];
start += VTLB_PAGE_SIZE;
new_region += VTLB_PAGE_SIZE;
}
}
@ -446,66 +443,70 @@ __fi void* vtlb_GetPhyPtr(u32 paddr)
//virtual mappings
//TODO: Add invalid paddr checks
void vtlb_VMap(u32 vaddr,u32 paddr,u32 sz)
void vtlb_VMap(u32 vaddr,u32 paddr,u32 size)
{
verify(0==(vaddr&VTLB_PAGE_MASK));
verify(0==(paddr&VTLB_PAGE_MASK));
verify(0==(sz&VTLB_PAGE_MASK) && sz>0);
verify(0==(size&VTLB_PAGE_MASK) && size>0);
while(sz>0)
while (size > 0)
{
s32 pme;
if (paddr>=VTLB_PMAP_SZ)
if (paddr >= VTLB_PMAP_SZ)
{
pme=UnmappedPhyHandler0;
if (paddr&0x80000000)
pme=UnmappedPhyHandler1;
pme|=0x80000000;
pme|=paddr;// top bit is set anyway ...
pme = UnmappedPhyHandler0;
if (paddr & 0x80000000)
pme = UnmappedPhyHandler1;
pme |= 0x80000000;
pme |= paddr;// top bit is set anyway ...
}
else
{
pme=vtlbdata.pmap[paddr>>VTLB_PAGE_BITS];
pme = vtlbdata.pmap[paddr>>VTLB_PAGE_BITS];
if (pme<0)
pme|=paddr;// top bit is set anyway ...
pme |= paddr;// top bit is set anyway ...
}
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=pme-vaddr;
vaddr+=VTLB_PAGE_SIZE;
paddr+=VTLB_PAGE_SIZE;
sz-=VTLB_PAGE_SIZE;
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS] = pme-vaddr;
vaddr += VTLB_PAGE_SIZE;
paddr += VTLB_PAGE_SIZE;
size -= VTLB_PAGE_SIZE;
}
}
void vtlb_VMapBuffer(u32 vaddr,void* buffer,u32 sz)
void vtlb_VMapBuffer(u32 vaddr,void* buffer,u32 size)
{
verify(0==(vaddr&VTLB_PAGE_MASK));
verify(0==(sz&VTLB_PAGE_MASK) && sz>0);
u32 bu8=(u32)buffer;
while(sz>0)
verify(0==(size&VTLB_PAGE_MASK) && size>0);
u32 bu8 = (u32)buffer;
while (size > 0)
{
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=bu8-vaddr;
vaddr+=VTLB_PAGE_SIZE;
bu8+=VTLB_PAGE_SIZE;
sz-=VTLB_PAGE_SIZE;
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS] = bu8-vaddr;
vaddr += VTLB_PAGE_SIZE;
bu8 += VTLB_PAGE_SIZE;
size -= VTLB_PAGE_SIZE;
}
}
void vtlb_VMapUnmap(u32 vaddr,u32 sz)
void vtlb_VMapUnmap(u32 vaddr,u32 size)
{
verify(0==(vaddr&VTLB_PAGE_MASK));
verify(0==(sz&VTLB_PAGE_MASK) && sz>0);
verify(0==(size&VTLB_PAGE_MASK) && size>0);
while(sz>0)
while (size > 0)
{
u32 handl=UnmappedVirtHandler0;
if (vaddr&0x80000000)
u32 handl = UnmappedVirtHandler0;
if (vaddr & 0x80000000)
{
handl=UnmappedVirtHandler1;
handl = UnmappedVirtHandler1;
}
handl|=vaddr; // top bit is set anyway ...
handl|=0x80000000;
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=handl-vaddr;
vaddr+=VTLB_PAGE_SIZE;
sz-=VTLB_PAGE_SIZE;
handl |= vaddr; // top bit is set anyway ...
handl |= 0x80000000;
vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS] = handl-vaddr;
vaddr += VTLB_PAGE_SIZE;
size -= VTLB_PAGE_SIZE;
}
}
@ -562,60 +563,86 @@ void vtlb_Term()
}
// Reserves the vtlb core allocation used by various emulation components!
//
// [TODO] basemem - request allocating memory at the specified virtual location, which can allow
// for easier debugging and/or 3rd party cheat programs. If 0, the operating system
// default is used.
void vtlb_Core_Alloc()
{
if( vtlbdata.alloc_base != NULL ) return;
vtlbdata.alloc_current = 0;
#ifdef __LINUX__
vtlbdata.alloc_base = SysMmapEx( 0x16000000, VTLB_ALLOC_SIZE, 0x80000000, "Vtlb" );
#else
// Win32 just needs this, since malloc always maps below 2GB.
vtlbdata.alloc_base = (u8*)_aligned_malloc( VTLB_ALLOC_SIZE, 4096 );
if( vtlbdata.alloc_base == NULL )
throw Exception::OutOfMemory( pxsFmt(L"PS2 mappable system ram (%u megs)", VTLB_ALLOC_SIZE / _1mb) );
#endif
if (!vtlbdata.vmap)
{
vtlbdata.vmap = (s32*)_aligned_malloc( VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap), 16 );
if (!vtlbdata.vmap)
throw Exception::OutOfMemory( L"VTLB Virtual Address Translation LUT" )
.SetDiagMsg(pxsFmt("(%u megs)", VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap) / _1mb)
);
}
}
void vtlb_Core_Shutdown()
void vtlb_Core_Free()
{
if( vtlbdata.alloc_base == NULL ) return;
#ifdef __LINUX__
SafeSysMunmap( vtlbdata.alloc_base, VTLB_ALLOC_SIZE );
#else
// Make sure and unprotect memory first, since CrtDebug will try to write to it.
HostSys::MemProtect( vtlbdata.alloc_base, VTLB_ALLOC_SIZE, Protect_ReadWrite );
safe_aligned_free( vtlbdata.alloc_base );
#endif
safe_aligned_free( vtlbdata.vmap );
}
// This function allocates memory block with are compatible with the Vtlb's requirements
// for memory locations. The Vtlb requires the topmost bit (Sign bit) of the memory
// pointer to be cleared. Some operating systems and/or implementations of malloc do that,
// but others do not. So use this instead to allocate the memory correctly for your
// platform.
//
u8* vtlb_malloc( uint size, uint align )
static wxString GetHostVmErrorMsg()
{
vtlbdata.alloc_current += align-1;
vtlbdata.alloc_current &= ~(align-1);
int rv = vtlbdata.alloc_current;
vtlbdata.alloc_current += size;
pxAssertDev( vtlbdata.alloc_current < VTLB_ALLOC_SIZE, "(vtlb_malloc) memory overflow! Please increase the size of VTLB_ALLOC_SIZE!" );
return &vtlbdata.alloc_base[rv];
return pxE(".Error:HostVmReserve",
L"Your system is too low on virtual resources for PCSX2 to run. This can be "
L"caused by having a small or disabled swapfile, or by other programs that are "
L"hogging resources."
);
}
void vtlb_free( void* pmem, uint size )
// --------------------------------------------------------------------------------------
// VtlbMemoryReserve (implementations)
// --------------------------------------------------------------------------------------
VtlbMemoryReserve::VtlbMemoryReserve( const wxString& name, size_t size )
: m_reserve( name, size )
{
vtlbdata.alloc_current -= size;
pxAssertDev( vtlbdata.alloc_current >= 0, "(vtlb_free) mismatched calls to vtlb_malloc and free detected via memory underflow." );
return;
m_reserve.SetPageAccessOnCommit( PageAccess_ReadWrite() );
}
void VtlbMemoryReserve::SetBaseAddr( uptr newaddr )
{
m_reserve.SetBaseAddr( newaddr );
}
void VtlbMemoryReserve::Reserve( sptr hostptr )
{
if (!m_reserve.ReserveAt( hostptr ))
{
throw Exception::OutOfMemory( m_reserve.GetName() )
.SetDiagMsg(L"Vtlb memory could not be reserved.")
.SetUserMsg(GetHostVmErrorMsg());
}
}
void VtlbMemoryReserve::Commit()
{
if (IsCommitted()) return;
if (!m_reserve.Commit())
{
throw Exception::OutOfMemory( m_reserve.GetName() )
.SetDiagMsg(L"Vtlb memory could not be committed.")
.SetUserMsg(GetHostVmErrorMsg());
}
}
void VtlbMemoryReserve::Reset()
{
Commit();
memzero_sse_a(m_reserve.GetPtr(), m_reserve.GetCommittedBytes());
}
void VtlbMemoryReserve::Decommit()
{
m_reserve.Reset();
}
void VtlbMemoryReserve::Release()
{
m_reserve.Release();
}
bool VtlbMemoryReserve::IsCommitted() const
{
return !!m_reserve.GetCommittedPageCount();
}

View File

@ -17,6 +17,10 @@
#include "MemoryTypes.h"
#include "Utilities/PageFaultSource.h"
static const uptr VTLB_AllocUpperBounds = _1gb * 2;
// Specialized function pointers for each read type
typedef mem8_t __fastcall vtlbMemR8FP(u32 addr);
typedef mem16_t __fastcall vtlbMemR16FP(u32 addr);
@ -34,12 +38,10 @@ typedef void __fastcall vtlbMemW128FP(u32 addr,const mem128_t* data);
typedef u32 vtlbHandler;
extern void vtlb_Core_Alloc();
extern void vtlb_Core_Shutdown();
extern void vtlb_Core_Free();
extern void vtlb_Init();
extern void vtlb_Reset();
extern void vtlb_Term();
extern u8* vtlb_malloc( uint size, uint align );
extern void vtlb_free( void* pmem, uint size );
extern vtlbHandler vtlb_NewHandler();
@ -85,32 +87,121 @@ extern void vtlb_DynGenWrite_Const( u32 bits, u32 addr_const );
extern void vtlb_DynGenRead64_Const( u32 bits, u32 addr_const );
extern void vtlb_DynGenRead32_Const( u32 bits, bool sign, u32 addr_const );
// --------------------------------------------------------------------------------------
// VtlbMemoryReserve
// --------------------------------------------------------------------------------------
class VtlbMemoryReserve
{
protected:
VirtualMemoryReserve m_reserve;
public:
VtlbMemoryReserve( const wxString& name, size_t size );
virtual ~VtlbMemoryReserve() throw()
{
m_reserve.Release();
}
virtual void Reserve( sptr hostptr );
virtual void Release();
virtual void Commit();
virtual void Reset();
virtual void Decommit();
virtual void SetBaseAddr( uptr newaddr );
bool IsCommitted() const;
};
// --------------------------------------------------------------------------------------
// eeMemoryReserve
// --------------------------------------------------------------------------------------
class eeMemoryReserve : public VtlbMemoryReserve
{
typedef VtlbMemoryReserve _parent;
public:
eeMemoryReserve();
virtual ~eeMemoryReserve() throw()
{
Release();
}
void Reserve();
void Commit();
void Decommit();
void Reset();
void Release();
};
// --------------------------------------------------------------------------------------
// iopMemoryReserve
// --------------------------------------------------------------------------------------
class iopMemoryReserve : public VtlbMemoryReserve
{
typedef VtlbMemoryReserve _parent;
public:
iopMemoryReserve();
virtual ~iopMemoryReserve() throw()
{
Release();
}
void Reserve();
void Commit();
void Decommit();
void Release();
void Reset();
};
// --------------------------------------------------------------------------------------
// vuMemoryReserve
// --------------------------------------------------------------------------------------
class vuMemoryReserve : public VtlbMemoryReserve
{
typedef VtlbMemoryReserve _parent;
public:
vuMemoryReserve();
virtual ~vuMemoryReserve() throw()
{
Release();
}
virtual void Reserve();
virtual void Release();
void Reset();
};
namespace vtlb_private
{
// Allocate enough memory for both EE and IOP memory space (IOP is roughly 2.5mb,
// so we alloc 4mb for now -- a little more than is needed).
static const uint VTLB_ALLOC_SIZE = sizeof(*eeMem) + (_1mb*4);
static const uint VTLB_PAGE_BITS = 12;
static const uint VTLB_PAGE_MASK = 4095;
static const uint VTLB_PAGE_SIZE = 4096;
static const uint VTLB_PMAP_ITEMS = 0x20000000 / VTLB_PAGE_SIZE;
static const uint VTLB_PMAP_SZ = 0x20000000;
static const uint VTLB_VMAP_ITEMS = 0x100000000ULL / VTLB_PAGE_SIZE;
static const uint VTLB_PMAP_SZ = _1mb * 512;
static const uint VTLB_PMAP_ITEMS = VTLB_PMAP_SZ / VTLB_PAGE_SIZE;
static const uint VTLB_VMAP_ITEMS = _4gb / VTLB_PAGE_SIZE;
static const uint VTLB_HANDLER_ITEMS = 128;
struct MapData
{
u8* alloc_base; //base of the memory array
int alloc_current; //current base
s32 pmap[VTLB_PMAP_ITEMS]; //512KB
s32 vmap[VTLB_VMAP_ITEMS]; //4MB
// first indexer -- 8/16/32/64/128 bit tables [values 0-4]
// second indexer -- read/write [0 or 1]
// third indexer -- 128 possible handlers!
void* RWFT[5][2][128];
void* RWFT[5][2][VTLB_HANDLER_ITEMS];
s32 pmap[VTLB_PMAP_ITEMS]; //512KB
s32* vmap; //4MB (allocated by vtlb_init)
MapData()
{
vmap = NULL;
}
};
extern __aligned(64) MapData vtlbdata;

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -46,7 +46,7 @@ void StreamException_ThrowLastError( const wxString& streamname, HANDLE result )
default:
{
throw Exception::Stream( streamname ).SetDiagMsg(wxsFormat( L"General Win32 File/stream error [GetLastError: %d]", error ));
throw Exception::BadStream( streamname ).SetDiagMsg(pxsFmt( L"General Win32 File/stream error [GetLastError: %d]", error ));
}
}
}
@ -58,7 +58,7 @@ bool StreamException_LogLastError( const wxString& streamname, const wxChar* act
{
StreamException_ThrowLastError( streamname, result );
}
catch( Exception::Stream& ex )
catch( Exception::BadStream& ex )
{
Console.WriteLn( Color_Yellow, L"%s: %s", action, ex.FormatDiagnosticMessage().c_str() );
return true;

View File

@ -18,18 +18,4 @@
#include <winnt.h>
#include "Common.h"
#include "System/PageFaultSource.h"
int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
{
if( eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION )
return EXCEPTION_CONTINUE_SEARCH;
Source_PageFault.Dispatch( PageFaultInfo( (uptr)eps->ExceptionRecord->ExceptionInformation[1] ) );
return Source_PageFault.WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
}
void InstallSignalHandler()
{
// NOP on Win32 systems -- we use __try{} __except{} instead.
}
#include "Utilities/PageFaultSource.h"

View File

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

View File

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

View File

@ -81,9 +81,6 @@ public:
__fi int Index (u32 startpc) const
{
int idx = LastIndex(startpc);
// fixme: I changed the parenthesis to be unambiguous, but this needs to be checked to see if ((x or y or z) and w)
// is correct, or ((x or y) or (z and w)), or some other variation. --arcum42
// Mixing &&'s and ||'s is not actually ambiguous; &&'s take precedence. Reverted to old behavior -- ChickenLiver.
if ((idx == -1) || (startpc < blocks[idx].startpc) ||
((blocks[idx].size) && (startpc >= blocks[idx].startpc + blocks[idx].size * 4)))
return -1;
@ -139,9 +136,10 @@ public:
static void recLUT_SetPage(uptr reclut[0x10000], uptr hwlut[0x10000],
BASEBLOCK *mapbase, uint pagebase, uint pageidx, uint mappage)
{
// this value is in 64k pages!
uint page = pagebase + pageidx;
jASSUME( page < 0x10000 );
pxAssume( page < 0x10000 );
reclut[page] = (uptr)&mapbase[(mappage - page) << 14];
if (hwlut)
hwlut[page] = 0u - (pagebase << 16);

View File

@ -22,6 +22,7 @@
#include "iR3000A.h"
#include "BaseblockEx.h"
#include "System/RecTypes.h"
#include <time.h>
@ -32,7 +33,6 @@
#include "IopCommon.h"
#include "iCore.h"
#include "SamplProf.h"
#include "NakedAsm.h"
#include "AppConfig.h"
@ -50,13 +50,8 @@ uptr psxhwLUT[0x10000];
#define HWADDR(mem) (psxhwLUT[mem >> 16] + (mem))
#define MAPBASE 0x48000000
#define RECMEM_SIZE (8*1024*1024)
static RecompiledCodeReserve* recMem = NULL;
// R3000A statics
int psxreclog = 0;
static u8 *recMem = NULL; // the recompiled blocks will be here
static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here
static BASEBLOCK *recROM = NULL; // and here
static BASEBLOCK *recROM1 = NULL; // also here
@ -130,7 +125,7 @@ static void recEventTest()
// stackframe setup code in this function)
static void __fastcall StackFrameCheckFailed( int espORebp, int regval )
{
pxFailDev( wxsFormat( L"(R3000A Recompiler Stackframe) Sanity check failed on %s\n\tCurrent=%d; Saved=%d",
pxFailDev( pxsFmt( L"(R3000A Recompiler Stackframe) Sanity check failed on %s\n\tCurrent=%d; Saved=%d",
(espORebp==0) ? L"ESP" : L"EBP", regval, (espORebp==0) ? s_store_esp : s_store_ebp )
);
@ -346,7 +341,7 @@ static DynGenFunc* _DynGen_EnterRecompiledCode()
static void _DynGen_Dispatchers()
{
// In case init gets called multiple times:
HostSys::MemProtectStatic( iopRecDispatchers, Protect_ReadWrite, false );
HostSys::MemProtectStatic( iopRecDispatchers, PageAccess_ReadWrite() );
// clear the buffer to 0xcc (easier debugging).
memset_8<0xcc,__pagesize>( iopRecDispatchers );
@ -363,7 +358,7 @@ static void _DynGen_Dispatchers()
iopJITCompileInBlock = _DynGen_JITCompileInBlock();
iopEnterRecompiledCode = _DynGen_EnterRecompiledCode();
HostSys::MemProtectStatic( iopRecDispatchers, Protect_ReadOnly, true );
HostSys::MemProtectStatic( iopRecDispatchers, PageAccess_ExecOnly() );
recBlocks.SetJITCompile( iopJITCompile );
}
@ -754,23 +749,38 @@ void psxRecompileCodeConst3(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode,
noconstcode(0);
}
static uptr m_ConfiguredCacheReserve = 32;
static u8* m_recBlockAlloc = NULL;
static const uint m_recBlockAllocSize =
(((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK));
static void recReserveCache()
{
if (!recMem) recMem = new RecompiledCodeReserve(L"R3000A Recompiler Cache", _1mb * 2);
recMem->SetProfilerName("IOPrec");
while (!recMem->IsOk())
{
if (recMem->Reserve( m_ConfiguredCacheReserve * _1mb, HostMemoryMap::IOPrec ) != NULL) break;
// If it failed, then try again (if possible):
if (m_ConfiguredCacheReserve < 4) break;
m_ConfiguredCacheReserve /= 2;
}
recMem->ThrowIfNotOk();
}
static void recReserve()
{
// IOP has no hardware requirements!
recReserveCache();
}
static void recAlloc()
{
// Note: the VUrec depends on being able to grab an allocation below the 0x10000000 line,
// so we give the EErec an address above that to try first as it's basemem address, hence
// the 0x28000000 pick (0x20000000 is picked by the EE)
if( recMem == NULL )
recMem = (u8*)SysMmapEx( 0x28000000, RECMEM_SIZE, 0, "recAlloc(R3000a)" );
if( recMem == NULL )
throw Exception::OutOfMemory( L"R3000A recompiled code cache" );
// Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory.
// Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
// always 4 bytes long).
@ -795,24 +805,22 @@ static void recAlloc()
if( s_pInstCache == NULL )
throw Exception::OutOfMemory( L"R3000 InstCache." );
ProfilerRegisterSource( "IOP Rec", recMem, RECMEM_SIZE );
_DynGen_Dispatchers();
}
void recResetIOP()
{
// calling recResetIOP without first calling recInit is bad mojo.
pxAssert( recMem != NULL );
pxAssert( m_recBlockAlloc != NULL );
DevCon.WriteLn( "iR3000A Recompiler reset." );
memset_8<0xcc,RECMEM_SIZE>( recMem ); // 0xcc is INT3
recAlloc();
recMem->Reset();
iopClearRecLUT((BASEBLOCK*)m_recBlockAlloc,
(((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4)));
for (int i = 0; i < 0x10000; i++)
recLUT_SetPage(psxRecLUT, 0, 0, 0, i, 0);
// IOP knows 64k pages, hence for the 0x10000's
// The bottom 2 bits of PC are always zero, so we <<14 to "compress"
@ -820,6 +828,7 @@ void recResetIOP()
// We're only mapping 20 pages here in 4 places.
// 0x80 comes from : (Ps2MemSize::IopRam / 0x10000) * 4
for (int i=0; i<0x80; i++)
{
recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0x0000, i, i & 0x1f);
@ -847,15 +856,14 @@ void recResetIOP()
recBlocks.Reset();
g_psxMaxRecMem = 0;
recPtr = recMem;
recPtr = *recMem;
psxbranch = 0;
}
static void recShutdown()
{
ProfilerTerminateSource( "IOPRec" );
safe_delete( recMem );
SafeSysMunmap(recMem, RECMEM_SIZE);
safe_aligned_free( m_recBlockAlloc );
safe_free( s_pInstCache );
@ -1202,8 +1210,9 @@ static void __fastcall iopRecRecompile( const u32 startpc )
pxAssert( startpc );
// if recPtr reached the mem limit reset whole mem
if (((uptr)recPtr - (uptr)recMem) >= (RECMEM_SIZE - 0x10000))
if (recPtr >= (recMem->GetPtrEnd() - _64kb)) {
recResetIOP();
}
x86SetPtr( recPtr );
x86Align(16);
@ -1390,12 +1399,12 @@ StartRecomp:
}
}
pxAssert( x86Ptr < recMem+RECMEM_SIZE );
pxAssert( xGetPtr() < recMem->GetPtrEnd() );
pxAssert(x86Ptr - recPtr < 0x10000);
s_pCurBlockEx->x86size = x86Ptr - recPtr;
pxAssert(xGetPtr() - recPtr < _64kb);
s_pCurBlockEx->x86size = xGetPtr() - recPtr;
recPtr = x86Ptr;
recPtr = xGetPtr();
pxAssert( (g_psxHasConstReg&g_psxFlushedConstReg) == g_psxHasConstReg );
@ -1403,12 +1412,25 @@ StartRecomp:
s_pCurBlockEx = NULL;
}
static void recSetCacheReserve( uint reserveInMegs )
{
m_ConfiguredCacheReserve = reserveInMegs;
}
static uint recGetCacheReserve()
{
return m_ConfiguredCacheReserve;
}
R3000Acpu psxRec = {
recAlloc,
recReserve,
recResetIOP,
recExecute,
recExecuteBlock,
recClearIOP,
recShutdown
recShutdown,
recGetCacheReserve,
recSetCacheReserve
};

View File

@ -21,15 +21,14 @@
#include "R5900Exceptions.h"
#include "R5900OpcodeTables.h"
#include "iR5900.h"
#include "BaseblockEx.h"
#include "System/RecTypes.h"
#include "vtlb.h"
#include "SamplProf.h"
#include "Dump.h"
#include "System/SysThreads.h"
#include "GS.h"
#include "CDVD/CDVD.h"
#include "Elfheader.h"
@ -37,14 +36,18 @@
# include <csetjmp>
#endif
#include "Utilities/MemsetFast.inl"
using namespace x86Emitter;
using namespace R5900;
#define PC_GETBLOCK(x) PC_GETBLOCK_(x, recLUT)
u32 maxrecmem = 0;
static __aligned16 uptr recLUT[0x10000];
static __aligned16 uptr hwLUT[0x10000];
static __aligned16 uptr recLUT[_64kb];
static __aligned16 uptr hwLUT[_64kb];
#define HWADDR(mem) (hwLUT[mem >> 16] + (mem))
@ -57,18 +60,41 @@ __aligned16 GPR_reg64 g_cpuConstRegs[32] = {0};
u32 g_cpuHasConstReg = 0, g_cpuFlushedConstReg = 0;
bool g_cpuFlushedPC, g_cpuFlushedCode, g_recompilingDelaySlot, g_maySignalException;
// --------------------------------------------------------------------------------------
// R5900LutReserve_RAM
// --------------------------------------------------------------------------------------
class R5900LutReserve_RAM : public SpatialArrayReserve
{
typedef SpatialArrayReserve _parent;
public:
R5900LutReserve_RAM( const wxString& name )
: _parent( name )
{
}
protected:
void OnCommittedBlock( void* block );
};
////////////////////////////////////////////////////////////////
// Static Private Variables - R5900 Dynarec
#define X86
static const int RECCONSTBUF_SIZE = 16384 * 2; // 64 bit consts in 32 bit units
static u8 *recMem = NULL; // the recompiled blocks will be here
static RecompiledCodeReserve* recMem = NULL;
static SpatialArrayReserve* recRAMCopy = NULL;
static R5900LutReserve_RAM* recLutReserve_RAM = NULL;
static uptr m_ConfiguredCacheReserve = 64;
static u32* recConstBuf = NULL; // 64-bit pseudo-immediates
static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here
static BASEBLOCK *recROM = NULL; // and here
static BASEBLOCK *recROM1 = NULL; // also here
static u32 *recRAMCopy = NULL;
static BaseBlocks recBlocks;
static u8* recPtr = NULL;
static u32 *recConstBufPtr = NULL;
@ -506,7 +532,7 @@ static DynGenFunc* _DynGen_EnterRecompiledCode()
static void _DynGen_Dispatchers()
{
// In case init gets called multiple times:
HostSys::MemProtectStatic( eeRecDispatchers, Protect_ReadWrite, false );
HostSys::MemProtectStatic( eeRecDispatchers, PageAccess_ReadWrite() );
// clear the buffer to 0xcc (easier debugging).
memset_8<0xcc,__pagesize>( eeRecDispatchers );
@ -523,7 +549,7 @@ static void _DynGen_Dispatchers()
JITCompileInBlock = _DynGen_JITCompileInBlock();
EnterRecompiledCode = _DynGen_EnterRecompiledCode();
HostSys::MemProtectStatic( eeRecDispatchers, Protect_ReadOnly, true );
HostSys::MemProtectStatic( eeRecDispatchers, PageAccess_ExecOnly() );
recBlocks.SetJITCompile( JITCompile );
}
@ -531,24 +557,45 @@ static void _DynGen_Dispatchers()
//////////////////////////////////////////////////////////////////////////////////////////
//
static const int REC_CACHEMEM = 0x01000000;
static void __fastcall dyna_block_discard(u32 start,u32 sz);
// memory allocation handle for the entire BASEBLOCK and stack allocations.
static u8* m_recBlockAlloc = NULL;
static __ri void ClearRecLUT(BASEBLOCK* base, int memsize)
{
for (int i = 0; i < memsize/4; i++)
base[i].SetFnptr((uptr)JITCompile);
}
static const uint m_recBlockAllocSize =
(((Ps2MemSize::Base + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK))
+ RECCONSTBUF_SIZE * sizeof(u32) + Ps2MemSize::Base;
void R5900LutReserve_RAM::OnCommittedBlock( void* block )
{
_parent::OnCommittedBlock(block);
ClearRecLUT((BASEBLOCK*)block, __pagesize * m_blocksize);
}
static void recThrowHardwareDeficiency( const wxChar* extFail )
{
throw Exception::HardwareDeficiency()
.SetDiagMsg(wxsFormat( L"R5900-32 recompiler init failed: %s is not available.", extFail))
.SetUserMsg(wxsFormat(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail ));
.SetDiagMsg(pxsFmt( L"R5900-32 recompiler init failed: %s is not available.", extFail))
.SetUserMsg(pxsFmt(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail ));
}
static void recAlloc()
static void recReserveCache()
{
if (!recMem) recMem = new RecompiledCodeReserve(L"R5900-32 Recompiler Cache", _1mb * 4);
recMem->SetProfilerName("EErec");
while (!recMem->IsOk())
{
if (recMem->Reserve( m_ConfiguredCacheReserve * _1mb, HostMemoryMap::EErec ) != NULL) break;
// If it failed, then try again (if possible):
if (m_ConfiguredCacheReserve < 16) break;
m_ConfiguredCacheReserve /= 2;
}
recMem->ThrowIfNotOk();
}
static void recReserve()
{
// Hardware Requirements Check...
@ -561,99 +608,31 @@ static void recAlloc()
if ( !x86caps.hasStreamingSIMD2Extensions )
recThrowHardwareDeficiency( L"SSE2" );
if( recMem == NULL )
{
// It's handy to have a constant base address for the EE recompiler buffer, since it
// allows me to key in the address directly in the debugger, and also recognize EE
// recompiled code from user-provisioned stack traces. But besides those, the recompiler
// has no actual restrictions on where it's compiled code buffer is located.
// Note: the SuperVU recompiler depends on being able to grab an allocation below the
// 0x10000000 line, so we give the EErec an address above that to try first as it's
// basemem address, hence the 0x20000000 pick.
const uint cachememsize = REC_CACHEMEM+0x1000;
recMem = (u8*)SysMmapEx( 0x20000000, cachememsize, 0, "recAlloc(R5900)" );
}
if( recMem == NULL )
throw Exception::OutOfMemory( L"R5900-32 recompiled code cache" );
// Goal: Allocate BASEBLOCKs for every possible branch target in PS2 memory.
// Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
// always 4 bytes long).
if( m_recBlockAlloc == NULL )
m_recBlockAlloc = (u8*) _aligned_malloc( m_recBlockAllocSize, 4096 );
if( m_recBlockAlloc == NULL )
throw Exception::OutOfMemory( L"R5900-32 BASEBLOCK tables" );
u8* curpos = m_recBlockAlloc;
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK);
recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK);
recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK);
recConstBuf = (u32*)curpos; curpos += RECCONSTBUF_SIZE * sizeof(u32);
recRAMCopy = (u32*)curpos;
if( s_pInstCache == NULL )
{
s_nInstCacheSize = 128;
s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize );
}
if( s_pInstCache == NULL )
throw Exception::OutOfMemory( L"R5900-32 InstCache" );
// No errors.. Proceed with initialization:
ProfilerRegisterSource( "EE Rec", recMem, REC_CACHEMEM+0x1000 );
_DynGen_Dispatchers();
x86FpuState = FPU_STATE;
recReserveCache();
}
struct ManualPageTracking
static void recAlloc()
{
u16 page;
u8 counter;
};
if (!recRAMCopy)
{
recRAMCopy = new SpatialArrayReserve( L"R5900 RAM copy" );
recRAMCopy->SetBlockSize(_16kb);
recRAMCopy->Reserve(Ps2MemSize::MainRam);
}
if (!recRAM)
{
recLutReserve_RAM = new R5900LutReserve_RAM( L"R5900 RAM LUT" );
recLutReserve_RAM->SetBlockSize(_16kb);
recLutReserve_RAM->Reserve(Ps2MemSize::MainRam + Ps2MemSize::Rom + Ps2MemSize::Rom1);
}
static __aligned16 u16 manual_page[Ps2MemSize::Base >> 12];
static __aligned16 u8 manual_counter[Ps2MemSize::Base >> 12];
BASEBLOCK* basepos = (BASEBLOCK*)recLutReserve_RAM->GetPtr();
recRAM = basepos; basepos += (Ps2MemSize::MainRam / 4);
recROM = basepos; basepos += (Ps2MemSize::Rom / 4);
recROM1 = basepos; basepos += (Ps2MemSize::Rom1 / 4);
static u32 eeRecIsReset = false;
////////////////////////////////////////////////////
void recResetEE( void )
{
//AtomicExchange( eeRecNeedsReset, false );
if( AtomicExchange( eeRecIsReset, true ) ) return;
Console.WriteLn( Color_StrongBlack, "EE/iR5900-32 Recompiler Reset" );
maxrecmem = 0;
if (IsDevBuild)
memset_8<0xcc, REC_CACHEMEM>(recMem); // 0xcc is INT3
memzero_ptr<m_recBlockAllocSize - Ps2MemSize::Base>( m_recBlockAlloc ); // Excluding the 32mb ram copy
memzero_ptr<RECCONSTBUF_SIZE * sizeof(u32)>(recConstBuf);
memzero( manual_page );
memzero( manual_counter );
ClearRecLUT((BASEBLOCK*)m_recBlockAlloc,
(((Ps2MemSize::Base + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4)));
if( s_pInstCache )
memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize );
recBlocks.Reset();
mmap_ResetBlockTracking();
#ifdef _MSC_VER
__asm emms;
#else
__asm__("emms");
#endif
pxAssert(recLutReserve_RAM->GetPtrEnd() == (u8*)basepos);
for (int i = 0; i < 0x10000; i++)
recLUT_SetPage(recLUT, 0, 0, 0, i, 0);
@ -684,30 +663,100 @@ void recResetEE( void )
recLUT_SetPage(recLUT, hwLUT, recROM1, 0xa000, i, i - 0x1e00);
}
x86SetPtr(recMem);
if( recConstBuf == NULL )
recConstBuf = (u32*) _aligned_malloc( RECCONSTBUF_SIZE * sizeof(*recConstBuf), 16 );
recPtr = recMem;
if( recConstBuf == NULL )
throw Exception::OutOfMemory( L"R5900-32 SIMD Constants Buffer" );
if( s_pInstCache == NULL )
{
s_nInstCacheSize = 128;
s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize );
}
if( s_pInstCache == NULL )
throw Exception::OutOfMemory( L"R5900-32 InstCache" );
// No errors.. Proceed with initialization:
_DynGen_Dispatchers();
x86FpuState = FPU_STATE;
}
struct ManualPageTracking
{
u16 page;
u8 counter;
};
static __aligned16 u16 manual_page[Ps2MemSize::MainRam >> 12];
static __aligned16 u8 manual_counter[Ps2MemSize::MainRam >> 12];
static u32 eeRecIsReset = false;
static u32 eeRecNeedsReset = false;
static bool eeCpuExecuting = false;
////////////////////////////////////////////////////
static void recResetRaw()
{
recAlloc();
if( AtomicExchange( eeRecIsReset, true ) ) return;
AtomicExchange( eeRecNeedsReset, false );
Console.WriteLn( Color_StrongBlack, "EE/iR5900-32 Recompiler Reset" );
recMem->Reset();
recRAMCopy->Reset();
recLutReserve_RAM->Reset();
maxrecmem = 0;
memzero_ptr<RECCONSTBUF_SIZE * sizeof(recConstBuf)>(recConstBuf);
if( s_pInstCache )
memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize );
recBlocks.Reset();
mmap_ResetBlockTracking();
x86SetPtr(*recMem);
recPtr = *recMem;
recConstBufPtr = recConstBuf;
x86FpuState = FPU_STATE;
branch = 0;
}
static void recShutdown( void )
static void recShutdown()
{
ProfilerTerminateSource( "EERec" );
safe_delete( recMem );
safe_delete( recRAMCopy );
safe_delete( recLutReserve_RAM );
recBlocks.Reset();
SafeSysMunmap( recMem, REC_CACHEMEM );
safe_aligned_free( m_recBlockAlloc );
recRAM = recROM = recROM1 = NULL;
recConstBuf = NULL;
recRAMCopy = NULL;
safe_aligned_free( recConstBuf );
safe_free( s_pInstCache );
s_nInstCacheSize = 0;
}
static void recResetEE()
{
if (eeCpuExecuting)
{
AtomicExchange( eeRecNeedsReset, true );
return;
}
recResetRaw();
}
void recStep( void )
{
}
@ -744,8 +793,6 @@ static void recCheckExecutionState()
}
}
static bool m_recExecutingCode = false;
static void recExecute()
{
// Implementation Notes:
@ -753,12 +800,14 @@ static void recExecute()
#if PCSX2_SEH
eeRecIsReset = false;
ScopedBool executing(m_recExecutingCode);
ScopedBool executing(eeCpuExecuting);
try {
EnterRecompiledCode();
}
catch( Exception::ExitCpuExecute& ) { }
catch( Exception::ExitCpuExecute& )
{
}
#else
@ -816,18 +865,8 @@ void R5900::Dynarec::OpcodeImpl::recBREAK( void )
//branch = 2;
}
// Clears the recLUT table so that all blocks are mapped to the JIT recompiler by default.
static __ri void ClearRecLUT(BASEBLOCK* base, int count)
{
for (int i = 0; i < count; i++)
base[i].SetFnptr((uptr)JITCompile);
}
void recClear(u32 addr, u32 size)
{
BASEBLOCKEX* pexblock;
BASEBLOCK* pblock;
// necessary since recompiler doesn't call femms/emms
#ifdef _MSC_VER
__asm emms;
@ -846,14 +885,14 @@ void recClear(u32 addr, u32 size)
u32 lowerextent = (u32)-1, upperextent = 0, ceiling = (u32)-1;
pexblock = recBlocks[blockidx + 1];
BASEBLOCKEX* pexblock = recBlocks[blockidx + 1];
if (pexblock)
ceiling = pexblock->startpc;
while (pexblock = recBlocks[blockidx]) {
u32 blockstart = pexblock->startpc;
u32 blockend = pexblock->startpc + pexblock->size * 4;
pblock = PC_GETBLOCK(blockstart);
BASEBLOCK* pblock = PC_GETBLOCK(blockstart);
if (pblock == s_pCurBlock) {
blockidx--;
@ -889,7 +928,7 @@ void recClear(u32 addr, u32 size)
}
if (upperextent > lowerextent)
ClearRecLUT(PC_GETBLOCK(lowerextent), (upperextent - lowerextent) / 4);
ClearRecLUT(PC_GETBLOCK(lowerextent), upperextent - lowerextent);
}
@ -1354,17 +1393,22 @@ static void __fastcall recRecompile( const u32 startpc )
pxAssume( startpc );
// if recPtr reached the mem limit reset whole mem
if ( ( (uptr)recPtr - (uptr)recMem ) >= REC_CACHEMEM-0x40000 || dumplog == 0xffffffff) {
recResetEE();
if (recPtr >= (recMem->GetPtrEnd() - _64kb)) {
AtomicExchange( eeRecNeedsReset, true );
}
if ( (recConstBufPtr - recConstBuf) >= RECCONSTBUF_SIZE - 64 ) {
else if ((recConstBufPtr - recConstBuf) >= RECCONSTBUF_SIZE - 64) {
Console.WriteLn("EE recompiler stack reset");
recResetEE();
AtomicExchange( eeRecNeedsReset, true );
}
if (eeRecNeedsReset) recResetRaw();
xSetPtr( recPtr );
recPtr = xGetAlignedCallTarget();
if (0x8000d618 == startpc)
DbgCon.WriteLn("Compiling block @ 0x%08x", startpc);
s_pCurBlock = PC_GETBLOCK(startpc);
pxAssert(s_pCurBlock->GetFnptr() == (uptr)JITCompile
@ -1764,7 +1808,7 @@ StartRecomp:
pxAssert( (pc-startpc)>>2 <= 0xffff );
s_pCurBlockEx->size = (pc-startpc)>>2;
if (HWADDR(pc) <= Ps2MemSize::Base) {
if (HWADDR(pc) <= Ps2MemSize::MainRam) {
BASEBLOCKEX *oldBlock;
int i;
@ -1774,10 +1818,12 @@ StartRecomp:
continue;
if (oldBlock->startpc >= HWADDR(pc))
continue;
if (oldBlock->startpc + oldBlock->size * 4 <= HWADDR(startpc))
if ((oldBlock->startpc + oldBlock->size * 4) <= HWADDR(startpc))
break;
if (memcmp(&recRAMCopy[oldBlock->startpc / 4], PSM(oldBlock->startpc),
oldBlock->size * 4)) {
if (memcmp(&(*recRAMCopy)[oldBlock->startpc / 4], PSM(oldBlock->startpc),
oldBlock->size * 4))
{
recClear(startpc, (pc - startpc) / 4);
s_pCurBlockEx = recBlocks.Get(HWADDR(startpc));
pxAssert(s_pCurBlockEx->startpc == HWADDR(startpc));
@ -1785,7 +1831,7 @@ StartRecomp:
}
}
memcpy_fast(&recRAMCopy[HWADDR(startpc) / 4], PSM(startpc), pc - startpc);
memcpy_fast(&(*recRAMCopy)[HWADDR(startpc) / 4], PSM(startpc), pc - startpc);
}
s_pCurBlock->SetFnptr((uptr)recPtr);
@ -1836,11 +1882,11 @@ StartRecomp:
}
}
pxAssert( xGetPtr() < recMem+REC_CACHEMEM );
pxAssert( xGetPtr() < recMem->GetPtrEnd() );
pxAssert( recConstBufPtr < recConstBuf + RECCONSTBUF_SIZE );
pxAssert( x86FpuState == 0 );
pxAssert(xGetPtr() - recPtr < 0x10000);
pxAssert(xGetPtr() - recPtr < _64kb);
s_pCurBlockEx->x86size = xGetPtr() - recPtr;
recPtr = xGetPtr();
@ -1859,7 +1905,7 @@ static void recThrowException( const BaseR5900Exception& ex )
#if PCSX2_SEH
ex.Rethrow();
#else
if (!m_recExecutingCode) ex.Rethrow();
if (!eeCpuExecuting) ex.Rethrow();
m_cpuException = ex.Clone();
recExitExecution();
#endif
@ -1870,15 +1916,25 @@ static void recThrowException( const BaseException& ex )
#if PCSX2_SEH
ex.Rethrow();
#else
if (!m_recExecutingCode) ex.Rethrow();
if (!eeCpuExecuting) ex.Rethrow();
m_Exception = ex.Clone();
recExitExecution();
#endif
}
static void recSetCacheReserve( uint reserveInMegs )
{
m_ConfiguredCacheReserve = reserveInMegs;
}
static uint recGetCacheReserve()
{
return m_ConfiguredCacheReserve;
}
R5900cpu recCpu =
{
recAlloc,
recReserve,
recShutdown,
recResetEE,
@ -1889,4 +1945,7 @@ R5900cpu recCpu =
recThrowException,
recThrowException,
recClear,
recGetCacheReserve,
recSetCacheReserve,
};

View File

@ -287,7 +287,7 @@ void vtlb_dynarec_init()
hasBeenCalled = true;
// In case init gets called multiple times:
HostSys::MemProtectStatic( m_IndirectDispatchers, Protect_ReadWrite, false );
HostSys::MemProtectStatic( m_IndirectDispatchers, PageAccess_ReadWrite() );
// clear the buffer to 0xcc (easier debugging).
memset_8<0xcc,0x1000>( m_IndirectDispatchers );
@ -309,7 +309,7 @@ void vtlb_dynarec_init()
}
}
HostSys::MemProtectStatic( m_IndirectDispatchers, Protect_ReadOnly, true );
HostSys::MemProtectStatic( m_IndirectDispatchers, PageAccess_ExecOnly() );
}
//////////////////////////////////////////////////////////////////////////////////////////

View File

@ -18,6 +18,7 @@
#include "PrecompiledHeader.h"
#include "Common.h"
#include "microVU.h"
#include "System/RecTypes.h"
// Include all the *.inl files (Needed because C++ sucks with templates and *.cpp files)
#include "microVU_Clamp.inl"
@ -80,8 +81,20 @@ const __aligned(32) mVU_Globals mVUglob = {
static __fi void mVUthrowHardwareDeficiency(const wxChar* extFail, int vuIndex) {
throw Exception::HardwareDeficiency()
.SetDiagMsg(wxsFormat(L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail))
.SetUserMsg(wxsFormat(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail ));
.SetDiagMsg(pxsFmt(L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail))
.SetUserMsg(pxsFmt(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail ));
}
void microVU::reserveCache()
{
cache_reserve = new RecompiledCodeReserve( pxsFmt("Micro VU%u Recompiler Cache", index) );
cache_reserve->SetProfilerName( pxsFmt("mVU%urec", index) );
cache = index ?
(u8*)cache_reserve->Reserve( cacheSize * _1mb, HostMemoryMap::mVU1rec ) :
(u8*)cache_reserve->Reserve( cacheSize * _1mb, HostMemoryMap::mVU0rec );
cache_reserve->ThrowIfNotOk();
}
// Only run this once per VU! ;)
@ -99,22 +112,14 @@ void microVU::init(uint vuIndex) {
microMemSize = (index ? 0x4000 : 0x1000);
progSize = (index ? 0x4000 : 0x1000) / 4;
progMemMask = progSize-1;
dispCache = NULL;
cache = NULL;
cacheSize = mVUcacheSize;
regAlloc = new microRegAlloc(index);
for (u32 i = 0; i < (progSize / 2); i++) {
prog.prog[i] = new deque<microProgram*>();
}
reserveCache();
dispCache = SysMmapEx(0, mVUdispCacheSize, 0, (index ? "Micro VU1 Dispatcher" : "Micro VU0 Dispatcher"));
if (!dispCache) throw Exception::OutOfMemory( index ? L"Micro VU1 Dispatcher" : L"Micro VU0 Dispatcher" );
memset(dispCache, 0xcc, mVUdispCacheSize);
// Allocates rec-cache and calls mVUreset()
mVUresizeCache(this, cacheSize + mVUcacheSafeZone);
//if (vuIndex) gen_memcpy_vibes();
regAlloc = new microRegAlloc(index);
}
// Resets Rec Data
@ -123,16 +128,12 @@ void microVU::reset() {
x86SetPtr(dispCache);
mVUdispatcherA(this);
mVUdispatcherB(this);
mVUemitSearch();
mVUemitSearch();
// Clear All Program Data
//memset(&prog, 0, sizeof(prog));
memset(&prog.lpState, 0, sizeof(prog.lpState));
if (IsDevBuild) { // Release builds shouldn't need this
memset(cache, 0xcc, cacheSize);
}
// Program Variables
prog.cleared = 1;
prog.isSame = -1;
@ -144,9 +145,15 @@ void microVU::reset() {
u8* z = cache;
prog.x86start = z;
prog.x86ptr = z;
prog.x86end = (u8*)((uptr)z + (uptr)(cacheSize - mVUcacheSafeZone)); // "Safe Zone"
prog.x86end = z + ((cacheSize - mVUcacheSafeZone) * _1mb);
for (u32 i = 0; i < (progSize / 2); i++) {
if (!prog.prog[i])
{
prog.prog[i] = new deque<microProgram*>();
continue;
}
deque<microProgram*>::iterator it(prog.prog[i]->begin());
for ( ; it != prog.prog[i]->end(); ++it) {
if (index) mVUdeleteProg<1>(it[0]);
@ -161,11 +168,13 @@ void microVU::reset() {
// Free Allocated Resources
void microVU::close() {
if (dispCache) { HostSys::Munmap(dispCache, mVUdispCacheSize); dispCache = NULL; }
if (cache) { HostSys::Munmap(cache, cacheSize); cache = NULL; }
safe_delete(cache_reserve);
SafeSysMunmap(dispCache, mVUdispCacheSize);
// Delete Programs and Block Managers
for (u32 i = 0; i < (progSize / 2); i++) {
if (!prog.prog[i]) continue;
deque<microProgram*>::iterator it(prog.prog[i]->begin());
for ( ; it != prog.prog[i]->end(); ++it) {
if (index) mVUdeleteProg<1>(it[0]);
@ -175,35 +184,6 @@ void microVU::close() {
}
}
static void mVUresizeCache(mV, u32 size) {
if (size >= (u32)mVUcacheMaxSize) {
if (mVU->cacheSize==mVUcacheMaxSize) {
// We can't grow the rec any larger, so just reset it and start over.
//(if we don't reset, the rec will eventually crash)
Console.WriteLn(Color_Magenta, "microVU%d: Cannot grow cache, size limit reached! [%dmb]. Resetting rec.", mVU->index, mVU->cacheSize/_1mb);
mVU->reset();
return;
}
size = mVUcacheMaxSize;
}
if (mVU->cache) Console.WriteLn(Color_Green, "microVU%d: Attempting to resize Cache [%dmb]", mVU->index, size/_1mb);
u8* cache = SysMmapEx(0, size, 0, (mVU->index ? "Micro VU1 RecCache" : "Micro VU0 RecCache"));
if(!cache && !mVU->cache) throw Exception::OutOfMemory( wxsFormat( L"Micro VU%d recompiled code cache", mVU->index) );
if(!cache) { Console.Error("microVU%d Error - Cache Resize Failed...", mVU->index); mVU->reset(); return; }
if (mVU->cache) {
HostSys::Munmap(mVU->cache, mVU->cacheSize);
ProfilerTerminateSource(isVU1?"mVU1 Rec":"mVU0 Rec");
}
mVU->cache = cache;
mVU->cacheSize = size;
ProfilerRegisterSource(isVU1?"mVU1 Rec":"mVU0 Rec", mVU->cache, mVU->cacheSize);
mVU->reset();
}
// Clears Block Data in specified range
static __fi void mVUclear(mV, u32 addr, u32 size) {
if (!mVU->prog.cleared) {
@ -323,55 +303,40 @@ _mVUt __fi void* mVUsearchProg(u32 startPC, uptr pState) {
// recMicroVU0 / recMicroVU1
//------------------------------------------------------------------
static u32 mvu0_allocated = 0;
static u32 mvu1_allocated = 0;
recMicroVU0::recMicroVU0() { m_Idx = 0; IsInterpreter = false; }
recMicroVU1::recMicroVU1() { m_Idx = 1; IsInterpreter = false; }
void recMicroVU0::Vsync() throw() { mVUvsyncUpdate(&microVU0); }
void recMicroVU1::Vsync() throw() { mVUvsyncUpdate(&microVU1); }
void recMicroVU0::Allocate() {
if(!m_AllocCount) {
m_AllocCount++;
if (AtomicExchange(mvu0_allocated, 1) == 0)
microVU0.init(0);
}
void recMicroVU0::Reserve() {
if (AtomicExchange(m_Reserved, 1) == 0)
microVU0.init(0);
}
void recMicroVU1::Allocate() {
if(!m_AllocCount) {
m_AllocCount++;
if (AtomicExchange(mvu1_allocated, 1) == 0)
microVU1.init(1);
}
void recMicroVU1::Reserve() {
if (AtomicExchange(m_Reserved, 1) == 0)
microVU1.init(1);
}
void recMicroVU0::Shutdown() throw() {
if (m_AllocCount > 0) {
m_AllocCount--;
if (AtomicExchange(mvu0_allocated, 0) == 1)
microVU0.close();
}
if (AtomicExchange(m_Reserved, 0) == 1)
microVU0.close();
}
void recMicroVU1::Shutdown() throw() {
if (m_AllocCount > 0) {
m_AllocCount--;
if (AtomicExchange(mvu1_allocated, 0) == 1)
microVU1.close();
}
if (AtomicExchange(m_Reserved, 0) == 1)
microVU1.close();
}
void recMicroVU0::Reset() {
if(!pxAssertDev(m_AllocCount, "MicroVU0 CPU Provider has not been allocated prior to reset!")) return;
if(!pxAssertDev(m_Reserved, "MicroVU0 CPU Provider has not been reserved prior to reset!")) return;
microVU0.reset();
}
void recMicroVU1::Reset() {
if(!pxAssertDev(m_AllocCount, "MicroVU1 CPU Provider has not been allocated prior to reset!")) return;
if(!pxAssertDev(m_Reserved, "MicroVU1 CPU Provider has not been reserved prior to reset!")) return;
microVU1.reset();
}
void recMicroVU0::Execute(u32 cycles) {
pxAssert(mvu0_allocated); // please allocate me first! :|
pxAssert(m_Reserved); // please allocate me first! :|
if(!(VU0.VI[REG_VPU_STAT].UL & 1)) return;
@ -381,17 +346,35 @@ void recMicroVU0::Execute(u32 cycles) {
((mVUrecCall)microVU0.startFunct)(VU0.VI[REG_TPC].UL, cycles);
}
void recMicroVU1::Execute(u32 cycles) {
pxAssert(mvu1_allocated); // please allocate me first! :|
pxAssert(m_Reserved); // please allocate me first! :|
if(!(VU0.VI[REG_VPU_STAT].UL & 0x100)) return;
((mVUrecCall)microVU1.startFunct)(VU1.VI[REG_TPC].UL, vu1RunCycles);
}
void recMicroVU0::Clear(u32 addr, u32 size) {
pxAssert(mvu0_allocated); // please allocate me first! :|
pxAssert(m_Reserved); // please allocate me first! :|
mVUclear(&microVU0, addr, 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);
}
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 "R5900OpcodeTables.h"
#include "x86emitter/x86emitter.h"
#include "SamplProf.h"
#include "microVU_Misc.h"
#include "microVU_IR.h"
@ -150,11 +149,8 @@ struct microProgManager {
microRegInfo lpState; // Pipeline state from where program left off (useful for continuing execution)
};
#define mVUdispCacheSize (0x1000) // Dispatcher Cache Size
#define mVUcacheSize ((index) ? (_1mb * 17) : (_1mb * 7)) // Initial Size (Excluding Safe-Zone)
#define mVUcacheMaxSize ((mVU->index) ? (_1mb * 100) : (_1mb * 50)) // Max Size allowed to grow to
#define mVUcacheGrowBy ((mVU->index) ? (_1mb * 15) : (_1mb * 10)) // Grows by this amount
#define mVUcacheSafeZone ((index) ? (_1mb * 3) : (_1mb * 3)) // Safe-Zone for last program
static const uint mVUdispCacheSize = __pagesize; // Dispatcher Cache Size (in bytes)
static const uint mVUcacheSafeZone = 3; // Safe-Zone for program recompilation (in megabytes)
struct microVU {
@ -171,11 +167,13 @@ struct microVU {
u32 progMemMask; // VU Micro Memory Size (in u32's)
u32 cacheSize; // VU Cache Size
microProgManager prog; // Micro Program Data
microProgManager prog; // Micro Program Data
ScopedPtr<microRegAlloc> regAlloc; // Reg Alloc Class
ScopedPtr<AsciiFile> logFile; // Log File Pointer
u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to)
RecompiledCodeReserve* cache_reserve;
u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to)
u8* dispCache; // Dispatchers Cache (where startFunct and exitFunct are written to)
u8* startFunct; // Ptr Function to the Start code for recompiled programs
u8* exitFunct; // Ptr Function to the Exit code for recompiled programs
@ -224,7 +222,17 @@ struct microVU {
pxAssumeDev((prog.IRinfo.curPC & 1) == 0, "microVU recompiler: Upper instructions cannot have valid branch addresses.");
return (((prog.IRinfo.curPC + 4) + (Imm11() * 2)) & progMemMask) * 4;
}
microVU()
{
cacheSize = 64;
cache = NULL;
dispCache = NULL;
startFunct = NULL;
exitFunct = NULL;
}
void reserveCache();
void init(uint vuIndex);
void reset();
void close();
@ -239,7 +247,6 @@ int mVUdebugNow = 0;
// Main Functions
static void mVUclear(mV, u32, u32);
static void mVUresizeCache(mV, u32);
static void* mVUblockFetch(microVU* mVU, u32 startPC, uptr pState);
_mVUt extern void* __fastcall mVUcompileJIT(u32 startPC, uptr pState);

View File

@ -92,7 +92,7 @@ void mVUdispatcherB(mV) {
xRET();
mVUcacheCheck(x86Ptr, mVU->dispCache, mVUdispCacheSize);
pxAssertDev(xGetPtr() < (mVU->dispCache + mVUdispCacheSize), "microVU: Dispatcher generation exceeded reserved cache area!");
}
//------------------------------------------------------------------
@ -121,8 +121,14 @@ _mVUt void mVUcleanUp() {
//mVUprint("microVU: Program exited successfully!");
//mVUprint("microVU: VF0 = {%x,%x,%x,%x}", mVU->regs().VF[0].UL[0], mVU->regs().VF[0].UL[1], mVU->regs().VF[0].UL[2], mVU->regs().VF[0].UL[3]);
//mVUprint("microVU: VI0 = %x", mVU->regs().VI[0].UL);
mVU->prog.x86ptr = x86Ptr;
mVUcacheCheck(x86Ptr, mVU->prog.x86start, (uptr)(mVU->prog.x86end - mVU->prog.x86start));
if ((xGetPtr() < mVU->prog.x86start) || (xGetPtr() >= mVU->prog.x86end)) {
Console.WriteLn(vuIndex ? Color_Orange : Color_Magenta, "microVU%d: Program cache limit reached.", mVU->index);
mVU->reset();
}
mVU->cycles = mVU->totalCycles - mVU->cycles;
mVU->regs().cycle += mVU->cycles;
cpuRegs.cycle += ((mVU->cycles < 3000) ? mVU->cycles : 3000) * EmuConfig.Speedhacks.VUCycleSteal;

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

View File

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

View File

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

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};
void dVifReset(int idx) {
// If the VIF cache is greater than 12mb, then it's due for a complete reset back
// down to a reasonable starting point of 4mb.
if( nVif[idx].vifCache && (nVif[idx].vifCache->getAllocSize() > _1mb*12) )
safe_delete(nVif[idx].vifCache);
void dVifReserve(int idx)
{
if (!nVif[idx].recReserve)
nVif[idx].recReserve = new RecompiledCodeReserve(pxsFmt(L"VIF%u Unpack Recompiler Cache", idx));
if( !nVif[idx].vifCache )
nVif[idx].vifCache = new BlockBuffer(_1mb*4);
else
nVif[idx].vifCache->clear();
nVif[idx].recReserve->Reserve( nVif[idx].recReserveSizeMB * _1mb, idx ? HostMemoryMap::VIF1rec : HostMemoryMap::VIF0rec );
}
void dVifReset(int idx) {
if( !nVif[idx].vifBlocks )
nVif[idx].vifBlocks = new HashBucket<_tParams>();
else
nVif[idx].vifBlocks->clear();
nVif[idx].numBlocks = 0;
nVif[idx].recPtr = nVif[idx].vifCache->getBlock();
nVif[idx].recEnd = &nVif[idx].recPtr[nVif[idx].vifCache->getAllocSize()-(_1mb/4)]; // .25mb Safe Zone
nVif[idx].recReserve->Reset();
nVif[idx].numBlocks = 0;
nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr();
}
void dVifClose(int idx) {
nVif[idx].numBlocks = 0;
safe_delete(nVif[idx].vifCache);
nVif[idx].recReserve->Reset();
safe_delete(nVif[idx].vifBlocks);
}
void dVifRelease(int idx) {
safe_delete(nVif[idx].recReserve);
}
VifUnpackSSE_Dynarec::VifUnpackSSE_Dynarec(const nVifStruct& vif_, const nVifBlock& vifBlock_)
: v(vif_)
, vB(vifBlock_)
@ -223,11 +226,10 @@ _vifT static __fi u8* dVifsetVUptr(uint cl, uint wl, bool isFill) {
// [TODO] : Finish implementing support for VIF's growable recBlocks buffer. Currently
// it clears the buffer only.
static __fi void dVifRecLimit(int idx) {
if (nVif[idx].recPtr > nVif[idx].recEnd) {
DevCon.WriteLn("nVif Rec - Out of Rec Cache! [%x > %x]", nVif[idx].recPtr, nVif[idx].recEnd);
nVif[idx].vifBlocks->clear();
nVif[idx].recPtr = nVif[idx].vifCache->getBlock();
nVif[idx].recEnd = &nVif[idx].recPtr[nVif[idx].vifCache->getAllocSize()-(_1mb/4)]; // .25mb Safe Zone
if (nVif[idx].recWritePtr > (nVif[idx].recReserve->GetPtrEnd() - _256kb)) {
DevCon.WriteLn("nVif Recompiler Cache Reset! [0x%08x > 0x%08x]", nVif[idx].recWritePtr, nVif[idx].recReserve->GetPtrEnd());
nVif[idx].recReserve->Reset();
nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr();
}
}
@ -277,11 +279,11 @@ _vifT __fi void dVifUnpack(const u8* data, bool isFill) {
if (dVifExecuteUnpack<idx>(data, isFill)) return;
xSetPtr(v.recPtr);
xSetPtr(v.recWritePtr);
_vBlock.startPtr = (uptr)xGetAlignedCallTarget();
v.vifBlocks->add(_vBlock);
VifUnpackSSE_Dynarec( v, _vBlock ).CompileRoutine();
nVif[idx].recPtr = xGetPtr();
nVif[idx].recWritePtr = xGetPtr();
// [TODO] : Ideally we should test recompile buffer limits prior to each instruction,
// which would be safer and more memory efficient than using an 0.25 meg recEnd marker.

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

View File

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

View File

@ -35,9 +35,9 @@
#include "R5900.h"
#include "iR5900.h"
#include "System/RecTypes.h"
#include "sVU_zerorec.h"
#include "SamplProf.h"
#include "NakedAsm.h"
#include "AppConfig.h"
@ -72,7 +72,7 @@ extern void iDumpVU1Registers();
#define SUPERVU_CHECKCONDITION 0 // has to be 0!!
#define VU_EXESIZE 0x00800000
static const uint sVU_EXESIZE = _8mb;
#define _Imm11_ (s32)( (vucode & 0x400) ? (0xfffffc00 | (vucode & 0x3ff)) : (vucode & 0x3ff) )
#define _UImm11_ (s32)(vucode & 0x7ff)
@ -90,7 +90,9 @@ static const u32 PWaitTimes[] = { 53, 43, 28, 23, 17, 11, 10 };
static u32 s_vuInfo; // info passed into rec insts
static const u32 s_MemSize[2] = {VU0_MEMSIZE, VU1_MEMSIZE};
static u8* s_recVUMem = NULL, *s_recVUPtr = NULL;
//static u8* s_recVUMem = NULL, *s_recVUPtr = NULL;
static RecompiledCodeReserve* s_recVUMem[2] = { NULL, NULL };
static u8* s_recVUPtr[2] = { NULL, NULL };
// tables which are defined at the bottom of this massive file.
extern void (*recVU_UPPER_OPCODE[64])(VURegs* VU, s32 info);
@ -315,9 +317,11 @@ VuBaseBlock::VuBaseBlock()
static list<VuFunctionHeader*> s_listVUHeaders[2];
static list<VuFunctionHeader*>* s_plistCachedHeaders[2] = {NULL, NULL};
static VuFunctionHeader** recVUHeaders[2] = {NULL, NULL};
static VuBlockHeader* recVUBlocks[2] = {NULL, NULL};
static u8* recVUStack = NULL, *recVUStackPtr = NULL;
static VuFunctionHeader** recVUHeaders[2] = { NULL, NULL };
static VuBlockHeader* recVUBlocks[2] = { NULL, NULL };
static u8* recVUStack[2] = { NULL, NULL };
static u8* recVUStackPtr[2] = { NULL, NULL };
static vector<_x86regs> s_vecRegArray(128);
static VURegs* VU = NULL;
@ -343,47 +347,23 @@ static void SuperVURecompile();
// allocate VU resources
static void SuperVUAlloc(int vuindex)
{
// The old -1 crap has been depreciated on this function. Please
// specify either 0 or 1, thanks.
pxAssert(vuindex >= 0);
if (s_recVUMem[vuindex]) return;
s_recVUMem[vuindex] = new RecompiledCodeReserve( pxsFmt("SuperVU%u Recompiler Cache", vuindex), 0 );
s_recVUMem[vuindex]->Reserve( sVU_EXESIZE, vuindex ? HostMemoryMap::sVU1rec : HostMemoryMap::sVU0rec, _256mb );
s_recVUMem[vuindex]->SetProfilerName(pxsFmt("sVU%urec",vuindex));
// upper 4 bits must be zero!
if (s_recVUMem == NULL)
if (!s_recVUMem[vuindex]->IsOk())
{
// upper 4 bits must be zero!
// Changed "first try base" to 0xf1e0000, since 0x0c000000 liked to fail a lot. (cottonvibes)
s_recVUMem = SysMmapEx(0xf1e0000, VU_EXESIZE, 0x10000000, "SuperVUAlloc");
// Try again at some other random memory location... whatever. >_<
if( s_recVUMem == NULL )
s_recVUMem = SysMmapEx(0xc2b0000, VU_EXESIZE, 0x10000000, "SuperVUAlloc");
if (s_recVUMem == NULL)
{
throw Exception::VirtualMemoryMapConflict()
.SetDiagMsg(wxsFormat( L"SuperVU failed to allocate virtual memory below 256MB." ))
.SetUserMsg(pxE( ".Error:superVU:VirtualMemoryAlloc",
L"Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory "
L"ranges required, and will not be available for use. This is not a critical error, since "
L"the sVU rec is obsolete, and you should use microVU instead anyway. :)"
));
}
ProfilerRegisterSource("sVU Rec", s_recVUMem, VU_EXESIZE);
if (recVUStack == NULL) recVUStack = new u8[SUPERVU_STACKSIZE * 4];
}
if (vuindex >= 0)
{
pxAssert(s_recVUMem != NULL);
if (recVUHeaders[vuindex] == NULL)
recVUHeaders[vuindex] = new VuFunctionHeader* [s_MemSize[vuindex] / 8];
if (recVUBlocks[vuindex] == NULL)
recVUBlocks[vuindex] = new VuBlockHeader[s_MemSize[vuindex] / 8];
if (s_plistCachedHeaders[vuindex] == NULL)
s_plistCachedHeaders[vuindex] = new list<VuFunctionHeader*>[s_MemSize[vuindex] / 8];
safe_delete(s_recVUMem[vuindex]);
throw Exception::VirtualMemoryMapConflict( s_recVUMem[vuindex]->GetName() )
.SetDiagMsg(pxsFmt( L"SuperVU failed to allocate virtual memory below 256MB." ))
.SetUserMsg(pxE( ".Error:superVU:VirtualMemoryAlloc",
L"Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory "
L"ranges required, and will not be available for use. This is not a critical error, since "
L"the sVU rec is obsolete, and you should use microVU instead anyway. :)"
));
}
}
@ -416,72 +396,64 @@ void DestroyVUHeaders(int vuindex)
// destroy VU resources
void SuperVUDestroy(int vuindex)
{
list<VuFunctionHeader*>::iterator it;
pxAssumeDev(vuindex >= 0 && vuindex <= 2, "Invalid VU index parameter!");
if (vuindex < 0)
{
SuperVUDestroy(0);
SuperVUDestroy(1);
ProfilerTerminateSource("VURec");
SafeSysMunmap(s_recVUMem, VU_EXESIZE);
safe_delete_array(recVUStack);
}
else
{
safe_delete_array(recVUHeaders[vuindex]);
safe_delete_array(recVUBlocks[vuindex]);
safe_delete_array(recVUHeaders[vuindex]);
safe_delete_array(recVUBlocks[vuindex]);
if (s_plistCachedHeaders[vuindex] != NULL)
if (s_plistCachedHeaders[vuindex] != NULL)
{
for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j)
{
for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j)
{
DestroyCachedHeaders(vuindex, j);
}
safe_delete_array(s_plistCachedHeaders[vuindex]);
DestroyCachedHeaders(vuindex, j);
}
DestroyVUHeaders(vuindex);
safe_delete_array(s_plistCachedHeaders[vuindex]);
}
DestroyVUHeaders(vuindex);
safe_delete(s_recVUMem[vuindex]);
safe_delete_array(recVUStack[vuindex]);
}
// reset VU
void SuperVUReset(int vuindex)
{
pxAssumeDev(vuindex >= 0 && vuindex <= 2, "Invalid VU index parameter!");
#ifdef PCSX2_DEBUG
s_vucount = 0;
#endif
if (s_recVUMem == NULL)
return;
DevCon.WriteLn("SuperVU%d: Resetting function and block lists.", vuindex);
//pxAssume( s_recVUMem != NULL );
if (recVUHeaders[vuindex] == NULL)
recVUHeaders[vuindex] = new VuFunctionHeader* [s_MemSize[vuindex] / 8];
if (recVUBlocks[vuindex] == NULL)
recVUBlocks[vuindex] = new VuBlockHeader[s_MemSize[vuindex] / 8];
if (s_plistCachedHeaders[vuindex] == NULL)
s_plistCachedHeaders[vuindex] = new std::list<VuFunctionHeader*>[s_MemSize[vuindex] / 8];
if (vuindex < 0)
if (recVUHeaders[vuindex]) memset(recVUHeaders[vuindex], 0, sizeof(VuFunctionHeader*) * (s_MemSize[vuindex] / 8));
if (recVUBlocks[vuindex]) memset(recVUBlocks[vuindex], 0, sizeof(VuBlockHeader) * (s_MemSize[vuindex] / 8));
if (s_plistCachedHeaders[vuindex] != NULL)
{
DbgCon.WriteLn("SuperVU: Resetting recompiler memory and structures.");
// Does this cause problems on VU recompiler resets? It could, if the VU works like
// the EE used to, and actually tries to re-enter the recBlock after issuing a clear. (air)
//memset_8<0xcd, VU_EXESIZE>(s_recVUMem);
memzero_ptr<SUPERVU_STACKSIZE>(recVUStack);
s_recVUPtr = s_recVUMem;
}
else
{
DbgCon.WriteLn("SuperVU [VU%d]: Resetting the recs and junk", vuindex);
if (recVUHeaders[vuindex]) memset(recVUHeaders[vuindex], 0, sizeof(VuFunctionHeader*) * (s_MemSize[vuindex] / 8));
if (recVUBlocks[vuindex]) memset(recVUBlocks[vuindex], 0, sizeof(VuBlockHeader) * (s_MemSize[vuindex] / 8));
if (s_plistCachedHeaders[vuindex] != NULL)
for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j)
{
for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j)
{
DestroyCachedHeaders(vuindex, j);
}
DestroyCachedHeaders(vuindex, j);
}
DestroyVUHeaders(vuindex);
}
DestroyVUHeaders(vuindex);
if (!s_recVUMem[vuindex] || !s_recVUMem[vuindex]->IsOk()) return;
DevCon.WriteLn("SuperVU%u: Resetting recompiler cache.", vuindex);
if (!recVUStack[vuindex]) recVUStack[vuindex] = new u8[SUPERVU_STACKSIZE * 4];
memzero_ptr<SUPERVU_STACKSIZE>(recVUStack[vuindex]);
s_recVUMem[vuindex]->Reset();
s_recVUPtr[vuindex] = *s_recVUMem[vuindex];
}
// clear the block and any joining blocks
@ -847,16 +819,15 @@ void VuBaseBlock::GetInstsAtPc(int instpc, list<VuInstruction*>& listinsts)
static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex)
{
pxAssert(vuindex < 2);
pxAssert(s_recVUPtr != NULL);
pxAssert(s_recVUPtr[vuindex] != NULL);
//Console.WriteLn("svu%c rec: %x", '0'+vuindex, startpc);
// if recPtr reached the mem limit reset whole mem
if (((uptr)s_recVUPtr - (uptr)s_recVUMem) >= VU_EXESIZE - 0x40000)
if ((s_recVUPtr[vuindex] < s_recVUMem[vuindex]->GetPtr()) || (s_recVUPtr[vuindex] >= s_recVUMem[vuindex]->GetPtrEnd() - _256kb))
{
//Console.WriteLn("SuperVU reset mem");
Console.WriteLn("SuperVU%u: Recompiler cache reset...", vuindex);
SuperVUReset(0);
SuperVUReset(1);
SuperVUReset(-1);
if (s_TotalVUCycles > 0)
{
// already executing, so return NULL
@ -912,12 +883,12 @@ static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex)
#endif
// code generation
x86SetPtr(s_recVUPtr);
xSetPtr(s_recVUPtr[vuindex]);
branch = 0;
SuperVURecompile();
s_recVUPtr = x86Ptr;
s_recVUPtr[vuindex] = xGetPtr();
// set the function's range
VuFunctionHeader::RANGE r;
@ -947,7 +918,7 @@ static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex)
}
s_listBlocks.clear();
pxAssert(s_recVUPtr < s_recVUMem + VU_EXESIZE);
pxAssertDev(s_recVUPtr[vuindex] < s_recVUMem[vuindex]->GetPtrEnd(), "SuperVU recompiler cache exceeded! (possible memory corruption)");
return s_pFnHeader;
}
@ -2697,18 +2668,18 @@ void SuperVUFlush(int p, int wait)
// executed only once per program
static u32* SuperVUStaticAlloc(u32 size)
{
pxAssert(recVUStackPtr + size <= recVUStack + SUPERVU_STACKSIZE);
pxAssert(recVUStackPtr[s_vu] + size <= recVUStack[s_vu] + SUPERVU_STACKSIZE);
// always zero
if (size == 4) *(u32*)recVUStackPtr = 0;
else memset(recVUStackPtr, 0, size);
recVUStackPtr += size;
return (u32*)(recVUStackPtr - size);
if (size == 4) *(u32*)recVUStackPtr[s_vu] = 0;
else memset(recVUStackPtr[s_vu], 0, size);
recVUStackPtr[s_vu] += size;
return (u32*)(recVUStackPtr[s_vu] - size);
}
static void SuperVURecompile()
{
// save cpu state
recVUStackPtr = recVUStack;
recVUStackPtr[s_vu] = recVUStack[s_vu];
_initXMMregs();
@ -4617,9 +4588,9 @@ recSuperVU0::recSuperVU0()
IsInterpreter = false;
}
void recSuperVU0::Allocate()
void recSuperVU0::Reserve()
{
SuperVUAlloc( 0 );
SuperVUAlloc(0);
}
void recSuperVU0::Shutdown() throw()
@ -4645,6 +4616,15 @@ void recSuperVU0::Clear(u32 Addr, u32 Size)
SuperVUClear(Addr, Size, 0);
}
uint recSuperVU0::GetCacheReserve() const
{
return sVU_EXESIZE / _1mb;
}
void recSuperVU0::SetCacheReserve( uint reserveInMegs ) const
{
//microVU0.cacheSize = reserveInMegs * _1mb;
}
// --------------------------------------------------------------------------------------
// recSuperVU1 Interface
@ -4655,9 +4635,9 @@ recSuperVU1::recSuperVU1()
IsInterpreter = false;
}
void recSuperVU1::Allocate()
void recSuperVU1::Reserve()
{
SuperVUAlloc( 1 );
SuperVUAlloc(1);
}
void recSuperVU1::Shutdown() throw()
@ -4670,6 +4650,16 @@ void recSuperVU1::Reset()
SuperVUReset( 1 );
}
uint recSuperVU1::GetCacheReserve() const
{
return sVU_EXESIZE / _1mb;
}
void recSuperVU1::SetCacheReserve( uint reserveInMegs ) const
{
//microVU0.cacheSize = reserveInMegs * _1mb;
}
#if 0
#include "sVU_Compare.h"
#else

View File

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

View File

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