diff --git a/common/include/Utilities/Dependencies.h b/common/include/Utilities/Dependencies.h index 25fd3bd22c..f36cac9d1d 100644 --- a/common/include/Utilities/Dependencies.h +++ b/common/include/Utilities/Dependencies.h @@ -189,6 +189,7 @@ static const s64 _32mb = _1mb * 32; static const s64 _64mb = _1mb * 64; static const s64 _256mb = _1mb * 256; static const s64 _1gb = _256mb * 4; +static const s64 _4gb = _1gb * 4; // =========================================================================================== diff --git a/common/include/Utilities/PageFaultSource.h b/common/include/Utilities/PageFaultSource.h index 32e71e98b9..ce16f63aa6 100644 --- a/common/include/Utilities/PageFaultSource.h +++ b/common/include/Utilities/PageFaultSource.h @@ -62,7 +62,7 @@ protected: }; // -------------------------------------------------------------------------------------- -// EventListener_PageFault +// EventListener_PageFault / EventListenerHelper_PageFault // -------------------------------------------------------------------------------------- class EventListener_PageFault : public IEventListener_PageFault { @@ -71,6 +71,36 @@ public: virtual ~EventListener_PageFault() throw(); }; +template< typename TypeToDispatchTo > +class EventListenerHelper_PageFault : public EventListener_PageFault +{ +public: + TypeToDispatchTo* Owner; + +public: + EventListenerHelper_PageFault( TypeToDispatchTo& dispatchTo ) + { + Owner = &dispatchTo; + } + + EventListenerHelper_PageFault( TypeToDispatchTo* dispatchTo ) + { + Owner = dispatchTo; + } + + virtual ~EventListenerHelper_PageFault() throw() {} + +protected: + virtual void OnPageFaultEvent( const PageFaultInfo& info, bool& handled ) + { + OnPageFaultEvent( info, handled ); + } + +}; + +// -------------------------------------------------------------------------------------- +// SrcType_PageFault +// -------------------------------------------------------------------------------------- class SrcType_PageFault : public EventSource { protected: @@ -90,57 +120,68 @@ protected: virtual void _DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt ); }; + // -------------------------------------------------------------------------------------- -// BaseVirtualMemoryReserve (WIP!!) +// VirtualMemoryReserve // -------------------------------------------------------------------------------------- -class BaseVirtualMemoryReserve : public EventListener_PageFault +class VirtualMemoryReserve { - DeclareNoncopyableObject( BaseVirtualMemoryReserve ); + DeclareNoncopyableObject( VirtualMemoryReserve ); public: wxString Name; protected: + // Default size of the reserve, in bytes. Can be specified when the object is contructed. + // Is used as the reserve size when Reserve() is called, unless an override is specified + // in the Reserve parameters. + size_t m_defsize; + void* m_baseptr; // reserved memory (in pages). - uptr m_reserved; - - // Incremental size by which the buffer grows (in pages) - uptr m_blocksize; + uptr m_pages_reserved; // Protection mode to be applied to committed blocks. PageProtectionMode m_prot_mode; // Records the number of pages committed to memory. // (metric for analysis of buffer usage) - uptr m_commited; + uptr m_pages_commited; public: - BaseVirtualMemoryReserve( const wxString& name ); - virtual ~BaseVirtualMemoryReserve() throw() + VirtualMemoryReserve( const wxString& name, size_t size = 0 ); + virtual ~VirtualMemoryReserve() throw() { - Free(); + Release(); } - virtual void* Reserve( uint size, uptr base = 0, uptr upper_bounds = 0 ); - virtual void Reset(); - virtual void Free(); - virtual bool TryResize( uint newsize ); + virtual void* Reserve( size_t size = 0, uptr base = 0, uptr upper_bounds = 0 ); + virtual void* ReserveAt( uptr base = 0, uptr upper_bounds = 0 ) + { + return Reserve(m_defsize, base, upper_bounds); + } - virtual void CommitBlocks( uptr page, uint blocks ); + virtual void Reset(); + virtual void Release(); + virtual bool TryResize( uint newsize ); + virtual bool Commit(); bool IsOk() const { return m_baseptr != NULL; } wxString GetName() const { return Name; } - uptr GetReserveSizeInBytes() const { return m_reserved * __pagesize; } - uptr GetReserveSizeInPages() const { return m_reserved; } + uptr GetReserveSizeInBytes() const { return m_pages_reserved * __pagesize; } + uptr GetReserveSizeInPages() const { return m_pages_reserved; } + uint GetCommittedPageCount() const { return m_pages_commited; } + uint GetCommittedBytes() const { return m_pages_commited * __pagesize; } u8* GetPtr() { return (u8*)m_baseptr; } const u8* GetPtr() const { return (u8*)m_baseptr; } + u8* GetPtrEnd() { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); } + const u8* GetPtrEnd() const { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); } - u8* GetPtrEnd() { return (u8*)m_baseptr + (m_reserved * __pagesize); } - const u8* GetPtrEnd() const { return (u8*)m_baseptr + (m_reserved * __pagesize); } + VirtualMemoryReserve& SetBaseAddr( uptr newaddr ); + VirtualMemoryReserve& SetPageAccessOnCommit( const PageProtectionMode& mode ); operator void*() { return m_baseptr; } operator const void*() const { return m_baseptr; } @@ -150,16 +191,45 @@ public: u8& operator[](uint idx) { - pxAssume(idx < (m_reserved * __pagesize)); + pxAssume(idx < (m_pages_reserved * __pagesize)); return *((u8*)m_baseptr + idx); } const u8& operator[](uint idx) const { - pxAssume(idx < (m_reserved * __pagesize)); + pxAssume(idx < (m_pages_reserved * __pagesize)); return *((u8*)m_baseptr + idx); } +}; + +// -------------------------------------------------------------------------------------- +// BaseVmReserveListener +// -------------------------------------------------------------------------------------- +class BaseVmReserveListener : public VirtualMemoryReserve +{ + DeclareNoncopyableObject( BaseVmReserveListener ); + + typedef VirtualMemoryReserve _parent; + +protected: + EventListenerHelper_PageFault m_pagefault_listener; + + // Incremental size by which the buffer grows (in pages) + uptr m_blocksize; + +public: + BaseVmReserveListener( const wxString& name, size_t size = 0 ); + virtual ~BaseVmReserveListener() throw() { } + + operator void*() { return m_baseptr; } + operator const void*() const { return m_baseptr; } + + operator u8*() { return (u8*)m_baseptr; } + operator const u8*() const { return (u8*)m_baseptr; } + + using _parent::operator[]; + protected: void OnPageFaultEvent( const PageFaultInfo& info, bool& handled ); @@ -175,6 +245,8 @@ protected: // This function is called for every committed block. virtual void OnCommittedBlock( void* block )=0; + + virtual void CommitBlocks( uptr page, uint blocks ); }; // -------------------------------------------------------------------------------------- @@ -202,9 +274,9 @@ protected: // 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 +class SpatialArrayReserve : public BaseVmReserveListener { - typedef BaseVirtualMemoryReserve __parent; + typedef BaseVmReserveListener _parent; protected: uint m_numblocks; @@ -218,7 +290,7 @@ protected: public: SpatialArrayReserve( const wxString& name ); - virtual void* Reserve( uint size, uptr base = 0, uptr upper_bounds = 0 ); + virtual void* Reserve( size_t size = 0, uptr base = 0, uptr upper_bounds = 0 ); virtual void Reset(); virtual bool TryResize( uint newsize ); @@ -234,7 +306,7 @@ public: operator u8*() { return (u8*)m_baseptr; } operator const u8*() const { return (u8*)m_baseptr; } - using __parent::operator[]; + using _parent::operator[]; protected: void DoCommitAndProtect( uptr page ); @@ -258,7 +330,8 @@ extern int SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps); # error PCSX2 - Unsupported operating system platform. #endif -extern void InstallSignalHandler(); +extern void pxInstallSignalHandler(); +extern void _platform_InstallSignalHandler(); extern SrcType_PageFault* Source_PageFault; diff --git a/common/src/Utilities/Linux/LnxHostSys.cpp b/common/src/Utilities/Linux/LnxHostSys.cpp index 7cff02002b..cdcecb3161 100644 --- a/common/src/Utilities/Linux/LnxHostSys.cpp +++ b/common/src/Utilities/Linux/LnxHostSys.cpp @@ -15,11 +15,64 @@ #include "../PrecompiledHeader.h" +#include "PageFaultSource.h" #include #include #include +extern void SignalExit(int sig); + +static const uptr m_pagemask = getpagesize()-1; + +// Linux implementation of SIGSEGV handler. Bind it using sigaction(). +static void SysPageFaultSignalFilter( int signal, siginfo_t *siginfo, void * ) +{ + // [TODO] : Add a thread ID filter to the Linux Signal handler here. + // Rationale: On windows, the __try/__except model allows per-thread specific behavior + // for page fault handling. On linux, there is a single signal handler for the whole + // process, but the handler is executed by the thread that caused the exception. + + + // Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done + // from the context of the current thread and stackframe. So long as the thread is not + // the main/ui thread, use of the px assertion system should be safe. Use of stdio should + // be safe even on the main thread. + // (in other words, stdio limitations only really apply to process-level asynchronous + // signals) + + // Note: Use of stdio functions isn't safe here. Avoid console logs, + // assertions, file logs, or just about anything else useful. + + Source_PageFault->Dispatch( PageFaultInfo( (uptr)siginfo->si_addr & ~m_pagemask ) ); + + // resumes execution right where we left off (re-executes instruction that + // caused the SIGSEGV). + if (Source_PageFault->WasHandled()) return; + + if (!wxThread::IsMain()) + { + pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr)); + } + + // Bad mojo! Completely invalid address. + // Instigate a trap if we're in a debugger, and if not then do a SIGKILL. + + wxTrap(); + if (!IsDebugBuild) raise( SIGKILL ); +} + +void _platform_InstallSignalHandler() +{ + Console.WriteLn("Installing POSIX SIGSEGV handler..."); + struct sigaction sa; + + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = SysPageFaultSignalFilter; + sigaction(SIGSEGV, &sa, NULL); +} + static __ri void PageSizeAssertionTest( size_t size ) { pxAssertMsg( (__pagesize == getpagesize()), pxsFmt( diff --git a/common/src/Utilities/VirtualMemory.cpp b/common/src/Utilities/VirtualMemory.cpp index 3ce141004d..1812ade3a7 100644 --- a/common/src/Utilities/VirtualMemory.cpp +++ b/common/src/Utilities/VirtualMemory.cpp @@ -27,6 +27,21 @@ template class EventSource< IEventListener_PageFault >; SrcType_PageFault* Source_PageFault = NULL; +void pxInstallSignalHandler() +{ + if (!Source_PageFault) + { + Source_PageFault = new SrcType_PageFault(); + } + + _platform_InstallSignalHandler(); + + // NOP on Win32 systems -- we use __try{} __except{} instead. +} + +// -------------------------------------------------------------------------------------- +// EventListener_PageFault (implementations) +// -------------------------------------------------------------------------------------- EventListener_PageFault::EventListener_PageFault() { pxAssume(Source_PageFault); @@ -53,50 +68,78 @@ void SrcType_PageFault::_DispatchRaw( ListenerIterator iter, const ListenerItera } // -------------------------------------------------------------------------------------- -// BaseVirtualMemoryReserve (implementations) +// VirtualMemoryReserve (implementations) // -------------------------------------------------------------------------------------- - -BaseVirtualMemoryReserve::BaseVirtualMemoryReserve( const wxString& name ) +VirtualMemoryReserve::VirtualMemoryReserve( const wxString& name, size_t size ) : Name( name ) { - m_commited = 0; - m_reserved = 0; - m_baseptr = NULL; - m_blocksize = __pagesize; - m_prot_mode = PageAccess_None(); + m_defsize = size; + + m_pages_commited = 0; + m_pages_reserved = 0; + m_baseptr = NULL; + m_prot_mode = PageAccess_None(); } +VirtualMemoryReserve& VirtualMemoryReserve::SetBaseAddr( uptr newaddr ) +{ + if (!pxAssertDev(!m_pages_reserved, "Invalid object state: you must release the virtual memory reserve prior to changing its base address!")) return *this; + + m_baseptr = (void*)newaddr; + return *this; +} + +VirtualMemoryReserve& VirtualMemoryReserve::SetPageAccessOnCommit( const PageProtectionMode& mode ) +{ + m_prot_mode = mode; + return *this; +} + + +// Notes: +// * This method should be called if the object is already in an released (unreserved) state. +// Subsequent calls will be ignored, and the existing reserve will be returned. +// // Parameters: +// size - size of the reserve, in bytes. (optional) +// If not specified (or zero), then the default size specified in the constructor for the +// object instance is used. +// // upper_bounds - criteria that must be met for the allocation to be valid. // If the OS refuses to allocate the memory below the specified address, the // object will fail to initialize and an exception will be thrown. -void* BaseVirtualMemoryReserve::Reserve( uint size, uptr base, uptr upper_bounds ) +void* VirtualMemoryReserve::Reserve( size_t size, uptr base, uptr upper_bounds ) { if (!pxAssertDev( m_baseptr == NULL, "(VirtualMemoryReserve) Invalid object state; object has already been reserved." )) return m_baseptr; - m_reserved = (size + __pagesize-4) / __pagesize; - uptr reserved_bytes = m_reserved * __pagesize; + if (!size) size = m_defsize; + if (!size) return NULL; + + m_pages_reserved = (size + __pagesize-4) / __pagesize; + uptr reserved_bytes = m_pages_reserved * __pagesize; m_baseptr = (void*)HostSys::MmapReserve(base, reserved_bytes); - if (!m_baseptr && (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds))) + if (!m_baseptr || (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds))) { + DevCon.Warning( L"%s: host memory @ 0x%08x -> 0x%08x is unavailable; attempting to map elsewhere...", + Name.c_str(), base, base + size ); + + SafeSysMunmap(m_baseptr, reserved_bytes); + 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 = HostSys::MmapReserve( 0, reserved_bytes ); } - - if ((upper_bounds != 0) && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)) - { - SafeSysMunmap( m_baseptr, reserved_bytes ); - // returns null, caller should throw an exception or handle appropriately. - } + } + + if ((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; @@ -108,20 +151,30 @@ void* BaseVirtualMemoryReserve::Reserve( uint size, uptr base, uptr upper_bounds } // Clears all committed blocks, restoring the allocation to a reserve only. -void BaseVirtualMemoryReserve::Reset() +void VirtualMemoryReserve::Reset() { - if (!m_commited) return; - - HostSys::MemProtect(m_baseptr, m_commited*__pagesize, PageAccess_None()); - HostSys::MmapResetPtr(m_baseptr, m_commited*__pagesize); - m_commited = 0; + if (!m_pages_commited) return; + + HostSys::MemProtect(m_baseptr, m_pages_commited*__pagesize, PageAccess_None()); + HostSys::MmapResetPtr(m_baseptr, m_pages_commited*__pagesize); + m_pages_commited = 0; } -void BaseVirtualMemoryReserve::Free() +void VirtualMemoryReserve::Release() { - HostSys::Munmap((uptr)m_baseptr, m_reserved*__pagesize); + SafeSysMunmap(m_baseptr, m_pages_reserved*__pagesize); } +bool VirtualMemoryReserve::Commit() +{ + if (!m_pages_reserved) return false; + if (!pxAssert(!m_pages_commited)) return true; + + m_pages_commited = m_pages_reserved; + return HostSys::MmapCommitPtr(m_baseptr, m_pages_reserved*__pagesize, m_prot_mode); +} + + // If growing the array, or if shrinking the array to some point that's still *greater* than the // committed memory range, then attempt a passive "on-the-fly" resize that maps/unmaps some portion // of the reserve. @@ -131,13 +184,13 @@ void BaseVirtualMemoryReserve::Free() // // Parameters: // newsize - new size of the reserved buffer, in bytes. -bool BaseVirtualMemoryReserve::TryResize( uint newsize ) +bool VirtualMemoryReserve::TryResize( uint newsize ) { uint newPages = (newsize + __pagesize - 1) / __pagesize; - if (newPages > m_reserved) + if (newPages > m_pages_reserved) { - uint toReservePages = newPages - m_reserved; + uint toReservePages = newPages - m_pages_reserved; uint toReserveBytes = toReservePages * __pagesize; DevCon.WriteLn( L"%-32s is being expanded by %u pages.", Name.c_str(), toReservePages); @@ -153,11 +206,11 @@ bool BaseVirtualMemoryReserve::TryResize( uint newsize ) DevCon.WriteLn( Color_Blue, L"%-32s @ 0x%08X -> 0x%08X [%umb]", Name.c_str(), m_baseptr, (uptr)m_baseptr+toReserveBytes, toReserveBytes / _1mb); } - else if (newPages < m_reserved) + else if (newPages < m_pages_reserved) { - if (m_commited > newsize) return false; + if (m_pages_commited > newsize) return false; - uint toRemovePages = m_reserved - newPages; + uint toRemovePages = m_pages_reserved - newPages; uint toRemoveBytes = toRemovePages * __pagesize; DevCon.WriteLn( L"%-32s is being shrunk by %u pages.", Name.c_str(), toRemovePages); @@ -171,8 +224,18 @@ bool BaseVirtualMemoryReserve::TryResize( uint newsize ) return true; } +// -------------------------------------------------------------------------------------- +// BaseVmReserveListener (implementations) +// -------------------------------------------------------------------------------------- -void BaseVirtualMemoryReserve::CommitBlocks( uptr page, uint blocks ) +BaseVmReserveListener::BaseVmReserveListener( const wxString& name, size_t size ) + : VirtualMemoryReserve( name, size ) + , m_pagefault_listener( this ) +{ + m_blocksize = __pagesize; +} + +void BaseVmReserveListener::CommitBlocks( uptr page, uint blocks ) { const uptr blocksbytes = blocks * m_blocksize * __pagesize; void* blockptr = (u8*)m_baseptr + (page * __pagesize); @@ -190,13 +253,13 @@ void BaseVirtualMemoryReserve::CommitBlocks( uptr page, uint blocks ) for( ; init= m_reserved)) return; + if ((offset < 0) || ((uptr)offset >= m_pages_reserved)) return; // Linux Note! the SIGNAL handler is very limited in what it can do, and not only can't // we let the C++ exception try to unwind the stack, we may not be able to log it either. @@ -238,7 +301,7 @@ void BaseVirtualMemoryReserve::OnPageFaultEvent(const PageFaultInfo& info, bool& // -------------------------------------------------------------------------------------- SpatialArrayReserve::SpatialArrayReserve( const wxString& name ) : - __parent( name ) + _parent( name ) { m_prot_mode = PageAccess_ReadWrite(); } @@ -250,9 +313,9 @@ uint SpatialArrayReserve::_calcBlockBitArrayLength() const return (((m_numblocks + 7) / 8) + 15) & ~15; } -void* SpatialArrayReserve::Reserve( uint size, uptr base, uptr upper_bounds ) +void* SpatialArrayReserve::Reserve( size_t size, uptr base, uptr upper_bounds ) { - void* addr = __parent::Reserve( size, base, upper_bounds ); + void* addr = _parent::Reserve( size, base, upper_bounds ); if (!addr) return NULL; if (m_blocksize) SetBlockSizeInPages( m_blocksize ); @@ -264,7 +327,7 @@ void* SpatialArrayReserve::Reserve( uint size, uptr base, uptr upper_bounds ) // Resets/clears the spatial array, reducing the memory commit pool overhead to zero (0). void SpatialArrayReserve::Reset() { - if (m_commited) + if (m_pages_commited) { u8* curptr = GetPtr(); const uint blockBytes = m_blocksize * __pagesize; @@ -299,7 +362,7 @@ bool SpatialArrayReserve::TryResize( uint newsize ) uint pages_in_use = i * m_blocksize; if (newpages < pages_in_use) return false; - if (!__parent::TryResize( newsize )) return false; + if (!_parent::TryResize( newsize )) return false; // On success, we must re-calibrate the internal blockbits array. @@ -317,12 +380,12 @@ bool SpatialArrayReserve::TryResize( uint newsize ) // in debug builds. SpatialArrayReserve& SpatialArrayReserve::SetBlockCount( uint blocks ) { - pxAssumeDev( !m_commited, "Invalid object state: SetBlockCount must be called prior to reserved memory accesses." ); + pxAssumeDev( !m_pages_commited, "Invalid object state: SetBlockCount must be called prior to reserved memory accesses." ); // Calculate such that the last block extends past the end of the array, if necessary. m_numblocks = blocks; - m_blocksize = (m_reserved + m_numblocks-1) / m_numblocks; + m_blocksize = (m_pages_reserved + m_numblocks-1) / m_numblocks; return *this; } @@ -334,10 +397,10 @@ SpatialArrayReserve& SpatialArrayReserve::SetBlockCount( uint blocks ) // a modified buffer will be ignored (and generate an assertion in dev/debug modes). SpatialArrayReserve& SpatialArrayReserve::SetBlockSizeInPages( uint pages ) { - if (pxAssertDev(!m_commited, "Invalid object state: Block size can only be changed prior to accessing or modifying the reserved buffer contents.")) + if (pxAssertDev(!m_pages_commited, "Invalid object state: Block size can only be changed prior to accessing or modifying the reserved buffer contents.")) { m_blocksize = pages; - m_numblocks = (m_reserved + m_blocksize - 1) / m_blocksize; + m_numblocks = (m_pages_reserved + m_blocksize - 1) / m_blocksize; m_blockbits.Alloc( _calcBlockBitArrayLength() ); } return *this; diff --git a/common/src/Utilities/Windows/WinHostSys.cpp b/common/src/Utilities/Windows/WinHostSys.cpp index 4db028ea24..d35b258246 100644 --- a/common/src/Utilities/Windows/WinHostSys.cpp +++ b/common/src/Utilities/Windows/WinHostSys.cpp @@ -15,8 +15,25 @@ #include "PrecompiledHeader.h" #include "Utilities/RedtapeWindows.h" +#include "PageFaultSource.h" + #include +int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps ) +{ + if( eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION ) + return EXCEPTION_CONTINUE_SEARCH; + + Source_PageFault->Dispatch( PageFaultInfo( (uptr)eps->ExceptionRecord->ExceptionInformation[1] ) ); + return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; +} + +void _platform_InstallSignalHandler() +{ + // NOP on Win32 systems -- we use __try{} __except{} instead. +} + + static DWORD ConvertToWinApi( const PageProtectionMode& mode ) { DWORD winmode = PAGE_NOACCESS; @@ -94,7 +111,7 @@ void* HostSys::Mmap(uptr base, size_t size) void HostSys::Munmap(uptr base, size_t size) { if (!base) return; - VirtualFree((void*)base, size, MEM_DECOMMIT); + //VirtualFree((void*)base, size, MEM_DECOMMIT); VirtualFree((void*)base, 0, MEM_RELEASE); } diff --git a/pcsx2/IopMem.cpp b/pcsx2/IopMem.cpp index a4e5825fd2..00b619378a 100644 --- a/pcsx2/IopMem.cpp +++ b/pcsx2/IopMem.cpp @@ -24,26 +24,38 @@ IopVM_MemoryAllocMess* iopMem = NULL; __pagealigned u8 iopHw[Ps2MemSize::IopHardware]; -void psxMemAlloc() +// -------------------------------------------------------------------------------------- +// iopMemoryReserve +// -------------------------------------------------------------------------------------- +iopMemoryReserve::iopMemoryReserve() + : _parent( L"IOP Main Memory (2mb)", sizeof(*iopMem) ) { - if( iopMem == NULL ) - iopMem = (IopVM_MemoryAllocMess*)vtlb_malloc( sizeof(*iopMem), 4096 ); +} - psxMemWLUT = (uptr*)_aligned_malloc(0x2000 * sizeof(uptr) * 2, 16); - psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16); +void iopMemoryReserve::Reserve() +{ + _parent::Reserve(HostMemoryMap::IOPmem); + //_parent::Reserve(EmuConfig.HostMap.IOP); + iopMem = (IopVM_MemoryAllocMess*)m_reserve.GetPtr(); } // Note! Resetting the IOP's memory state is dependent on having *all* psx memory allocated, // which is performed by MemInit and PsxMemInit() -void psxMemReset() +void iopMemoryReserve::Reset() { - pxAssume( psxMemWLUT != NULL ); - pxAssume( iopMem != NULL ); + _parent::Reset(); - DbgCon.WriteLn( "IOP Resetting physical ram..." ); + pxAssume( iopMem ); + + if (!psxMemWLUT) + { + psxMemWLUT = (uptr*)_aligned_malloc(0x2000 * sizeof(uptr) * 2, 16); + psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16); + } + + DbgCon.WriteLn("IOP resetting main memory..."); memzero_ptr<0x2000 * sizeof(uptr) * 2>( psxMemWLUT ); // clears both allocations, RLUT and WLUT - memzero( *iopMem ); // Trick! We're accessing RLUT here through WLUT, since it's the non-const pointer. // So the ones with a 0x2000 prefixed are RLUT tables. @@ -87,15 +99,21 @@ void psxMemReset() //for (i=0; i<0x0008; i++) psxMemWLUT[i + 0xbfc0] = (uptr)&psR[i << 16]; } -void psxMemShutdown() +void iopMemoryReserve::Shutdown() { - vtlb_free( iopMem, sizeof(*iopMem) ); - iopMem = NULL; + _parent::Shutdown(); safe_aligned_free(psxMemWLUT); psxMemRLUT = NULL; } +void iopMemoryReserve::Release() +{ + _parent::Release(); + iopMem = NULL; +} + + u8 __fastcall iopMemRead8(u32 mem) { mem &= 0x1fffffff; diff --git a/pcsx2/IopMem.h b/pcsx2/IopMem.h index 3ee0b4cfa6..ae6c6bd6e3 100644 --- a/pcsx2/IopMem.h +++ b/pcsx2/IopMem.h @@ -71,6 +71,7 @@ static __fi u8* iopPhysMem( u32 addr ) #define psxHu16(mem) (*(u16*)&iopHw[(mem) & 0xffff]) #define psxHu32(mem) (*(u32*)&iopHw[(mem) & 0xffff]) +extern void psxMemReserve(); extern void psxMemAlloc(); extern void psxMemReset(); extern void psxMemShutdown(); diff --git a/pcsx2/Linux/LnxHostSys.cpp b/pcsx2/Linux/LnxHostSys.cpp deleted file mode 100644 index 1d46634e7d..0000000000 --- a/pcsx2/Linux/LnxHostSys.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" - -#include -#include -#include "Common.h" - -#include "Utilities/PageFaultSource.h" - -extern void SignalExit(int sig); - -static const uptr m_pagemask = getpagesize()-1; - -// Linux implementation of SIGSEGV handler. Bind it using sigaction(). -static void SysPageFaultSignalFilter( int signal, siginfo_t *siginfo, void * ) -{ - // Note: Use of most stdio functions isn't safe here. Avoid console logs, - // assertions, file logs, or just about anything else useful. - - Source_PageFault->Dispatch( PageFaultInfo( (uptr)siginfo->si_addr & ~m_pagemask ) ); - - // resumes execution right where we left off (re-executes instruction that - // caused the SIGSEGV). - if( Source_PageFault->WasHandled() ) return; - - // Bad mojo! Completely invalid address. - // Instigate a trap if we're in a debugger, and if not then do a SIGKILL. - - wxTrap(); - if( !IsDebugBuild ) raise( SIGKILL ); -} - -void InstallSignalHandler() -{ - Console.WriteLn("Installing POSIX SIGSEGV handler..."); - struct sigaction sa; - - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = SysPageFaultSignalFilter; - sigaction(SIGSEGV, &sa, NULL); -} - -void NTFS_CompressFile( const wxString& file, bool compressStatus ) {} diff --git a/pcsx2/Linux/LnxKeyCodes.cpp b/pcsx2/Linux/LnxKeyCodes.cpp index a98befcb72..d87f7e9efa 100644 --- a/pcsx2/Linux/LnxKeyCodes.cpp +++ b/pcsx2/Linux/LnxKeyCodes.cpp @@ -20,6 +20,8 @@ #include #include +void NTFS_CompressFile( const wxString& file, bool compressStatus ) {} + // Returns a WXK_* keycode, given some kinda GDK input mess! int TranslateGDKtoWXK( u32 keysym ) { diff --git a/pcsx2/Memory.cpp b/pcsx2/Memory.cpp index d9e7e59115..415ca979f7 100644 --- a/pcsx2/Memory.cpp +++ b/pcsx2/Memory.cpp @@ -586,30 +586,8 @@ protected: static mmap_PageFaultHandler* mmap_faultHandler = NULL; EEVM_MemoryAllocMess* eeMem = NULL; - __pagealigned u8 eeHw[Ps2MemSize::Hardware]; -void memAlloc() -{ - if( eeMem == NULL ) - eeMem = (EEVM_MemoryAllocMess*)vtlb_malloc( sizeof(*eeMem), 4096 ); - - if( eeMem == NULL) - throw Exception::OutOfMemory( L"PS2 Main Memory (VTLB)" ) - .SetUserMsg(L"Could not allocate memory needed for the PS2 virtual machine's main memory (approx. 42mb)."); - - pxAssume(Source_PageFault); - mmap_faultHandler = new mmap_PageFaultHandler(); -} - -void memShutdown() -{ - safe_delete(mmap_faultHandler); - - vtlb_free( eeMem, sizeof(*eeMem) ); - eeMem = NULL; - vtlb_Term(); -} void memBindConditionalHandlers() { @@ -639,19 +617,39 @@ void memBindConditionalHandlers() } } -// Resets memory mappings, unmaps TLBs, reloads bios roms, etc. -void memReset() + +// -------------------------------------------------------------------------------------- +// eeMemoryReserve (implementations) +// -------------------------------------------------------------------------------------- +eeMemoryReserve::eeMemoryReserve() + : _parent( L"EE Main Memory", sizeof(*eeMem) ) { - // VTLB Protection Preparations. - //HostSys::MemProtect( m_psAllMem, m_allMemSize, Protect_ReadWrite ); +} + +void eeMemoryReserve::Reserve() +{ + _parent::Reserve(HostMemoryMap::EEmem); + //_parent::Reserve(EmuConfig.HostMap.IOP); + eeMem = (EEVM_MemoryAllocMess*)m_reserve.GetPtr(); +} + +// Resets memory mappings, unmaps TLBs, reloads bios roms, etc. +void eeMemoryReserve::Reset() +{ + if (!mmap_faultHandler) + { + pxAssume(Source_PageFault); + mmap_faultHandler = new mmap_PageFaultHandler(); + } + + _parent::Reset(); // Note!! Ideally the vtlb should only be initialized once, and then subsequent // resets of the system hardware would only clear vtlb mappings, but since the // rest of the emu is not really set up to support a "soft" reset of that sort // we opt for the hard/safe version. - pxAssume( eeMem != NULL ); - memzero( *eeMem ); + pxAssume( eeMem ); #ifdef ENABLECACHE memset(pCache,0,sizeof(_cacheS)*64); @@ -764,9 +762,18 @@ void memReset() LoadBIOS(); } -////////////////////////////////////////////////////////////////////////////////////////// -// Memory Protection and Block Checking, vtlb Style! -// +void eeMemoryReserve::Release() +{ + safe_delete(mmap_faultHandler); + _parent::Release(); + eeMem = NULL; + vtlb_Term(); +} + + +// =========================================================================================== +// Memory Protection and Block Checking, vtlb Style! +// =========================================================================================== // For the first time code is recompiled (executed), the PS2 ram page for that code is // protected using Virtual Memory (mprotect). If the game modifies its own code then this // protection causes an *exception* to be raised (signal in Linux), which is handled by diff --git a/pcsx2/Memory.h b/pcsx2/Memory.h index 5deee6be22..547a9d1d8b 100644 --- a/pcsx2/Memory.h +++ b/pcsx2/Memory.h @@ -107,9 +107,7 @@ static __fi void ZeroQWC( u128& dest ) #define psSu64(mem) (*(u64 *)&eeMem->Scratch[(mem) & 0x3fff]) #define psSu128(mem) (*(u128*)&eeMem->Scratch[(mem) & 0x3fff]) -extern void memAlloc(); -extern void memReset(); // clears PS2 ram and loads the bios. Throws Exception::FileNotFound on error. -extern void memShutdown(); + extern void memSetKernelMode(); //extern void memSetSupervisorMode(); extern void memSetUserMode(); diff --git a/pcsx2/MemoryTypes.h b/pcsx2/MemoryTypes.h index db1b6b4a70..9f13853062 100644 --- a/pcsx2/MemoryTypes.h +++ b/pcsx2/MemoryTypes.h @@ -17,18 +17,18 @@ namespace Ps2MemSize { - static const uint MainRam = 0x02000000; // 32 MB main memory! - static const uint Rom = 0x00400000; // 4 MB main rom - static const uint Rom1 = 0x00040000; // DVD player - static const uint Rom2 = 0x00080000; // Chinese rom extension (?) - static const uint ERom = 0x001C0000; // DVD player extensions (?) - static const uint Hardware = 0x00010000; - static const uint Scratch = 0x00004000; + static const uint MainRam = _32mb; // 32 MB main memory! + static const uint Rom = _1mb * 4; // 4 MB main rom + static const uint Rom1 = 0x00040000; // DVD player + static const uint Rom2 = 0x00080000; // Chinese rom extension (?) + static const uint ERom = 0x001C0000; // DVD player extensions (?) + static const uint Hardware = _64kb; + static const uint Scratch = _16kb; - static const uint IopRam = 0x00200000; // 2MB main ram on the IOP. - static const uint IopHardware = 0x00010000; + static const uint IopRam = _1mb * 2; // 2MB main ram on the IOP. + static const uint IopHardware = _64kb; - static const uint GSregs = 0x00002000; // 8k for the GS registers and stuff. + static const uint GSregs = 0x00002000; // 8k for the GS registers and stuff. } typedef u8 mem8_t; @@ -53,6 +53,9 @@ typedef u128 mem128_t; // memory, such as hardware registers or scratchpad, the access will generate a page fault, the // compiled block will be cleared and re-compiled using "full" VTLB translation logic. // +// Note that support for this feature may not be doable under x86/32 platforms, due to the +// 2gb/3gb limit of Windows XP (the 3gb feature will make it slightly more feasible at least). +// #define VTLB_UsePageFaulting 0 #if VTLB_UsePageFaulting @@ -101,7 +104,7 @@ struct EEVM_MemoryAllocMess struct IopVM_MemoryAllocMess { u8 Main[Ps2MemSize::IopRam]; // Main memory (hard-wired to 2MB) - u8 P[0x00010000]; // I really have no idea what this is... --air + u8 P[_64kb]; // I really have no idea what this is... --air u8 Sif[0x100]; // a few special SIF/SBUS registers (likely not needed) }; diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index d093da9fcb..4ac9680a29 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -50,14 +50,14 @@ static const uint eeWaitCycles = 3072; bool eeEventTestIsActive = false; +extern SysMainMemory& GetVmMemory(); + void cpuReset() { - if( GetMTGS().IsOpen() ) + if (GetMTGS().IsOpen()) GetMTGS().WaitGS(); // GS better be done processing before we reset the EE, just in case. - memReset(); - psxMemReset(); - vuMicroMemReset(); + GetVmMemory().ResetAll(); memzero(cpuRegs); memzero(fpuRegs); diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index c55047efa3..b922787d20 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -41,7 +41,7 @@ extern void resetNewVif(int idx); // Parameters: // name - a nice long name that accurately describes the contents of this reserve. RecompiledCodeReserve::RecompiledCodeReserve( const wxString& name, uint defCommit ) - : BaseVirtualMemoryReserve( name ) + : BaseVmReserveListener( name ) { m_blocksize = (1024 * 128) / __pagesize; m_prot_mode = PageAccess_Any(); @@ -73,9 +73,9 @@ uint RecompiledCodeReserve::_calcDefaultCommitInBlocks() const return (m_def_commit + m_blocksize - 1) / m_blocksize; } -void* RecompiledCodeReserve::Reserve( uint size, uptr base, uptr upper_bounds ) +void* RecompiledCodeReserve::Reserve( size_t size, uptr base, uptr upper_bounds ) { - if (!__parent::Reserve(size, base, upper_bounds)) return NULL; + if (!_parent::Reserve(size, base, upper_bounds)) return NULL; _registerProfiler(); return m_baseptr; } @@ -93,7 +93,7 @@ RecompiledCodeReserve& RecompiledCodeReserve::SetProfilerName( const wxString& s void RecompiledCodeReserve::DoCommitAndProtect( uptr page ) { - CommitBlocks(page, (m_commited || !m_def_commit) ? 1 : _calcDefaultCommitInBlocks() ); + CommitBlocks(page, (m_pages_commited || !m_def_commit) ? 1 : _calcDefaultCommitInBlocks() ); } void RecompiledCodeReserve::OnCommittedBlock( void* block ) @@ -333,84 +333,71 @@ static wxString GetMemoryErrorVM() // -------------------------------------------------------------------------------------- // SysReserveVM (implementations) // -------------------------------------------------------------------------------------- -SysReserveVM::SysReserveVM() +SysMainMemory::SysMainMemory() { - if (!Source_PageFault) Source_PageFault = new SrcType_PageFault(); - - // [TODO] : Reserve memory addresses for PS2 virtual machine - //DevCon.WriteLn( "Reserving memory addresses for the PS2 virtual machine..." ); } -void SysReserveVM::CleanupMess() throw() +SysMainMemory::~SysMainMemory() throw() { - try - { - safe_delete(Source_PageFault); - } - DESTRUCTOR_CATCHALL + ShutdownAll(); + ReleaseAll(); } -SysReserveVM::~SysReserveVM() throw() +void SysMainMemory::ReserveAll() { - CleanupMess(); + pxInstallSignalHandler(); + + DevCon.WriteLn( "PS2vm: Mapping host memory for all virtual systems..." ); + + m_ee.Reserve(); + m_iop.Reserve(); + m_vu.Reserve(); } -// -------------------------------------------------------------------------------------- -// SysAllocVM (implementations) -// -------------------------------------------------------------------------------------- -SysAllocVM::SysAllocVM() +void SysMainMemory::CommitAll() { - InstallSignalHandler(); + if (m_ee.IsCommitted() && m_iop.IsCommitted() && m_vu.IsCommitted()) return; - Console.WriteLn( "Allocating memory for the PS2 virtual machine..." ); + DevCon.WriteLn( "PS2vm: Allocating host memory for all virtual systems..." ); - try - { - vtlb_Core_Alloc(); - memAlloc(); - psxMemAlloc(); - vuMicroMemAlloc(); - } - // ---------------------------------------------------------------------------- - catch( Exception::OutOfMemory& ex ) - { - ex.UserMsg() += L"\n\n" + GetMemoryErrorVM(); - CleanupMess(); - throw; - } - catch( std::bad_alloc& ex ) - { - CleanupMess(); - - // re-throw std::bad_alloc as something more friendly. This is needed since - // much of the code uses new/delete internally, which throw std::bad_alloc on fail. - - throw Exception::OutOfMemory() - .SetDiagMsg( - L"std::bad_alloc caught while trying to allocate memory for the PS2 Virtual Machine.\n" - L"Error Details: " + fromUTF8( ex.what() ) - ) - .SetUserMsg(GetMemoryErrorVM()); // translated - } + m_ee.Commit(); + m_iop.Commit(); + m_vu.Commit(); } -void SysAllocVM::CleanupMess() throw() + +void SysMainMemory::ResetAll() { - try - { - vuMicroMemShutdown(); - psxMemShutdown(); - memShutdown(); - vtlb_Core_Shutdown(); - } - DESTRUCTOR_CATCHALL + CommitAll(); + + DevCon.WriteLn( "PS2vm: Resetting host memory for all virtual systems..." ); + + m_ee.Reset(); + m_iop.Reset(); + m_vu.Reset(); } -SysAllocVM::~SysAllocVM() throw() +void SysMainMemory::ShutdownAll() { - CleanupMess(); + Console.WriteLn( "PS2vm: Shutting down host memory for all virtual systems..." ); + + m_ee.Shutdown(); + m_iop.Shutdown(); + m_vu.Shutdown(); } +void SysMainMemory::ReleaseAll() +{ + Console.WriteLn( "PS2vm: Releasing host memory maps for all virtual systems..." ); + + m_ee.Shutdown(); + m_iop.Shutdown(); + m_vu.Shutdown(); + + safe_delete(Source_PageFault); +} + + // -------------------------------------------------------------------------------------- // SysCpuProviderPack (implementations) // -------------------------------------------------------------------------------------- diff --git a/pcsx2/System.h b/pcsx2/System.h index 52280eb138..00a92f88da 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -21,6 +21,8 @@ #include "Utilities/Threading.h" // to use threading stuff, include the Threading namespace in your file. #include "CDVD/CDVDaccess.h" +#include "vtlb.h" + typedef SafeArray VmStateBuffer; class BaseVUmicroCPU; @@ -30,49 +32,62 @@ class RecompiledCodeReserve; // are provided and used to assist in debugging and possibly hacking; as it makes it possible // for a programmer to know exactly where to look (consistently!) for the base address of // the various virtual machine components. These addresses can be keyed directly into the -// debugger's disasm window to get disassembl of recompiled code, and they can be used to help +// debugger's disasm window to get disassembly of recompiled code, and they can be used to help // identify recompiled code addresses in the callstack. // All of these areas should be reserved as soon as possible during program startup, and its // important that none of the areas overlap. In all but superVU's case, failure due to overlap // or other conflict will result in the operating system picking a preferred address for the mapping. + namespace HostMemoryMap { // superVU is OLD SCHOOL, and it requires its allocation to be in the lower 256mb // of the virtual memory space. (8mb each) - static const uptr sVU0rec = _256mb - (_16mb*2); - static const uptr sVU1rec = _256mb - (_16mb*1); + static const uptr sVU0rec = _256mb - (_8mb*3); + static const uptr sVU1rec = _256mb - (_8mb*2); // PS2 main memory, SPR, and ROMs - static const uptr EEmem = 0x20000000; + static const uptr EEmem = 0x30000000; // IOP main memory and ROMs - static const uptr IOPmem = 0x28000000; + static const uptr IOPmem = 0x34000000; + + // VU0 and VU1 memory. + static const uptr VUmem = 0x38000000; // EE recompiler code cache area (64mb) - static const uptr EErec = 0x30000000; + static const uptr EErec = 0x40000000; // IOP recompiler code cache area (16 or 32mb) - static const uptr IOPrec = 0x34000000; + static const uptr IOPrec = 0x44000000; - // microVU1 recompiler code cache area (64mb) - static const uptr mVU0rec = 0x38000000; + // microVU1 recompiler code cache area (32 or 64mb) + static const uptr mVU0rec = 0x48000000; // microVU0 recompiler code cache area (64mb) - static const uptr mVU1rec = 0x40000000; + static const uptr mVU1rec = 0x50000000; } // -------------------------------------------------------------------------------------- -// SysReserveVM +// SysMainMemory // -------------------------------------------------------------------------------------- -class SysReserveVM +// This class provides the main memory for the virtual machines. +class SysMainMemory { -public: - SysReserveVM(); - virtual ~SysReserveVM() throw(); - protected: - void CleanupMess() throw(); + eeMemoryReserve m_ee; + iopMemoryReserve m_iop; + vuMemoryReserve m_vu; + +public: + SysMainMemory(); + virtual ~SysMainMemory() throw(); + + virtual void ReserveAll(); + virtual void CommitAll(); + virtual void ResetAll(); + virtual void ShutdownAll(); + virtual void ReleaseAll(); }; // -------------------------------------------------------------------------------------- @@ -142,6 +157,8 @@ extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true ); extern wxString SysGetDiscID(); +extern SysMainMemory& GetVmMemory(); + // -------------------------------------------------------------------------------------- // PCSX2_SEH - Defines existence of "built in" Structured Exception Handling support. // -------------------------------------------------------------------------------------- diff --git a/pcsx2/System/RecTypes.h b/pcsx2/System/RecTypes.h index e999780058..1fec845da1 100644 --- a/pcsx2/System/RecTypes.h +++ b/pcsx2/System/RecTypes.h @@ -23,9 +23,9 @@ // A recompiled code reserve is a simple sequential-growth block of memory which is auto- // cleared to INT 3 (0xcc) as needed. // -class RecompiledCodeReserve : public BaseVirtualMemoryReserve +class RecompiledCodeReserve : public BaseVmReserveListener { - typedef BaseVirtualMemoryReserve __parent; + typedef BaseVmReserveListener _parent; protected: // Specifies the number of blocks that should be committed automatically when the @@ -40,7 +40,7 @@ public: RecompiledCodeReserve( const wxString& name, uint defCommit = 0 ); virtual ~RecompiledCodeReserve() throw(); - virtual void* Reserve( uint size, uptr base=0, uptr upper_bounds=0 ); + virtual void* Reserve( size_t size, uptr base=0, uptr upper_bounds=0 ); virtual void OnCommittedBlock( void* block ); virtual RecompiledCodeReserve& SetProfilerName( const wxString& shortname ); diff --git a/pcsx2/System/SysCoreThread.cpp b/pcsx2/System/SysCoreThread.cpp index a1f59ded4e..4c28750d44 100644 --- a/pcsx2/System/SysCoreThread.cpp +++ b/pcsx2/System/SysCoreThread.cpp @@ -111,13 +111,24 @@ void SysCoreThread::SetElfOverride( const wxString& elf ) Hle_SetElfPath(elf.ToUTF8()); } -void SysCoreThread::Reset() +// Performs a quicker reset that does not deallocate memory associated with PS2 virtual machines +// or cpu providers (recompilers). +void SysCoreThread::ResetQuick() { Suspend(); + m_resetVirtualMachine = true; m_hasActiveMachine = false; } +void SysCoreThread::Reset() +{ + ResetQuick(); + GetVmMemory().ShutdownAll(); + SysClearExecutionCache(); +} + + // Applies a full suite of new settings, which will automatically facilitate the necessary // resets of the core and components (including plugins, if needed). The scope of resetting // is determined by comparing the current settings against the new settings, so that only @@ -159,6 +170,8 @@ void SysCoreThread::_reset_stuff_as_needed() // because of changes to the TLB. We don't actually support the TLB, however, so rec // resets aren't in fact *needed* ... yet. But might as well, no harm. --air + GetVmMemory().CommitAll(); + if( m_resetVirtualMachine || m_resetRecompilers || m_resetProfilers ) { SysClearExecutionCache(); diff --git a/pcsx2/System/SysThreads.h b/pcsx2/System/SysThreads.h index b686777269..3ca161c2ae 100644 --- a/pcsx2/System/SysThreads.h +++ b/pcsx2/System/SysThreads.h @@ -184,6 +184,7 @@ public: virtual void OnResumeReady(); virtual void Reset(); + virtual void ResetQuick(); virtual void Cancel( bool isBlocking=true ); virtual bool Cancel( const wxTimeSpan& timeout ); diff --git a/pcsx2/VUmicro.h b/pcsx2/VUmicro.h index 8270c17714..3a5d09bbd2 100644 --- a/pcsx2/VUmicro.h +++ b/pcsx2/VUmicro.h @@ -19,15 +19,15 @@ #include "VUops.h" #include "R5900.h" -static const uint VU0_MEMSIZE = 0x1000; -static const uint VU0_PROGSIZE = 0x1000; -static const uint VU1_MEMSIZE = 0x4000; -static const uint VU1_PROGSIZE = 0x4000; +static const uint VU0_MEMSIZE = 0x1000; // 4kb +static const uint VU0_PROGSIZE = 0x1000; // 4kb +static const uint VU1_MEMSIZE = 0x4000; // 16kb +static const uint VU1_PROGSIZE = 0x4000; // 16kb -static const uint VU0_MEMMASK = VU0_MEMSIZE-1; -static const uint VU0_PROGMASK = VU0_PROGSIZE-1; -static const uint VU1_MEMMASK = VU1_MEMSIZE-1; -static const uint VU1_PROGMASK = VU1_PROGSIZE-1; +static const uint VU0_MEMMASK = VU0_MEMSIZE-1; +static const uint VU0_PROGMASK = VU0_PROGSIZE-1; +static const uint VU1_MEMMASK = VU1_MEMSIZE-1; +static const uint VU1_PROGMASK = VU1_PROGSIZE-1; #define vuRunCycles (512*12) // Cycles to run ExecuteBlockJIT() for (called from within recs) #define vu0RunCycles (512*12) // Cycles to run vu0 for whenever ExecuteBlock() is called @@ -287,10 +287,6 @@ extern BaseVUmicroCPU* CpuVU0; extern BaseVUmicroCPU* CpuVU1; -extern void vuMicroMemAlloc(); -extern void vuMicroMemShutdown(); -extern void vuMicroMemReset(); - // VU0 extern void vu0ResetRegs(); extern void __fastcall vu0ExecMicro(u32 addr); diff --git a/pcsx2/VUmicroMem.cpp b/pcsx2/VUmicroMem.cpp index d0aad70822..5eea6ec73c 100644 --- a/pcsx2/VUmicroMem.cpp +++ b/pcsx2/VUmicroMem.cpp @@ -18,43 +18,41 @@ #include "Common.h" #include "VUmicro.h" + __aligned16 VURegs vuRegs[2]; -static u8* m_vuAllMem = NULL; -static const uint m_vuMemSize = - 0x1000 + // VU0micro memory - 0x4000 + // VU0 memory - 0x4000 + // VU1 memory - 0x4000; -void vuMicroMemAlloc() +vuMemoryReserve::vuMemoryReserve() + : _parent( L"VU0/1 on-chip memory", VU1_PROGSIZE + VU1_MEMSIZE + VU0_PROGSIZE + VU0_MEMSIZE ) { - if( m_vuAllMem == NULL ) - m_vuAllMem = vtlb_malloc( m_vuMemSize, 16 ); +} - if( m_vuAllMem == NULL ) - throw Exception::OutOfMemory( L"VU0 and VU1 on-chip memory" ); +void vuMemoryReserve::Reserve() +{ + _parent::Reserve(HostMemoryMap::VUmem); + //_parent::Reserve(EmuConfig.HostMemMap.VUmem); - u8* curpos = m_vuAllMem; + u8* curpos = m_reserve.GetPtr(); VU0.Micro = curpos; curpos += 0x1000; VU0.Mem = curpos; curpos += 0x4000; VU1.Micro = curpos; curpos += 0x4000; VU1.Mem = curpos; - //curpos += 0x4000; } -void vuMicroMemShutdown() +void vuMemoryReserve::Release() { - // -- VTLB Memory Allocation -- + _parent::Release(); - vtlb_free( m_vuAllMem, m_vuMemSize ); - m_vuAllMem = NULL; + VU0.Micro = VU0.Mem = NULL; + VU1.Micro = VU1.Mem = NULL; } -void vuMicroMemReset() +void vuMemoryReserve::Reset() { - pxAssume( VU0.Mem != NULL ); - pxAssume( VU1.Mem != NULL ); + _parent::Reset(); + + pxAssume( VU0.Mem ); + pxAssume( VU1.Mem ); memMapVUmicro(); @@ -67,8 +65,6 @@ void vuMicroMemReset() VU0.VF[0].f.z = 0.0f; VU0.VF[0].f.w = 1.0f; VU0.VI[0].UL = 0; - memzero_ptr<4*1024>(VU0.Mem); - memzero_ptr<4*1024>(VU0.Micro); // === VU1 Initialization === memzero(VU1.ACC); @@ -79,8 +75,6 @@ void vuMicroMemReset() VU1.VF[0].f.z = 0.0f; VU1.VF[0].f.w = 1.0f; VU1.VI[0].UL = 0; - memzero_ptr<16*1024>(VU1.Mem); - memzero_ptr<16*1024>(VU1.Micro); } void SaveStateBase::vuMicroFreeze() diff --git a/pcsx2/gui/App.h b/pcsx2/gui/App.h index d3cc86acdc..89538f7810 100644 --- a/pcsx2/gui/App.h +++ b/pcsx2/gui/App.h @@ -476,8 +476,7 @@ public: // blocked threads stalling the GUI. ExecutorThread SysExecutorThread; ScopedPtr m_CpuProviders; - ScopedPtr m_VmReserve; - ScopedPtr m_VmAllocs; + ScopedPtr m_VmReserve; protected: wxWindowID m_id_MainFrame; @@ -499,6 +498,8 @@ public: void SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override=wxEmptyString ); void LogicalVsync(); + SysMainMemory& GetVmReserve(); + GSFrame& GetGsFrame() const; MainEmuFrame& GetMainFrame() const; @@ -528,8 +529,6 @@ public: void StartPendingSave(); void ClearPendingSave(); - void AllocateVM(); - // -------------------------------------------------------------------------- // App-wide Resources // -------------------------------------------------------------------------- diff --git a/pcsx2/gui/AppCoreThread.cpp b/pcsx2/gui/AppCoreThread.cpp index 178864ae9e..7e3a42298a 100644 --- a/pcsx2/gui/AppCoreThread.cpp +++ b/pcsx2/gui/AppCoreThread.cpp @@ -109,6 +109,17 @@ void AppCoreThread::Reset() _parent::Reset(); } +void AppCoreThread::ResetQuick() +{ + if( !GetSysExecutorThread().IsSelf() ) + { + GetSysExecutorThread().PostEvent( SysExecEvent_InvokeCoreThreadMethod(&AppCoreThread::ResetQuick) ); + return; + } + + _parent::ResetQuick(); +} + ExecutorThread& GetSysExecutorThread() { return wxGetApp().SysExecutorThread; @@ -183,7 +194,6 @@ void Pcsx2App::SysApplySettings() void AppCoreThread::OnResumeReady() { wxGetApp().SysApplySettings(); - wxGetApp().AllocateVM(); wxGetApp().PostMethod( AppSaveSettings ); _parent::OnResumeReady(); } diff --git a/pcsx2/gui/AppCoreThread.h b/pcsx2/gui/AppCoreThread.h index 7afd428925..3ed3ae90a8 100644 --- a/pcsx2/gui/AppCoreThread.h +++ b/pcsx2/gui/AppCoreThread.h @@ -134,6 +134,7 @@ public: virtual void Suspend( bool isBlocking=false ); virtual void Resume(); virtual void Reset(); + virtual void ResetQuick(); virtual void Cancel( bool isBlocking=true ); virtual bool StateCheckInThread(); virtual void ChangeCdvdSource(); diff --git a/pcsx2/gui/AppEventListeners.h b/pcsx2/gui/AppEventListeners.h index 54d5021f7c..4a54621a43 100644 --- a/pcsx2/gui/AppEventListeners.h +++ b/pcsx2/gui/AppEventListeners.h @@ -163,6 +163,12 @@ public: // this second layer class to act as a bridge between the event system and the class's // handler implementations. // +// Explained in detail: The class that wants to listen to shit will implement its expected +// virtual overrides from the listener classes (OnCoreThread_Started, for example), and then +// it adds an instance of the EventListenerHelper_CoreThread class to itself, instead of +// *inheriting* from it. Thusly, the Helper gets initialized when the class is created, +// and when events are dispatched to the listener, it forwards the event to the main class. +// --air template< typename TypeToDispatchTo > class EventListenerHelper_CoreThread : public EventListener_CoreThread @@ -212,9 +218,9 @@ public: protected: void CorePlugins_OnLoaded() { Owner.OnCorePlugins_Loaded(); } void CorePlugins_OnInit() { Owner.OnCorePlugins_Init(); } - void CorePlugins_OnOpening() { Owner.OnCorePlugins_Opening(); } + void CorePlugins_OnOpening() { Owner.OnCorePlugins_Opening(); } void CorePlugins_OnOpened() { Owner.OnCorePlugins_Opened(); } - void CorePlugins_OnClosing() { Owner.OnCorePlugins_Closing(); } + void CorePlugins_OnClosing() { Owner.OnCorePlugins_Closing(); } void CorePlugins_OnClosed() { Owner.OnCorePlugins_Closed(); } void CorePlugins_OnShutdown() { Owner.OnCorePlugins_Shutdown(); } void CorePlugins_OnUnloaded() { Owner.OnCorePlugins_Unloaded(); } diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index ac3ebafff8..d9f539b5eb 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -238,12 +238,6 @@ void Pcsx2App::OpenProgramLog() if( m_current_focus ) m_current_focus->SetFocus(); } -void Pcsx2App::AllocateVM() -{ - if (m_VmAllocs) return; - m_VmAllocs = new SysAllocVM(); -} - void Pcsx2App::AllocateCoreStuffs() { if( AppRpc_TryInvokeAsync( &Pcsx2App::AllocateCoreStuffs ) ) return; @@ -252,7 +246,7 @@ void Pcsx2App::AllocateCoreStuffs() SysLogMachineCaps(); AppApplySettings(); - if (!m_VmReserve) m_VmReserve = new SysReserveVM(); + GetVmReserve().ReserveAll(); if( !m_CpuProviders ) { @@ -820,12 +814,12 @@ void Pcsx2App::CleanUp() __fi wxString AddAppName( const wxChar* fmt ) { - return wxsFormat( fmt, pxGetAppName().c_str() ); + return pxsFmt( fmt, pxGetAppName().c_str() ); } __fi wxString AddAppName( const char* fmt ) { - return wxsFormat( fromUTF8(fmt), pxGetAppName().c_str() ); + return pxsFmt( fromUTF8(fmt), pxGetAppName().c_str() ); } // ------------------------------------------------------------------------------------------ diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index a19e23f824..fa64938bd9 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -702,6 +702,12 @@ void Pcsx2App::PostIdleAppMethod( FnPtr_Pcsx2App method ) AddIdleEvent( evt ); } +SysMainMemory& Pcsx2App::GetVmReserve() +{ + if (!m_VmReserve) m_VmReserve = new SysMainMemory(); + return *m_VmReserve; +} + void Pcsx2App::OpenGsPanel() { if( AppRpc_TryInvoke( &Pcsx2App::OpenGsPanel ) ) return; @@ -851,7 +857,7 @@ protected: DbgCon.WriteLn( Color_Gray, "(SysExecute) received." ); - CoreThread.Reset(); + CoreThread.ResetQuick(); CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso ); if( m_UseCDVDsrc ) @@ -930,6 +936,11 @@ MainEmuFrame* GetMainFramePtr() return wxTheApp ? wxGetApp().GetMainFramePtr() : NULL; } +SysMainMemory& GetVmMemory() +{ + return wxGetApp().GetVmReserve(); +} + SysCoreThread& GetCoreThread() { return CoreThread; diff --git a/pcsx2/vtlb.cpp b/pcsx2/vtlb.cpp index 1695fd5d1e..fb4fd2f37a 100644 --- a/pcsx2/vtlb.cpp +++ b/pcsx2/vtlb.cpp @@ -33,9 +33,10 @@ #include "Common.h" #include "vtlb.h" #include "COP0.h" - #include "R5900Exceptions.h" +#include "Utilities\MemsetFast.inl" + using namespace R5900; using namespace vtlb_private; @@ -46,7 +47,7 @@ namespace vtlb_private __aligned(64) MapData vtlbdata; } -static vtlbHandler vtlbHandlerCount=0; +static vtlbHandler vtlbHandlerCount = 0; static vtlbHandler DefaultPhyHandler; static vtlbHandler UnmappedVirtHandler0; @@ -565,69 +566,67 @@ void vtlb_Term() // [TODO] basemem - request allocating memory at the specified virtual location, which can allow // for easier debugging and/or 3rd party cheat programs. If 0, the operating system // default is used. -void vtlb_Core_Alloc( /*uptr basemem*/ ) +void vtlb_Core_Alloc() { - if( vtlbdata.alloc_base != NULL ) return; - - vtlbdata.alloc_current = 0; - vtlbdata.alloc_base = SysMmapEx( HostMemoryMap::EEmem, VTLB_ALLOC_SIZE, 0x80000000, "Vtlb" ); - -#ifndef __WXMSW__ - // [TODO] Win32 can fall back on this, since malloc always maps below 2GB. (but we need to - // make sure we flag it and call the right free -- and really it should never fail anyway - // since SysMmapEx should still grab addresses below the 2gb line when given the 0 param - // (OS picks the location). - - //if (!vtlbdata.alloc_base) - // vtlbdata.alloc_base = (u8*)_aligned_malloc( VTLB_ALLOC_SIZE, 4096 ); -#endif - - if (!vtlbdata.alloc_base) - throw Exception::OutOfMemory( pxsFmt(L"PS2 mappable system ram (%u megs)", VTLB_ALLOC_SIZE / _1mb) ); - vtlbdata.vmap = (s32*)_aligned_malloc( VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap), 16 ); if (!vtlbdata.vmap) - throw Exception::OutOfMemory( pxsFmt(L"VTLB virtual LUT (%u megs)", VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap) / _1mb) ); + throw Exception::OutOfMemory( L"VTLB Virtual Address Translation LUT" ) + .SetDiagMsg(pxsFmt("(%u megs)", VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap) / _1mb) + ); } -void vtlb_Core_Shutdown() +void vtlb_Core_Free() { safe_aligned_free( vtlbdata.vmap ); - - if (!vtlbdata.alloc_base) return; - - SafeSysMunmap( vtlbdata.alloc_base, VTLB_ALLOC_SIZE ); - -#ifdef __WXMSW__ - // Make sure and unprotect memory first, since CrtDebug will try to write to it. - //HostSys::MemProtect( vtlbdata.alloc_base, VTLB_ALLOC_SIZE, Protect_ReadWrite ); - //safe_aligned_free( vtlbdata.alloc_base ); -#endif - } -// This function allocates memory block with are compatible with the Vtlb's requirements -// for memory locations. The Vtlb requires the topmost bit (Sign bit) of the memory -// pointer to be cleared. Some operating systems and/or implementations of malloc do that, -// but others do not. So use this instead to allocate the memory correctly for your -// platform. -// -u8* vtlb_malloc( uint size, uint align ) +// -------------------------------------------------------------------------------------- +// VtlbMemoryReserve (implementations) +// -------------------------------------------------------------------------------------- +VtlbMemoryReserve::VtlbMemoryReserve( const wxString& name, size_t size ) + : m_reserve( name, size ) { - vtlbdata.alloc_current += align-1; - vtlbdata.alloc_current &= ~(align-1); - - int rv = vtlbdata.alloc_current; - vtlbdata.alloc_current += size; - - pxAssertDev( vtlbdata.alloc_current < VTLB_ALLOC_SIZE, "(vtlb_malloc) memory overflow! Please increase the size of VTLB_ALLOC_SIZE!" ); - return &vtlbdata.alloc_base[rv]; + m_reserve.SetPageAccessOnCommit( PageAccess_ReadWrite() ); } -void vtlb_free( void* pmem, uint size ) +void VtlbMemoryReserve::SetBaseAddr( uptr newaddr ) { - if (!pmem) return; - - vtlbdata.alloc_current -= size; - pxAssertDev( vtlbdata.alloc_current >= 0, "(vtlb_free) mismatched calls to vtlb_malloc and free detected via memory underflow." ); + m_reserve.SetBaseAddr( newaddr ); } + +void VtlbMemoryReserve::Reserve( sptr hostptr ) +{ + m_reserve.Reserve(); + if (!m_reserve.IsOk()) + throw Exception::OutOfMemory( m_reserve.GetName() ); +} + +void VtlbMemoryReserve::Commit() +{ + if (IsCommitted()) return; + if (!m_reserve.Commit()) + throw Exception::OutOfMemory( m_reserve.GetName() ); +} + +void VtlbMemoryReserve::Reset() +{ + if (!m_reserve.Commit()) + throw Exception::OutOfMemory( m_reserve.GetName() ); + + memzero_sse_a(m_reserve.GetPtr(), m_reserve.GetCommittedBytes()); +} + +void VtlbMemoryReserve::Shutdown() +{ + m_reserve.Reset(); +} + +void VtlbMemoryReserve::Release() +{ + m_reserve.Release(); +} + +bool VtlbMemoryReserve::IsCommitted() const +{ + return !!m_reserve.GetCommittedPageCount(); +} \ No newline at end of file diff --git a/pcsx2/vtlb.h b/pcsx2/vtlb.h index a80c586879..934988d60b 100644 --- a/pcsx2/vtlb.h +++ b/pcsx2/vtlb.h @@ -17,6 +17,10 @@ #include "MemoryTypes.h" +#include "Utilities/PageFaultSource.h" + +static const uptr VTLB_AllocUpperBounds = _1gb * 2; + // Specialized function pointers for each read type typedef mem8_t __fastcall vtlbMemR8FP(u32 addr); typedef mem16_t __fastcall vtlbMemR16FP(u32 addr); @@ -34,12 +38,10 @@ typedef void __fastcall vtlbMemW128FP(u32 addr,const mem128_t* data); typedef u32 vtlbHandler; extern void vtlb_Core_Alloc(); -extern void vtlb_Core_Shutdown(); +extern void vtlb_Core_Free(); extern void vtlb_Init(); extern void vtlb_Reset(); extern void vtlb_Term(); -extern u8* vtlb_malloc( uint size, uint align ); -extern void vtlb_free( void* pmem, uint size ); extern vtlbHandler vtlb_NewHandler(); @@ -85,19 +87,100 @@ extern void vtlb_DynGenWrite_Const( u32 bits, u32 addr_const ); extern void vtlb_DynGenRead64_Const( u32 bits, u32 addr_const ); extern void vtlb_DynGenRead32_Const( u32 bits, bool sign, u32 addr_const ); +// -------------------------------------------------------------------------------------- +// VtlbMemoryReserve +// -------------------------------------------------------------------------------------- +class VtlbMemoryReserve +{ +protected: + VirtualMemoryReserve m_reserve; + +public: + VtlbMemoryReserve( const wxString& name, size_t size ); + virtual ~VtlbMemoryReserve() throw() + { + m_reserve.Release(); + } + + virtual void Reserve( sptr hostptr ); + virtual void Release(); + + virtual void Commit(); + virtual void Reset(); + virtual void Shutdown(); + virtual void SetBaseAddr( uptr newaddr ); + + bool IsCommitted() const; +}; + +// -------------------------------------------------------------------------------------- +// eeMemoryReserve +// -------------------------------------------------------------------------------------- +class eeMemoryReserve : public VtlbMemoryReserve +{ + typedef VtlbMemoryReserve _parent; + +public: + eeMemoryReserve(); + virtual ~eeMemoryReserve() throw() + { + Release(); + } + + void Reserve(); + void Release(); + void Reset(); +}; + +// -------------------------------------------------------------------------------------- +// iopMemoryReserve +// -------------------------------------------------------------------------------------- +class iopMemoryReserve : public VtlbMemoryReserve +{ + typedef VtlbMemoryReserve _parent; + +public: + iopMemoryReserve(); + virtual ~iopMemoryReserve() throw() + { + Release(); + } + + void Reserve(); + void Release(); + void Reset(); + void Shutdown(); +}; + +// -------------------------------------------------------------------------------------- +// vuMemoryReserve +// -------------------------------------------------------------------------------------- +class vuMemoryReserve : public VtlbMemoryReserve +{ + typedef VtlbMemoryReserve _parent; + +public: + vuMemoryReserve(); + virtual ~vuMemoryReserve() throw() + { + Release(); + } + + virtual void Reserve(); + virtual void Release(); + + void Reset(); +}; + namespace vtlb_private { - // Allocate enough memory for EE, IOP, and VU, memory space (IOP + VU is roughly - // 2.5mb, so we alloc 4mb for now -- a little more than is needed). - static const uint VTLB_ALLOC_SIZE = sizeof(*eeMem) + (_1mb*4); - static const uint VTLB_PAGE_BITS = 12; static const uint VTLB_PAGE_MASK = 4095; static const uint VTLB_PAGE_SIZE = 4096; - static const uint VTLB_PMAP_ITEMS = 0x20000000 / VTLB_PAGE_SIZE; - static const uint VTLB_PMAP_SZ = 0x20000000; - static const uint VTLB_VMAP_ITEMS = 0x100000000ULL / VTLB_PAGE_SIZE; + static const uint VTLB_PMAP_ITEMS = _256mb / VTLB_PAGE_SIZE; + static const uint VTLB_PMAP_SZ = _256mb; + static const uint VTLB_VMAP_ITEMS = _4gb / VTLB_PAGE_SIZE; struct MapData { @@ -110,6 +193,8 @@ namespace vtlb_private s32* vmap; //4MB (allocated by vtlb_init) + u8* reserve_base; //base of the memory array + u8* alloc_base; //base of the memory array int alloc_current; //current base }; diff --git a/pcsx2/windows/WinSysExec.cpp b/pcsx2/windows/WinSysExec.cpp index 5d1f482fba..462515651e 100644 --- a/pcsx2/windows/WinSysExec.cpp +++ b/pcsx2/windows/WinSysExec.cpp @@ -19,17 +19,3 @@ #include "Common.h" #include "Utilities/PageFaultSource.h" - -int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps ) -{ - if( eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION ) - return EXCEPTION_CONTINUE_SEARCH; - - Source_PageFault->Dispatch( PageFaultInfo( (uptr)eps->ExceptionRecord->ExceptionInformation[1] ) ); - return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; -} - -void InstallSignalHandler() -{ - // NOP on Win32 systems -- we use __try{} __except{} instead. -} diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index d80b6416f4..ea7c0aee53 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -65,11 +65,11 @@ bool g_cpuFlushedPC, g_cpuFlushedCode, g_recompilingDelaySlot, g_maySignalExcept // -------------------------------------------------------------------------------------- class R5900LutReserve_RAM : public SpatialArrayReserve { - typedef SpatialArrayReserve __parent; + typedef SpatialArrayReserve _parent; public: R5900LutReserve_RAM( const wxString& name ) - : __parent( name ) + : _parent( name ) { } @@ -567,7 +567,7 @@ static __ri void ClearRecLUT(BASEBLOCK* base, int memsize) void R5900LutReserve_RAM::OnCommittedBlock( void* block ) { - __parent::OnCommittedBlock(block); + _parent::OnCommittedBlock(block); ClearRecLUT((BASEBLOCK*)block, __pagesize * m_blocksize); }