mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
bed33749b5
commit
4bee22a4cd
|
@ -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" />
|
||||
|
|
|
@ -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"
|
||||
>
|
||||
|
|
|
@ -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!
|
||||
// ===========================================================================================
|
||||
|
|
|
@ -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) );
|
||||
}
|
|
@ -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,17 +160,59 @@ 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;
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 );
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -432,7 +432,7 @@ set(pcsx2SystemSources
|
|||
|
||||
# System headers
|
||||
set(pcsx2SystemHeaders
|
||||
System/PageFaultSource.h
|
||||
System/RecTypes.h
|
||||
System/SysThreads.h)
|
||||
|
||||
# Utilities sources
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "Vif_Dma.h"
|
||||
#include <limits.h>
|
||||
|
||||
#include "Utilities/MemsetFast.inl"
|
||||
|
||||
// the BP doesn't advance and returns -1 if there is no data to be read
|
||||
__aligned16 tIPU_cmd ipu_cmd;
|
||||
__aligned16 tIPU_BP g_BP;
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include "Mpeg.h"
|
||||
#include "Vlc.h"
|
||||
|
||||
#include "Utilities/MemsetFast.inl"
|
||||
|
||||
const int non_linear_quantizer_scale [] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
|
|
|
@ -24,48 +24,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
template< typename T >
|
||||
__noinline void memzero_sse_a( T& dest )
|
||||
{
|
||||
#define MZFqwc (sizeof(dest)/16)
|
||||
|
||||
C_ASSERT( (sizeof(dest) & 0xf) == 0 );
|
||||
|
||||
__m128 zeroreg = _mm_setzero_ps();
|
||||
|
||||
float (*destxmm)[4] = (float(*)[4])&dest;
|
||||
|
||||
#define StoreDestIdx(idx) case idx: _mm_store_ps(&destxmm[idx-1][0], zeroreg)
|
||||
|
||||
switch( MZFqwc & 0x07 )
|
||||
{
|
||||
StoreDestIdx(0x07);
|
||||
StoreDestIdx(0x06);
|
||||
StoreDestIdx(0x05);
|
||||
StoreDestIdx(0x04);
|
||||
StoreDestIdx(0x03);
|
||||
StoreDestIdx(0x02);
|
||||
StoreDestIdx(0x01);
|
||||
}
|
||||
|
||||
destxmm += (MZFqwc & 0x07);
|
||||
for( uint i=0; i<MZFqwc / 8; ++i, destxmm+=8 )
|
||||
{
|
||||
_mm_store_ps(&destxmm[0][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[1][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[2][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[3][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[4][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[5][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[6][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[7][0], zeroreg);
|
||||
}
|
||||
|
||||
#undef MZFqwc
|
||||
};
|
||||
|
||||
// the IPU is fixed to 16 byte strides (128-bit / QWC resolution):
|
||||
static const uint decoder_stride = 16;
|
||||
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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 )
|
||||
|
|
255
pcsx2/System.cpp
255
pcsx2/System.cpp
|
@ -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 )
|
||||
{
|
||||
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -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__
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -459,6 +459,10 @@
|
|||
RelativePath="..\..\Plugins.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\System\RecTypes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\SamplProf.h"
|
||||
>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <winnt.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "System/PageFaultSource.h"
|
||||
#include "Utilities/PageFaultSource.h"
|
||||
|
||||
int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
|
||||
{
|
||||
|
|
|
@ -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)));
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(µVU0); }
|
||||
void recMicroVU1::Vsync() throw() { mVUvsyncUpdate(µVU1); }
|
||||
|
||||
void recMicroVU0::Allocate() {
|
||||
if(!m_AllocCount) {
|
||||
m_AllocCount++;
|
||||
if (AtomicExchange(mvu0_allocated, 1) == 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)
|
||||
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)
|
||||
if (AtomicExchange(m_Reserved, 0) == 1)
|
||||
microVU0.close();
|
||||
}
|
||||
}
|
||||
void recMicroVU1::Shutdown() throw() {
|
||||
if (m_AllocCount > 0) {
|
||||
m_AllocCount--;
|
||||
if (AtomicExchange(mvu1_allocated, 0) == 1)
|
||||
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(µVU0, addr, size);
|
||||
}
|
||||
void recMicroVU1::Clear(u32 addr, u32 size) {
|
||||
pxAssert(mvu1_allocated); // please allocate me first! :|
|
||||
pxAssert(m_Reserved); // please allocate me first! :|
|
||||
mVUclear(µVU1, addr, size);
|
||||
}
|
||||
|
||||
uint recMicroVU0::GetCacheReserve() const
|
||||
{
|
||||
return microVU0.cacheSize / _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;
|
||||
}
|
||||
|
|
|
@ -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,6 +175,8 @@ struct microVU {
|
|||
ScopedPtr<microRegAlloc> regAlloc; // Reg Alloc Class
|
||||
ScopedPtr<AsciiFile> logFile; // Log File Pointer
|
||||
|
||||
|
||||
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
|
||||
|
@ -225,6 +227,15 @@ struct microVU {
|
|||
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();
|
||||
void close();
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ void mVUdispatcherB(mV) {
|
|||
|
||||
xRET();
|
||||
|
||||
mVUcacheCheck(x86Ptr, mVU->dispCache, mVUdispCacheSize);
|
||||
pxAssertDev(xGetPtr() < (mVU->dispCache + mVUdispCacheSize), "microVU: Dispatcher generation exceeded reserved cache area!");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
@ -121,8 +121,14 @@ _mVUt void mVUcleanUp() {
|
|||
//mVUprint("microVU: Program exited successfully!");
|
||||
//mVUprint("microVU: VF0 = {%x,%x,%x,%x}", mVU->regs().VF[0].UL[0], mVU->regs().VF[0].UL[1], mVU->regs().VF[0].UL[2], mVU->regs().VF[0].UL[3]);
|
||||
//mVUprint("microVU: VI0 = %x", mVU->regs().VI[0].UL);
|
||||
|
||||
mVU->prog.x86ptr = x86Ptr;
|
||||
mVUcacheCheck(x86Ptr, mVU->prog.x86start, (uptr)(mVU->prog.x86end - mVU->prog.x86start));
|
||||
|
||||
if ((xGetPtr() < mVU->prog.x86start) || (xGetPtr() >= mVU->prog.x86end)) {
|
||||
Console.WriteLn(vuIndex ? Color_Orange : Color_Magenta, "microVU%d: Program cache limit reached.", mVU->index);
|
||||
mVU->reset();
|
||||
}
|
||||
|
||||
mVU->cycles = mVU->totalCycles - mVU->cycles;
|
||||
mVU->regs().cycle += mVU->cycles;
|
||||
cpuRegs.cycle += ((mVU->cycles < 3000) ? mVU->cycles : 3000) * EmuConfig.Speedhacks.VUCycleSteal;
|
||||
|
|
|
@ -298,15 +298,6 @@ static const bool doConstProp = 0; // Set to 1 to turn on vi15 const propagation
|
|||
|
||||
//------------------------------------------------------------------
|
||||
|
||||
// Cache Limit Check
|
||||
#define mVUcacheCheck(ptr, start, limit) { \
|
||||
uptr diff = ptr - start; \
|
||||
if (diff >= limit) { \
|
||||
DevCon.WriteLn("microVU%d: Program cache limit reached. Size = 0x%x", mVU->index, diff); \
|
||||
mVUresizeCache(mVU, mVU->cacheSize + mVUcacheGrowBy); \
|
||||
} \
|
||||
}
|
||||
|
||||
extern void mVUmergeRegs(const xmm& dest, const xmm& src, int xyzw, bool modXYZW=false);
|
||||
extern void mVUsaveReg(const xmm& reg, xAddressVoid ptr, int xyzw, bool modXYZW);
|
||||
extern void mVUloadReg(const xmm& reg, xAddressVoid ptr, int xyzw);
|
||||
|
|
|
@ -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);
|
||||
|
@ -317,7 +320,9 @@ 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 u8* recVUStack[2] = { NULL, NULL };
|
||||
static u8* recVUStackPtr[2] = { NULL, NULL };
|
||||
|
||||
static vector<_x86regs> s_vecRegArray(128);
|
||||
|
||||
static VURegs* VU = NULL;
|
||||
|
@ -343,23 +348,15 @@ 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)
|
||||
{
|
||||
// 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");
|
||||
|
||||
// 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)
|
||||
if (!s_recVUMem[vuindex]->IsOk())
|
||||
{
|
||||
safe_delete(s_recVUMem[vuindex]);
|
||||
throw Exception::VirtualMemoryMapConflict()
|
||||
.SetDiagMsg(pxsFmt( L"SuperVU failed to allocate virtual memory below 256MB." ))
|
||||
.SetUserMsg(pxE( ".Error:superVU:VirtualMemoryAlloc",
|
||||
|
@ -367,23 +364,8 @@ static void SuperVUAlloc(int vuindex)
|
|||
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,18 +398,8 @@ 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]);
|
||||
|
||||
|
@ -440,36 +412,31 @@ void SuperVUDestroy(int 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)
|
||||
{
|
||||
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));
|
||||
|
||||
|
@ -481,7 +448,16 @@ void SuperVUReset(int 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,7 +4592,7 @@ recSuperVU0::recSuperVU0()
|
|||
IsInterpreter = false;
|
||||
}
|
||||
|
||||
void recSuperVU0::Allocate()
|
||||
void recSuperVU0::Reserve()
|
||||
{
|
||||
SuperVUAlloc(0);
|
||||
}
|
||||
|
@ -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,7 +4639,7 @@ recSuperVU1::recSuperVU1()
|
|||
IsInterpreter = false;
|
||||
}
|
||||
|
||||
void recSuperVU1::Allocate()
|
||||
void recSuperVU1::Reserve()
|
||||
{
|
||||
SuperVUAlloc(1);
|
||||
}
|
||||
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue