newHostVM branch: Implemented VM reservation feature for all recompilers.

* SuperVU note: SuperVU recompiler now uses two separate 8mb caches for VU0 and VU1 (needed in order to simplify/saneify the reserve/alloc stages of pcsx2 app startup).
 * Added MemsetFast.inl, which houses SSE intrinsic versions of memset and memzero, for use on aligned data targets.

git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@3975 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-10-27 19:18:46 +00:00
parent bed33749b5
commit 4bee22a4cd
32 changed files with 703 additions and 534 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" />

View File

@ -291,6 +291,10 @@
RelativePath="..\..\src\Utilities\StringHelpers.cpp"
>
</File>
<File
RelativePath="..\..\src\Utilities\VirtualMemory.cpp"
>
</File>
<File
RelativePath="..\..\src\Utilities\vssprintf.cpp"
>
@ -417,6 +421,10 @@
RelativePath="..\..\include\Utilities\MemcpyFast.h"
>
</File>
<File
RelativePath="..\..\include\Utilities\MemsetFast.inl"
>
</File>
<File
RelativePath="..\..\include\Utilities\Path.h"
>

View File

@ -160,7 +160,7 @@ public:
~ScopedBool() throw()
{
m_boolme = false;
*m_boolme = false;
}
};
@ -177,6 +177,19 @@ 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 _64mb = _1mb * 64;
static const s64 _256mb = _1mb * 256;
static const s64 _1gb = _256mb * 4;
// ===========================================================================================
// i18n/Translation Feature Set!
// ===========================================================================================

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

@ -13,6 +13,8 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
// [TODO] Rename this file to VirtualMemory.h !!
#pragma once
// =====================================================================================================
@ -20,8 +22,9 @@
// =====================================================================================================
// 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 "Utilities/EventSource.h"
#include "EventSource.h"
struct PageFaultInfo
{
@ -125,9 +128,11 @@ public:
Free();
}
void* Reserve( uint size, uptr base = 0, uptr upper_bounds = 0 );
void Reset();
void Free();
virtual void* Reserve( uint size, uptr base = 0, uptr upper_bounds = 0 );
virtual void Reset();
virtual void Free();
bool IsOk() const { return m_baseptr != NULL; }
uptr GetReserveSizeInBytes() const { return m_reserved * __pagesize; }
uptr GetReserveSizeInPages() const { return m_reserved; }
@ -155,16 +160,58 @@ protected:
};
// --------------------------------------------------------------------------------------
// RecompiledCodeReserve
// SpatialArrayReserve
// --------------------------------------------------------------------------------------
class RecompiledCodeReserve : public BaseVirtualMemoryReserve
// 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 BaseVirtualMemoryReserve
{
typedef BaseVirtualMemoryReserve __parent;
protected:
public:
RecompiledCodeReserve( const wxString& name, uint defCommit = 0 );
SpatialArrayReserve( const wxString& name, uint defCommit = 0 );
virtual void* Reserve( uint size, uptr base = 0, uptr upper_bounds = 0 );
void OnCommittedBlock( void* block );
void OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled );
// 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.
// Calls to this function prior to initializing the reserve will be ignored (and will
// generate an assertion in debug builds).
SpatialArrayReserve& SetBlockCount( uint blocks );
// Sets the block size via pages (pages are defined by the __pagesize global, which is
// typically 4096).
SpatialArrayReserve& SetBlockSizeInPages( uint bytes );
// This method 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.
uint SetBlockSize( uint bytes );
operator void*() { return m_baseptr; }
operator const void*() const { return m_baseptr; }
@ -190,7 +237,6 @@ extern int SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps);
# error PCSX2 - Unsupported operating system platform.
#endif
extern void InstallSignalHandler();
extern SrcType_PageFault* Source_PageFault;

View File

@ -101,6 +101,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); }
@ -121,7 +122,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

@ -121,6 +121,7 @@ set(UtilitiesSources
ThreadingDialogs.cpp
ThreadTools.cpp
vssprintf.cpp
VirtualMemory.cpp
wxAppWithHelpers.cpp
wxGuiTools.cpp
wxHelpers.cpp
@ -145,7 +146,9 @@ set(UtilitiesHeaders
../../include/Utilities/HashMap.h
../../include/Utilities/lnx_memzero.h
../../include/Utilities/MemcpyFast.h
../../include/Utilities/MemsetFast.h
../../include/Utilities/Path.h
../../include/Utilities/PageFaultSource.h
../../include/Utilities/pxCheckBox.h
../../include/Utilities/pxRadioPanel.h
../../include/Utilities/pxStaticText.h

View File

@ -136,7 +136,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

@ -0,0 +1,203 @@
/* 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"
#include "EventSource.inl"
#include "MemsetFast.inl"
template class EventSource< IEventListener_PageFault >;
SrcType_PageFault* Source_PageFault = NULL;
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 );
}
// --------------------------------------------------------------------------------------
// BaseVirtualMemoryReserve (implementations)
// --------------------------------------------------------------------------------------
BaseVirtualMemoryReserve::BaseVirtualMemoryReserve( const wxString& name )
: Name( name )
{
m_commited = 0;
m_reserved = 0;
m_baseptr = NULL;
m_block_size = __pagesize;
m_prot_mode = PageAccess_None();
}
// Parameters:
// 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* BaseVirtualMemoryReserve::Reserve( uint size, uptr base, uptr upper_bounds )
{
if (!pxAssertDev( m_baseptr == NULL, "(VirtualMemoryReserve) Invalid object state; object has already been reserved." ))
return m_baseptr;
m_reserved = (size + __pagesize-4) / __pagesize;
uptr reserved_bytes = m_reserved * __pagesize;
m_baseptr = (void*)HostSys::MmapReserve(base, reserved_bytes);
if (!m_baseptr && (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)))
{
if (base)
{
DevCon.Warning( L"%s: address 0x%08x is unavailable; trying OS-selected address instead.", Name.c_str(), base );
// Let's try again at an OS-picked memory area, and then hope it meets needed
// boundschecking criteria below.
SafeSysMunmap( m_baseptr, reserved_bytes );
m_baseptr = (void*)HostSys::MmapReserve( NULL, 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;
DevCon.WriteLn( Color_Blue, L"%-32s @ 0x%08X -> 0x%08X [%umb]", Name.c_str(),
m_baseptr, (uptr)m_baseptr+reserved_bytes, reserved_bytes / _1mb);
/*if (m_def_commit)
{
const uint camt = m_def_commit * __pagesize;
HostSys::MmapCommit(m_baseptr, camt);
HostSys::MemProtect(m_baseptr, camt, m_prot_mode);
u8* init = (u8*)m_baseptr;
u8* endpos = init + camt;
for( ; init<endpos; init += m_block_size*__pagesize )
OnCommittedBlock(init);
m_commited += m_def_commit * __pagesize;
}*/
return m_baseptr;
}
// Clears all committed blocks, restoring the allocation to a reserve only.
void BaseVirtualMemoryReserve::Reset()
{
if (!m_commited) return;
HostSys::MemProtect(m_baseptr, m_commited*__pagesize, PageAccess_None());
HostSys::MmapReset(m_baseptr, m_commited*__pagesize);
m_commited = 0;
}
void BaseVirtualMemoryReserve::Free()
{
HostSys::Munmap((uptr)m_baseptr, m_reserved*__pagesize);
}
void BaseVirtualMemoryReserve::OnPageFaultEvent(const PageFaultInfo& info, bool& handled)
{
uptr offset = (info.addr - (uptr)m_baseptr) / __pagesize;
if (offset >= m_reserved) return;
try {
if (!m_commited && m_def_commit)
{
const uint camt = m_def_commit * __pagesize;
// first block being committed! Commit the default requested
// amount if its different from the blocksize.
HostSys::MmapCommit(m_baseptr, camt);
HostSys::MemProtect(m_baseptr, camt, m_prot_mode);
u8* init = (u8*)m_baseptr;
u8* endpos = init + camt;
for( ; init<endpos; init += m_block_size*__pagesize )
OnCommittedBlock(init);
m_commited += m_def_commit;
handled = true;
return;
}
void* bleh = (u8*)m_baseptr + (offset * __pagesize);
// Depending on the operating system, one or both of these could fail if the system
// is low on either physical ram or virtual memory.
HostSys::MmapCommit(bleh, m_block_size*__pagesize);
HostSys::MemProtect(bleh, m_block_size*__pagesize, m_prot_mode);
m_commited += m_block_size;
OnCommittedBlock(bleh);
handled = true;
}
catch (Exception::OutOfMemory& ex)
{
OnOutOfMemory( ex, (u8*)m_baseptr + (offset * __pagesize), handled );
}
#ifndef __WXMSW__
// 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.
// In Linux, however, 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 can't really log it either.
// We can't issue a proper assertion (requires user popup). We can't do jack or shit,
// *unless* its attached to a debugger; then we can, at a bare minimum, trap it.
catch (Exception::BaseException& ex)
{
wxTrap();
handled = false;
}
#endif
}
// --------------------------------------------------------------------------------------
// SpatialArrayReserve (implementations)
// --------------------------------------------------------------------------------------
void* SpatialArrayReserve::Reserve( uint size, uptr base, uptr upper_bounds )
{
return __parent::Reserve( size, base, upper_bounds );
}

View File

@ -91,6 +91,7 @@ wxString PageProtectionMode::ToString() const
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

@ -432,7 +432,7 @@ set(pcsx2SystemSources
# System headers
set(pcsx2SystemHeaders
System/PageFaultSource.h
System/RecTypes.h
System/SysThreads.h)
# Utilities sources

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

@ -367,10 +367,10 @@
<Unit filename="../SysForwardDefs.h" />
<Unit filename="../System.cpp" />
<Unit filename="../System.h" />
<Unit filename="../System/PageFaultSource.h" />
<Unit filename="../System/SysCoreThread.cpp" />
<Unit filename="../System/SysThreadBase.cpp" />
<Unit filename="../System/SysThreads.h" />
<Unit filename="../System/RecTypes.h" />
<Unit filename="../Utilities/AsciiFile.h" />
<Unit filename="../Utilities/FileUtils.cpp" />
<Unit filename="../Utilities/folderdesc.txt" />

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

View File

@ -102,20 +102,9 @@ typedef int BOOL;
typedef void FnType_Void();
typedef FnType_Void* Fnptr_Void;
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 _64mb = _1mb * 64;
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

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

View File

@ -16,192 +16,24 @@
#include "PrecompiledHeader.h"
#include "Common.h"
#include "IopCommon.h"
#include "System/PageFaultSource.h"
#include "Utilities/EventSource.inl"
#include "VUmicro.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"
#include "System/RecTypes.h"
#include "Utilities/MemsetFast.inl"
extern void closeNewVif(int idx);
extern void resetNewVif(int idx);
template class EventSource< IEventListener_PageFault >;
SrcType_PageFault* Source_PageFault = NULL;
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 );
}
// --------------------------------------------------------------------------------------
// BaseVirtualMemoryReserve (implementations)
// RecompiledCodeReserve (implementations)
// --------------------------------------------------------------------------------------
BaseVirtualMemoryReserve::BaseVirtualMemoryReserve( const wxString& name )
: Name( name )
{
m_commited = 0;
m_reserved = 0;
m_baseptr = NULL;
m_block_size = __pagesize;
m_prot_mode = PageAccess_None();
}
// Parameters:
// 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* BaseVirtualMemoryReserve::Reserve( uint size, uptr base, uptr upper_bounds )
{
if (!pxAssertDev( m_baseptr == NULL, "(VirtualMemoryReserve) Invalid object state; object has already been reserved." ))
return m_baseptr;
m_reserved = (size + __pagesize-4) / __pagesize;
uptr reserved_bytes = m_reserved * __pagesize;
m_baseptr = (void*)HostSys::MmapReserve(base, reserved_bytes);
if (!m_baseptr && (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)))
{
if (base)
{
DevCon.Warning( L"%s default address 0x%08x is unavailable; falling back on OS-default address.", Name.c_str(), base );
// Let's try again at an OS-picked memory area, and then hope it meets needed
// boundschecking criteria below.
SafeSysMunmap( m_baseptr, reserved_bytes );
m_baseptr = (void*)HostSys::MmapReserve( NULL, 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;
DevCon.WriteLn( Color_Blue, L"%s mapped @ 0x%08X -> 0x%08X [%umb]", Name.c_str(),
m_baseptr, (uptr)m_baseptr+reserved_bytes, reserved_bytes / _1mb);
/*if (m_def_commit)
{
const uint camt = m_def_commit * __pagesize;
HostSys::MmapCommit(m_baseptr, camt);
HostSys::MemProtect(m_baseptr, camt, m_prot_mode);
u8* init = (u8*)m_baseptr;
u8* endpos = init + camt;
for( ; init<endpos; init += m_block_size*__pagesize )
OnCommittedBlock(init);
m_commited += m_def_commit * __pagesize;
}*/
return m_baseptr;
}
// Clears all committed blocks, restoring the allocation to a reserve only.
void BaseVirtualMemoryReserve::Reset()
{
if (!m_commited) return;
HostSys::MemProtect(m_baseptr, m_commited*__pagesize, PageAccess_None());
HostSys::MmapReset(m_baseptr, m_commited*__pagesize);
m_commited = 0;
}
void BaseVirtualMemoryReserve::Free()
{
HostSys::Munmap((uptr)m_baseptr, m_reserved*__pagesize);
}
void BaseVirtualMemoryReserve::OnPageFaultEvent(const PageFaultInfo& info, bool& handled)
{
uptr offset = (info.addr - (uptr)m_baseptr) / __pagesize;
if (offset >= m_reserved) return;
try {
if (!m_commited && m_def_commit)
{
const uint camt = m_def_commit * __pagesize;
// first block being committed! Commit the default requested
// amount if its different from the blocksize.
HostSys::MmapCommit(m_baseptr, camt);
HostSys::MemProtect(m_baseptr, camt, m_prot_mode);
u8* init = (u8*)m_baseptr;
u8* endpos = init + camt;
for( ; init<endpos; init += m_block_size*__pagesize )
OnCommittedBlock(init);
m_commited += m_def_commit * __pagesize;
handled = true;
return;
}
void* bleh = (u8*)m_baseptr + (offset * __pagesize);
// Depending on the operating system, one or both of these could fail if the system
// is low on either physical ram or virtual memory.
HostSys::MmapCommit(bleh, m_block_size*__pagesize);
HostSys::MemProtect(bleh, m_block_size*__pagesize, m_prot_mode);
m_commited += m_block_size;
OnCommittedBlock(bleh);
handled = true;
}
catch (Exception::OutOfMemory& ex)
{
OnOutOfMemory( ex, (u8*)m_baseptr + (offset * __pagesize), handled );
}
#ifndef __WXMSW__
// 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.
// In Linux, however, 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 can't really log it either.
// We can't issue a proper assertion (requires user popup). We can't do jack or shit,
// *unless* its attached to a debugger; then we can, at a bare minimum, trap it.
catch (Exception::BaseException& ex)
{
wxTrap();
handled = false;
}
#endif
}
RecompiledCodeReserve::RecompiledCodeReserve( const wxString& name, uint defCommit )
: BaseVirtualMemoryReserve( name )
{
@ -210,46 +42,6 @@ RecompiledCodeReserve::RecompiledCodeReserve( const wxString& name, uint defComm
m_def_commit = defCommit / __pagesize;
}
template< u8 data >
__noinline void memset_sse_a( void* dest, const size_t size )
{
const uint MZFqwc = size / 16;
pxAssert( (size & 0xf) == 0 );
static __aligned16 const u8 loadval[8] = { data,data,data,data,data,data,data,data };
__m128 srcreg = _mm_load_ps( (float*)loadval );
srcreg = _mm_loadh_pi( srcreg, (__m64*)loadval );
float (*destxmm)[4] = (float(*)[4])dest;
#define StoreDestIdx(idx) case idx: _mm_store_ps(&destxmm[idx-1][0], srcreg)
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);
}
};
void RecompiledCodeReserve::OnCommittedBlock( void* block )
{
@ -263,23 +55,25 @@ void RecompiledCodeReserve::OnCommittedBlock( void* block )
}
}
void RecompiledCodeReserve::OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled )
void RecompiledCodeReserve::ResetProcessReserves() const
{
// Truncate and reset reserves of all other in-use recompiler caches, as this should
// help free up quite a bit of emergency memory.
//Cpu->SetCacheReserve( (Cpu->GetCacheReserve() * 3) / 2 );
Cpu->Reset();
//CpuVU0->SetCacheReserve( (CpuVU0->GetCacheReserve() * 3) / 2 );
CpuVU0->SetCacheReserve( (CpuVU0->GetCacheReserve() * 3) / 2 );
CpuVU0->Reset();
//CpuVU1->SetCacheReserve( (CpuVU1->GetCacheReserve() * 3) / 2 );
CpuVU1->SetCacheReserve( (CpuVU1->GetCacheReserve() * 3) / 2 );
CpuVU1->Reset();
//psxCpu->SetCacheReserve( (psxCpu->GetCacheReserve() * 3) / 2 );
psxCpu->Reset();
}
// Default behavior for out of memory: the
void RecompiledCodeReserve::OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled )
{
// Since the recompiler is happy writing away to memory, we have to truncate the reserve
// to include the page currently being accessed, and cannot go any smaller. This will
// allow the rec to finish emitting the current block of instructions, detect that it has
@ -293,6 +87,11 @@ void RecompiledCodeReserve::OnOutOfMemory( const Exception::OutOfMemory& ex, voi
try
{
// Truncate and reset reserves of all other in-use recompiler caches, as this should
// help free up quite a bit of emergency memory.
ResetProcessReserves();
uint cusion = std::min<uint>( m_block_size, 4 );
HostSys::MmapCommit((u8*)blockptr, cusion * __pagesize);
HostSys::MemProtect((u8*)blockptr, cusion * __pagesize, m_prot_mode);
@ -442,7 +241,7 @@ CpuInitializer< CpuType >::CpuInitializer()
{
try {
MyCpu = new CpuType();
MyCpu->Allocate();
MyCpu->Reserve();
}
catch( Exception::RuntimeError& ex )
{
@ -461,7 +260,7 @@ CpuInitializer< CpuType >::CpuInitializer()
template< typename CpuType >
CpuInitializer< CpuType >::~CpuInitializer() throw()
{
if( MyCpu )
if (MyCpu)
MyCpu->Shutdown();
}
@ -608,11 +407,6 @@ SysCpuProviderPack::SysCpuProviderPack()
}
// 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(); }
@ -633,9 +427,6 @@ void SysCpuProviderPack::CleanupMess() throw()
closeNewVif(0);
closeNewVif(1);
// Special SuperVU "complete" terminator (stupid hacky recompiler)
SuperVUDestroy( -1 );
psxRec.Shutdown();
recCpu.Shutdown();
}
@ -695,10 +486,6 @@ 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();

View File

@ -22,8 +22,9 @@
#include "CDVD/CDVDaccess.h"
typedef SafeArray<u8> VmStateBuffer;
class BaseVUmicroCPU;
class BaseVUmicroCPU;
class RecompiledCodeReserve;
// This is a table of default virtual map addresses for ps2vm components. These locations
// are provided and used to assist in debugging and possibly hacking; as it makes it possible
@ -38,8 +39,9 @@ class BaseVUmicroCPU;
namespace HostMemoryMap
{
// superVU is OLD SCHOOL, and it requires its allocation to be in the lower 256mb
// of the virtual memory space. (8mb)
static const uptr sVUrec = 0x0f1e0000;
// of the virtual memory space. (8mb each)
static const uptr sVU0rec = _256mb - (_16mb*2);
static const uptr sVU1rec = _256mb - (_16mb*1);
// PS2 main memory, SPR, and ROMs
static const uptr EEmem = 0x20000000;

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

@ -0,0 +1,46 @@
/* 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. When using this class, care should be take to re-
// implement the provided OnOutOfMemory handler so that it clears other recompiled memory
// reserves that are known to be attached to the process.
//
class RecompiledCodeReserve : public BaseVirtualMemoryReserve
{
protected:
public:
RecompiledCodeReserve( const wxString& name, uint defCommit = 0 );
virtual void OnCommittedBlock( void* block );
virtual void OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled );
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;
};

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__

View File

@ -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,13 +60,13 @@ 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;
@ -80,7 +80,7 @@ public:
return 0;
}
virtual void Allocate()=0;
virtual void Reserve()=0;
virtual void Shutdown()=0;
virtual void Reset()=0;
virtual void Execute(u32 cycles)=0;
@ -96,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;
};
// --------------------------------------------------------------------------------------
@ -157,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
@ -175,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 {}
};
// --------------------------------------------------------------------------------------
@ -196,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
@ -214,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;
};
// --------------------------------------------------------------------------------------
@ -234,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
@ -249,11 +273,14 @@ 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;

View File

@ -459,6 +459,10 @@
RelativePath="..\..\Plugins.h"
>
</File>
<File
RelativePath="..\..\System\RecTypes.h"
>
</File>
<File
RelativePath="..\..\SamplProf.h"
>

View File

@ -18,7 +18,7 @@
#include <winnt.h>
#include "Common.h"
#include "System/PageFaultSource.h"
#include "Utilities/PageFaultSource.h"
int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
{

View File

@ -22,7 +22,7 @@
#include "iR3000A.h"
#include "BaseblockEx.h"
#include "PageFaultSource.h"
#include "System/RecTypes.h"
#include <time.h>
@ -759,8 +759,9 @@ static void recReserve()
{
if (!recMem)
{
recMem = new RecompiledCodeReserve(L"R3000A recompiled code cache", _1mb * 2);
recMem = new RecompiledCodeReserve(L"R3000A Recompiler Cache", _1mb * 2);
recMem->Reserve( _16mb, HostMemoryMap::IOPrec );
ProfilerRegisterSource( "IOP Rec", *recMem, recMem->GetReserveSizeInBytes() );
}
}
@ -790,17 +791,16 @@ static void recAlloc()
if( s_pInstCache == NULL )
throw Exception::OutOfMemory( L"R3000 InstCache." );
ProfilerRegisterSource( "IOP Rec", *recMem, recMem->GetReserveSizeInBytes() );
_DynGen_Dispatchers();
}
void recResetIOP()
{
DevCon.WriteLn( "iR3000A Recompiler reset." );
recAlloc();
recMem->Reset();
DevCon.WriteLn( "iR3000A Recompiler reset." );
iopClearRecLUT((BASEBLOCK*)m_recBlockAlloc,
(((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4)));

View File

@ -21,16 +21,15 @@
#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 "System/PageFaultSource.h"
#include "GS.h"
#include "CDVD/CDVD.h"
#include "Elfheader.h"
@ -562,7 +561,7 @@ static void recReserve()
if ( !x86caps.hasStreamingSIMD2Extensions )
recThrowHardwareDeficiency( L"SSE2" );
recMem = new RecompiledCodeReserve(L"R5900-32 recompiled code cache", _1mb * 4);
recMem = new RecompiledCodeReserve(L"R5900-32 Recompiler Cache", _1mb * 4);
recMem->Reserve( _64mb, HostMemoryMap::EErec );
}
@ -614,6 +613,7 @@ static __aligned16 u8 manual_counter[Ps2MemSize::MainRam >> 12];
static u32 eeRecIsReset = false;
static u32 eeRecNeedsReset = false;
static bool eeRecIsActive = false;
static bool eeCpuExecuting = false;
////////////////////////////////////////////////////
static void recResetRaw()
@ -701,7 +701,7 @@ static void recShutdown()
static void recResetEE()
{
if (eeRecIsActive)
if (eeRecIsActive || eeCpuExecuting)
{
AtomicExchange( eeRecNeedsReset, true );
return;
@ -746,8 +746,6 @@ static void recCheckExecutionState()
}
}
static bool m_recExecutingCode = false;
static void recExecute()
{
// Implementation Notes:
@ -755,12 +753,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
@ -1369,7 +1369,7 @@ static void __fastcall recRecompile( const u32 startpc )
// From here on we need to have EE recompile resets disabled, since to reset
// the rec while we're writing to it typically leads to GPF.
ScopedBool active_scope(eeRecIsActive);
//ScopedBool active_scope(eeRecIsActive);
xSetPtr( recPtr );
recPtr = xGetAlignedCallTarget();
@ -1868,7 +1868,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
@ -1879,7 +1879,7 @@ 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

View File

@ -18,6 +18,7 @@
#include "PrecompiledHeader.h"
#include "Common.h"
#include "microVU.h"
#include "RecTypes.h"
// Include all the *.inl files (Needed because C++ sucks with templates and *.cpp files)
#include "microVU_Clamp.inl"
@ -99,22 +100,22 @@ 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*>();
}
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();
cache_reserve = new RecompiledCodeReserve( pxsFmt("Micro VU%u Recompiler Cache", index) );
cache = index ?
(u8*)cache_reserve->Reserve( cacheSize, HostMemoryMap::mVU1rec ) :
(u8*)cache_reserve->Reserve( cacheSize, HostMemoryMap::mVU0rec );
if(!cache_reserve->IsOk())
throw Exception::VirtualMemoryMapConflict().SetDiagMsg(pxsFmt( L"Micro VU%u Recompiler Cache", index ));
ProfilerRegisterSource (index ? "mVU1 Rec" : "mVU0 Rec", cache, cacheSize);
regAlloc = new microRegAlloc(index);
}
// Resets Rec Data
@ -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);
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,17 @@ 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; }
if (cache_reserve && cache_reserve->IsOk())
{
ProfilerTerminateSource (index ? "mVU1 Rec" : "mVU0 Rec");
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 +188,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(mVU->index ? HostMemoryMap::mVU1rec : HostMemoryMap::mVU0rec, 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 +307,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 +350,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 / _1mb;
}
uint recMicroVU1::GetCacheReserve() const
{
return microVU1.cacheSize / _1mb;
}
void recMicroVU0::SetCacheReserve( uint reserveInMegs ) const
{
microVU0.cacheSize = reserveInMegs * _1mb;
}
void recMicroVU1::SetCacheReserve( uint reserveInMegs ) const
{
microVU1.cacheSize = reserveInMegs * _1mb;
}

View File

@ -150,7 +150,7 @@ struct microProgManager {
microRegInfo lpState; // Pipeline state from where program left off (useful for continuing execution)
};
#define mVUdispCacheSize (0x1000) // Dispatcher Cache Size
#define mVUdispCacheSize (__pagesize) // 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
@ -175,7 +175,9 @@ struct microVU {
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,6 +226,15 @@ 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 = _1mb * 64;
cache = NULL;
dispCache = NULL;
startFunct = NULL;
exitFunct = NULL;
}
void init(uint vuIndex);
void reset();
@ -239,7 +250,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

@ -35,6 +35,7 @@
#include "R5900.h"
#include "iR5900.h"
#include "System/RecTypes.h"
#include "sVU_zerorec.h"
#include "SamplProf.h"
@ -72,7 +73,7 @@ extern void iDumpVU1Registers();
#define SUPERVU_CHECKCONDITION 0 // has to be 0!!
static const uint VU_EXESIZE = _1mb * 8;
static const uint sVU_EXESIZE = _8mb;
#define _Imm11_ (s32)( (vucode & 0x400) ? (0xfffffc00 | (vucode & 0x3ff)) : (vucode & 0x3ff) )
#define _UImm11_ (s32)(vucode & 0x7ff)
@ -90,7 +91,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 +318,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 +348,24 @@ 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( L"SuperVU Recompiler Cache", 0 );
s_recVUMem[vuindex]->Reserve( sVU_EXESIZE, vuindex ? HostMemoryMap::sVU1rec : HostMemoryMap::sVU0rec, _256mb );
// 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(HostMemoryMap::sVUrec, VU_EXESIZE, 0x10000000, "SuperVUAlloc");
safe_delete(s_recVUMem[vuindex]);
throw Exception::VirtualMemoryMapConflict()
.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. :)"
));
// 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(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. :)"
));
}
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];
ProfilerRegisterSource("sVU Rec", *s_recVUMem[vuindex], sVU_EXESIZE);
}
}
@ -416,72 +398,66 @@ 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);
ProfilerTerminateSource(vuindex ? "sVU1Rec" : "sVU0Rec");
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 +823,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 +887,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 +922,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 +2672,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 +4592,9 @@ recSuperVU0::recSuperVU0()
IsInterpreter = false;
}
void recSuperVU0::Allocate()
void recSuperVU0::Reserve()
{
SuperVUAlloc( 0 );
SuperVUAlloc(0);
}
void recSuperVU0::Shutdown() throw()
@ -4645,6 +4620,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 +4639,9 @@ recSuperVU1::recSuperVU1()
IsInterpreter = false;
}
void recSuperVU1::Allocate()
void recSuperVU1::Reserve()
{
SuperVUAlloc( 1 );
SuperVUAlloc(1);
}
void recSuperVU1::Shutdown() throw()
@ -4670,6 +4654,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