From 495e872e98ec45663fb7b5db21ec4b2847d43404 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Fri, 22 Oct 2010 15:05:56 +0000 Subject: [PATCH 01/22] newHostVM branch created; implementation purposes: * a mapped memory system for PS2 virtual machine areas (32mb main memory, 2mb IOP memory, etc) that will be constant across all builds of PCSX2 (should fix problems with 3rdparty cheat apps) * virtual reservation system for recompilers; reduces the emulator's overall memory usage while reducing the need for recompiler resets at the same time. * recompiler resets (if/when needed) should be much faster. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@3956 96395faa-99c1-11dd-bbfe-3dabce05a288 From 01541f2c928b0d33207ee41fa42fafeb153d5cf4 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Fri, 22 Oct 2010 16:23:52 +0000 Subject: [PATCH 02/22] newHostVM branch: work-in-progress stuff... git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@3958 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/include/Utilities/General.h | 96 ++++++- common/src/Utilities/Linux/LnxHostSys.cpp | 130 +++++++--- common/src/Utilities/Windows/WinHostSys.cpp | 105 +++++--- common/src/Utilities/wxAppWithHelpers.cpp | 2 +- common/src/x86emitter/cpudetect.cpp | 8 +- pcsx2/CDVD/IsoFileFormats.cpp | 2 +- pcsx2/Interpreter.cpp | 19 +- pcsx2/Memory.cpp | 31 +-- pcsx2/Memory.h | 4 + pcsx2/MemoryTypes.h | 8 +- pcsx2/PrecompiledHeader.h | 6 + pcsx2/R3000A.h | 7 +- pcsx2/R3000AInterpreter.cpp | 6 +- pcsx2/R5900.h | 30 +-- pcsx2/SaveState.cpp | 4 +- pcsx2/System.cpp | 264 +++++++++++++++++++- pcsx2/System.h | 36 +++ pcsx2/System/PageFaultSource.h | 90 +++++++ pcsx2/VUmicro.h | 8 + pcsx2/gui/App.h | 1 + pcsx2/gui/Dialogs/GameDatabaseDialog.cpp | 2 - pcsx2/gui/MainFrame.cpp | 4 +- pcsx2/gui/MainFrame.h | 1 + pcsx2/gui/MainMenuClicks.cpp | 5 + pcsx2/gui/Panels/GameDatabasePanel.cpp | 2 +- pcsx2/ps2/LegacyDmac.cpp | 4 +- pcsx2/vtlb.cpp | 52 ++-- pcsx2/vtlb.h | 17 +- pcsx2/windows/cheats/browser.cpp | 2 +- pcsx2/windows/cheats/cheats.cpp | 2 +- pcsx2/x86/iR3000A.cpp | 50 ++-- pcsx2/x86/ix86-32/iR5900-32.cpp | 108 ++++---- pcsx2/x86/ix86-32/recVTLB.cpp | 4 +- pcsx2/x86/microVU.cpp | 4 +- pcsx2/x86/microVU.h | 2 +- pcsx2/x86/microVU_Misc.inl | 4 +- pcsx2/x86/newVif_UnpackSSE.cpp | 4 +- pcsx2/x86/sVU_zerorec.cpp | 6 +- 38 files changed, 859 insertions(+), 271 deletions(-) diff --git a/common/include/Utilities/General.h b/common/include/Utilities/General.h index 4cba92cd50..cc66993397 100644 --- a/common/include/Utilities/General.h +++ b/common/include/Utilities/General.h @@ -133,14 +133,83 @@ protected: virtual void DoDeletion(); }; - -enum PageProtectionMode +// -------------------------------------------------------------------------------------- +// PageProtectionMode +// -------------------------------------------------------------------------------------- +class PageProtectionMode { - Protect_NoAccess = 0, - Protect_ReadOnly, - Protect_ReadWrite +protected: + bool m_read; + bool m_write; + bool m_exec; + +public: + PageProtectionMode() + { + All( false ); + } + + PageProtectionMode& Read( bool allow=true ) + { + m_read = allow; + return *this; + } + + PageProtectionMode& Write( bool allow=true ) + { + m_write = allow; + return *this; + } + + PageProtectionMode& Execute( bool allow=true ) + { + m_exec = allow; + return *this; + } + + PageProtectionMode& All( bool allow=true ) + { + m_read = m_write = m_exec = allow; + return *this; + } + + bool CanRead() const { return m_read; } + bool CanWrite() const { return m_write; } + bool CanExecute() const { return m_exec && m_read; } + + wxString ToString() const; }; +static __fi PageProtectionMode PageAccess_None() +{ + return PageProtectionMode(); +} + +static __fi PageProtectionMode PageAccess_ReadOnly() +{ + return PageProtectionMode().Read(); +} + +static __fi PageProtectionMode PageAccess_WriteOnly() +{ + return PageProtectionMode().Write(); +} + +static __fi PageProtectionMode PageAccess_ReadWrite() +{ + return PageAccess_ReadOnly().Write(); +} + +static __fi PageProtectionMode PageAccess_ExecOnly() +{ + return PageAccess_ReadOnly().Execute(); +} + +static __fi PageProtectionMode PageAccess_Any() +{ + return PageProtectionMode().All(); +} + // -------------------------------------------------------------------------------------- // HostSys // -------------------------------------------------------------------------------------- @@ -148,22 +217,25 @@ enum PageProtectionMode // platform prior to wxWidgets .. it should prolly be removed -- air) namespace HostSys { + void* MmapReserve(uptr base, size_t size); + void MmapCommit(void* base, size_t size); + void MmapReset(void* base, size_t size); + // Maps a block of memory for use as a recompiled code buffer. - // The allocated block has code execution privileges. // Returns NULL on allocation failure. - extern void *Mmap(uptr base, u32 size); + extern void* Mmap(uptr base, size_t size); // Unmaps a block allocated by SysMmap - extern void Munmap(uptr base, u32 size); + extern void Munmap(uptr base, size_t size); - extern void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution=false ); + extern void MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode ); - extern void Munmap( void* base, u32 size ); + extern void Munmap( void* base, size_t size ); template< uint size > - void MemProtectStatic( u8 (&arr)[size], PageProtectionMode mode, bool allowExecution=false ) + void MemProtectStatic( u8 (&arr)[size], const PageProtectionMode& mode ) { - MemProtect( arr, size, mode, allowExecution ); + MemProtect( arr, size, mode ); } } diff --git a/common/src/Utilities/Linux/LnxHostSys.cpp b/common/src/Utilities/Linux/LnxHostSys.cpp index e55e4941c8..a453b03e8f 100644 --- a/common/src/Utilities/Linux/LnxHostSys.cpp +++ b/common/src/Utilities/Linux/LnxHostSys.cpp @@ -19,46 +19,104 @@ #include #include -namespace HostSys +static __ri void PageSizeAssertionTest( size_t size ) { - static const uptr m_pagemask = getpagesize()-1; + pxAssert( (__pagesize == getpagesize()), pxsFmt( + "Internal system error: Operating system pagesize does not match compiled pagesize.\n\t" + L"\tOS Page Size: 0x%x (%d), Compiled Page Size: 0x%x (%u)", + getpagesize(), getpagesize(), __pagesize, __pagesize ) + ); - void *Mmap(uptr base, u32 size) + pxAssertDev( (size & (__pagesize-1)) == 0, pxsFmt( + L"Memory block size must be a multiple of the target platform's page size.\n" + L"\tPage Size: 0x%x (%u), Block Size: 0x%x (%u)", + __pagesize, __pagesize, size, size ) + ); +} + +void* HostSys::MmapReserve(uptr base, size_t size) +{ + PageSizeAssertionTest(size); + + // On linux a reserve-without-commit is performed by using mmap on a read-only + // or anonymous source, with PROT_NONE (no-access) permission. Since the mapping + // is completely inaccessible, the OS will simply reserve it and will not put it + // against the commit table. + return mmap((void*)base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +} + +void HostSys::MmapCommit(void* base, size_t size) +{ + // In linux, reserved memory is automatically committed when its permissions are + // changed to something other than PROT_NONE. Since PCSX2 code *must* do that itself + // prior to making use of memory anyway, this call should be a NOP. +} + +void HostSys::MmapReset(void* base, size_t size) +{ + // On linux the only way to reset the memory is to unmap and remap it as PROT_NONE. + // That forces linux to unload all committed pages and start from scratch. + + // FIXME: Ideally this code would have some threading lock on it to prevent any other + // malloc/free code in the current process from interfering with the operation, but I + // can't think of any good way to do that. (generally it shouldn't be a problem in + // PCSX2 anyway, since MmapReset is only called when the ps2vm is suspended; so that + // pretty well stops all PCSX2 threads anyway). + + Munmap(base, size); + void* result = Mmap(base, size); + + pxAssertRel (result != base, pxsFmt( + "Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped. " + "This is likely caused by multi-thread memory contention.", base, base+size + )); +} + +void* HostSys::Mmap(void* base, size_t size) +{ + PageSizeAssertionTest(size); + + // MAP_ANONYMOUS - means we have no associated file handle (or device). + + return mmap(base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +} + +void HostSys::Munmap(void* base, size_t size) +{ + munmap(base, size); +} + +void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode ) +{ + PageSizeAssertionTest(size); + + uint lnxmode = 0; + + if (mode.CanWrite()) lnxmode |= PROT_WRITE; + if (mode.CanRead()) lnxmode |= PROT_READ; + if (mode.CanExecute()) lnxmode |= PROT_EXEC | PROT_READ; + + int result = mprotect( baseaddr, size, lnxmode ); + + if (!result) { - u8 *Mem; - Mem = (u8*)mmap((uptr*)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - if (Mem == MAP_FAILED) Console.Warning("Mmap Failed!"); - - return Mem; - } - - void Munmap(uptr base, u32 size) - { - munmap((uptr*)base, size); - } - - void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution ) - { - pxAssertDev( (size & (__pagesize-1)) == 0, wxsFormat( - L"Memory block size must be a multiple of the target platform's page size.\n" - L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)", - __pagesize, __pagesize, size, size ) - ); - - int lnxmode = 0; - - // make sure size is aligned to the system page size: - // Check is redundant against the assertion above, but might as well... - size = (size + m_pagemask) & ~m_pagemask; - - switch( mode ) + switch(errno) { - case Protect_NoAccess: break; - case Protect_ReadOnly: lnxmode = PROT_READ; break; - case Protect_ReadWrite: lnxmode = PROT_READ | PROT_WRITE; break; + case EINVAL: + pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)"), + baseaddr, (uptr)baseaddr+size, mode.ToString().c_str() + ); + break; + + case ENOMEM: + throw Exception::OutOfMemory( psxFmt( L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)"), + baseaddr, (uptr)baseaddr+size, mode.ToString().c_str() + ); + break; + + case EACCES: + break; } - - if( allowExecution ) lnxmode |= PROT_EXEC; - mprotect( baseaddr, size, lnxmode ); + throw Exception::OutOfMemory() } } diff --git a/common/src/Utilities/Windows/WinHostSys.cpp b/common/src/Utilities/Windows/WinHostSys.cpp index 1f37b36bd3..0759d2406a 100644 --- a/common/src/Utilities/Windows/WinHostSys.cpp +++ b/common/src/Utilities/Windows/WinHostSys.cpp @@ -17,46 +17,81 @@ #include "Utilities/RedtapeWindows.h" #include -namespace HostSys +void* HostSys::MmapReserve(uptr base, size_t size) { - void *Mmap(uptr base, u32 size) + return VirtualAlloc((void*)base, size, MEM_RESERVE, PAGE_NOACCESS); +} + +void HostSys::MmapCommit(void* base, size_t size) +{ + // Execution flag for this and the Reserve should match... ? + void* result = VirtualAlloc(base, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + pxAssumeDev(result, L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows()); +} + +void HostSys::MmapReset(void* base, size_t size) +{ + // Execution flag is actually irrelevant for this operation, but whatever. + //void* result = VirtualAlloc((void*)base, size, MEM_RESET, PAGE_EXECUTE_READWRITE); + //pxAssumeDev(result, L"VirtualAlloc RESET failed: " + Exception::WinApiError().GetMsgFromWindows()); + + VirtualFree(base, size, MEM_DECOMMIT); +} + +void* HostSys::Mmap(uptr base, size_t size) +{ + return VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); +} + +void HostSys::Munmap(uptr base, size_t size) +{ + if (!base) return; + VirtualFree((void*)base, size, MEM_DECOMMIT); + VirtualFree((void*)base, 0, MEM_RELEASE); +} + +void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode ) +{ + pxAssertDev( ((size & (__pagesize-1)) == 0), wxsFormat( + L"Memory block size must be a multiple of the target platform's page size.\n" + L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)", + __pagesize, __pagesize, size, size ) + ); + + DWORD winmode = PAGE_NOACCESS; + + // Windows has some really bizarre memory protection enumeration that uses bitwise + // numbering (like flags) but is in fact not a flag value. *Someone* from the early + // microsoft days wasn't a very good coder, me thinks. --air + + if (mode.CanExecute()) { - return VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ; } - - void Munmap(uptr base, u32 size) + else if (mode.CanRead()) { - if( base == NULL ) return; - VirtualFree((void*)base, size, MEM_DECOMMIT); - VirtualFree((void*)base, 0, MEM_RELEASE); + winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY; } - - void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution ) + + DWORD OldProtect; // enjoy my uselessness, yo! + if (!VirtualProtect( baseaddr, size, winmode, &OldProtect )) { - pxAssertDev( ((size & (__pagesize-1)) == 0), wxsFormat( - L"Memory block size must be a multiple of the target platform's page size.\n" - L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)", - __pagesize, __pagesize, size, size ) - ); - - DWORD winmode = 0; - - switch( mode ) - { - case Protect_NoAccess: - winmode = ( allowExecution ) ? PAGE_EXECUTE : PAGE_NOACCESS; - break; - - case Protect_ReadOnly: - winmode = ( allowExecution ) ? PAGE_EXECUTE_READ : PAGE_READONLY; - break; - - case Protect_ReadWrite: - winmode = ( allowExecution ) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; - break; - } - - DWORD OldProtect; // enjoy my uselessness, yo! - VirtualProtect( baseaddr, size, winmode, &OldProtect ); + throw Exception::WinApiError().SetDiagMsg( + pxsFmt(L"VirtualProtect failed @ 0x%08X -> 0x%08X (mode=%s)", + baseaddr, (uptr)baseaddr + size, mode.ToString().c_str() + )); } } + +wxString PageProtectionMode::ToString() const +{ + wxString modeStr; + + if (m_read) modeStr += L"Read"; + if (m_write) modeStr += L"Write"; + if (m_exec) modeStr += L"Exec"; + + if (modeStr.Length() <= 5) modeStr += L"Only"; + + return modeStr; +} diff --git a/common/src/Utilities/wxAppWithHelpers.cpp b/common/src/Utilities/wxAppWithHelpers.cpp index 8a1b28f9ac..7821454cb5 100644 --- a/common/src/Utilities/wxAppWithHelpers.cpp +++ b/common/src/Utilities/wxAppWithHelpers.cpp @@ -675,7 +675,7 @@ void wxAppWithHelpers::OnDeleteThread( wxCommandEvent& evt ) return; } - pxThreadLog.Write(thr->GetName(), (wxString)L"Thread object deleted successfully" + (thr->HasPendingException() ? wxEmptyString : L"[exception pending!]")); + pxThreadLog.Write(thr->GetName(), (wxString)L"Thread object deleted successfully" + (thr->HasPendingException() ? L" [exception pending!]" : wxEmptyString)); thr->RethrowException(); } diff --git a/common/src/x86emitter/cpudetect.cpp b/common/src/x86emitter/cpudetect.cpp index 7fd0bf46d7..95928cf85b 100644 --- a/common/src/x86emitter/cpudetect.cpp +++ b/common/src/x86emitter/cpudetect.cpp @@ -59,13 +59,13 @@ void x86capabilities::SIMD_EstablishMXCSRmask() // the fxsave buffer must be 16-byte aligned to avoid GPF. I just save it to an // unused portion of recSSE, since it has plenty of room to spare. - HostSys::MemProtectStatic( recSSE, Protect_ReadWrite, true ); + HostSys::MemProtectStatic( recSSE, PageAccess_ReadWrite() ); xSetPtr( recSSE ); xFXSAVE( ptr[&targetFXSAVE] ); xRET(); - HostSys::MemProtectStatic( recSSE, Protect_ReadOnly, true ); + HostSys::MemProtectStatic( recSSE, PageAccess_ExecOnly() ); CallAddress( recSSE ); @@ -310,7 +310,7 @@ u32 x86capabilities::CalculateMHz() const // Results of CPU void x86capabilities::SIMD_ExceptionTest() { - HostSys::MemProtectStatic( recSSE, Protect_ReadWrite, true ); + HostSys::MemProtectStatic( recSSE, PageAccess_ReadWrite() ); ////////////////////////////////////////////////////////////////////////////////////////// // SIMD Instruction Support Detection (Second Pass) @@ -336,7 +336,7 @@ void x86capabilities::SIMD_ExceptionTest() xMOVDQU( xmm1, ptr[ecx] ); xRET(); - HostSys::MemProtectStatic( recSSE, Protect_ReadOnly, true ); + HostSys::MemProtectStatic( recSSE, PageAccess_ExecOnly() ); bool sse3_result = _test_instruction( recSSE ); // sse3 bool ssse3_result = _test_instruction( funcSSSE3 ); diff --git a/pcsx2/CDVD/IsoFileFormats.cpp b/pcsx2/CDVD/IsoFileFormats.cpp index 140913b9a2..540cf2f55a 100644 --- a/pcsx2/CDVD/IsoFileFormats.cpp +++ b/pcsx2/CDVD/IsoFileFormats.cpp @@ -245,7 +245,7 @@ void isoFile::_WriteBlock(const u8* src, uint lsn) void isoFile::_WriteBlockD(const u8* src, uint lsn) { // Find and ignore blocks that have already been dumped: - for (uint i=0; iMain, 0x00000000,Ps2MemSize::Base);//mirrored on first 256 mb ? + vtlb_MapBlock(eeMem->Main, 0x00000000,Ps2MemSize::MainRam);//mirrored on first 256 mb ? // High memory, uninstalled on the configuration we emulate - vtlb_MapHandler(null_handler, Ps2MemSize::Base, 0x10000000 - Ps2MemSize::Base); + vtlb_MapHandler(null_handler, Ps2MemSize::MainRam, 0x10000000 - Ps2MemSize::MainRam); // Various ROMs (all read-only) vtlb_MapBlock(eeMem->ROM, 0x1fc00000,Ps2MemSize::Rom); @@ -796,15 +796,17 @@ enum vtlb_ProtectionMode struct vtlb_PageProtectionInfo { - // Ram De-mapping -- used to convert fully translated/mapped offsets into psM back - // into their originating ps2 physical ram address. Values are assigned when pages - // are marked for protection. + // Ram De-mapping -- used to convert fully translated/mapped offsets (which reside with + // in the eeMem->Main block) back into their originating ps2 physical ram address. + // Values are assigned when pages are marked for protection. since pages are automatically + // cleared and reset when TLB-remapped, stale values in this table (due to on-the-fly TLB + // changes) will be re-assigned the next time the page is accessed. u32 ReverseRamMap; vtlb_ProtectionMode Mode; }; -static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::Base >> 12]; +static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::MainRam >> 12]; // returns: @@ -820,14 +822,14 @@ int mmap_GetRamPageInfo( u32 paddr ) uptr ptr = (uptr)PSM( paddr ); uptr rampage = ptr - (uptr)eeMem->Main; - if (rampage >= Ps2MemSize::Base) + if (rampage >= Ps2MemSize::MainRam) return -1; //not in ram, no tracking done ... rampage >>= 12; return ( m_PageProtectInfo[rampage].Mode == ProtMode_Manual ) ? 1 : 0; } -// paddr - physically mapped address +// paddr - physically mapped PS2 address void mmap_MarkCountedRamPage( u32 paddr ) { paddr &= ~0xfff; @@ -835,8 +837,9 @@ void mmap_MarkCountedRamPage( u32 paddr ) uptr ptr = (uptr)PSM( paddr ); int rampage = (ptr - (uptr)eeMem->Main) >> 12; - // Important: reassign paddr here, since TLB changes could alter the paddr->psM mapping - // (and clear blocks accordingly), but don't necessarily clear the protection status. + // Important: Update the ReverseRamMap here because TLB changes could alter the paddr + // mapping into eeMem->Main. + m_PageProtectInfo[rampage].ReverseRamMap = paddr; if( m_PageProtectInfo[rampage].Mode == ProtMode_Write ) @@ -848,7 +851,7 @@ void mmap_MarkCountedRamPage( u32 paddr ) ); m_PageProtectInfo[rampage].Mode = ProtMode_Write; - HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, Protect_ReadOnly ); + HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, PageAccess_ReadOnly() ); } // offset - offset of address relative to psM. @@ -863,7 +866,7 @@ static __fi void mmap_ClearCpuBlock( uint offset ) pxAssertMsg( m_PageProtectInfo[rampage].Mode != ProtMode_Manual, "Attempted to clear a block that is already under manual protection." ); - HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, Protect_ReadWrite ); + HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, PageAccess_ReadWrite() ); m_PageProtectInfo[rampage].Mode = ProtMode_Manual; Cpu->Clear( m_PageProtectInfo[rampage].ReverseRamMap, 0x400 ); } @@ -872,7 +875,7 @@ void mmap_PageFaultHandler::OnPageFaultEvent( const PageFaultInfo& info, bool& h { // get bad virtual address uptr offset = info.addr - (uptr)eeMem->Main; - if( offset >= Ps2MemSize::Base ) return; + if( offset >= Ps2MemSize::MainRam ) return; mmap_ClearCpuBlock( offset ); handled = true; @@ -886,5 +889,5 @@ void mmap_ResetBlockTracking() { //DbgCon.WriteLn( "vtlb/mmap: Block Tracking reset..." ); memzero( m_PageProtectInfo ); - HostSys::MemProtect( eeMem->Main, Ps2MemSize::Base, Protect_ReadWrite ); + HostSys::MemProtect( eeMem->Main, Ps2MemSize::MainRam, PageAccess_ReadWrite() ); } diff --git a/pcsx2/Memory.h b/pcsx2/Memory.h index 7a325e1aec..5deee6be22 100644 --- a/pcsx2/Memory.h +++ b/pcsx2/Memory.h @@ -24,6 +24,10 @@ #include +// [TODO] This *could* be replaced with an assignment operator on u128 that implicitly +// uses _mm_store and _mm_load internally. However, there are alignment concerns -- +// u128 is not alignment strict. (we would need a u128 and u128a for types known to +// be strictly 128-bit aligned). static __fi void CopyQWC( void* dest, const void* src ) { _mm_store_ps( (float*)dest, _mm_load_ps((const float*)src) ); diff --git a/pcsx2/MemoryTypes.h b/pcsx2/MemoryTypes.h index 3ae0c42638..db1b6b4a70 100644 --- a/pcsx2/MemoryTypes.h +++ b/pcsx2/MemoryTypes.h @@ -17,7 +17,7 @@ namespace Ps2MemSize { - static const uint Base = 0x02000000; // 32 MB main memory! + 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 (?) @@ -61,9 +61,9 @@ typedef u128 mem128_t; // full breadth of PS2 RAM and ROM mappings are directly supported. struct EEVM_MemoryAllocMess { - u8 (&Main)[Ps2MemSize::Base]; // Main memory (hard-wired to 32MB) + u8 (&Main)[Ps2MemSize::MainRam]; // Main memory (hard-wired to 32MB) - u8 _padding1[0x1e000000-Ps2MemSize::Base] + u8 _padding1[0x1e000000-Ps2MemSize::MainRam] u8 (&ROM1)[Ps2MemSize::Rom1]; // DVD player u8 _padding2[0x1e040000-(0x1e000000+Ps2MemSize::Rom1)] @@ -80,8 +80,8 @@ struct EEVM_MemoryAllocMess struct EEVM_MemoryAllocMess { + u8 Main[Ps2MemSize::MainRam]; // Main memory (hard-wired to 32MB) u8 Scratch[Ps2MemSize::Scratch]; // Scratchpad! - u8 Main[Ps2MemSize::Base]; // Main memory (hard-wired to 32MB) u8 ROM[Ps2MemSize::Rom]; // Boot rom (4MB) u8 ROM1[Ps2MemSize::Rom1]; // DVD player u8 ROM2[Ps2MemSize::Rom2]; // Chinese extensions diff --git a/pcsx2/PrecompiledHeader.h b/pcsx2/PrecompiledHeader.h index c8bdcffc83..e24bcfc556 100644 --- a/pcsx2/PrecompiledHeader.h +++ b/pcsx2/PrecompiledHeader.h @@ -102,9 +102,15 @@ 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; diff --git a/pcsx2/R3000A.h b/pcsx2/R3000A.h index 62b6e6af71..b384a17253 100644 --- a/pcsx2/R3000A.h +++ b/pcsx2/R3000A.h @@ -178,11 +178,12 @@ extern bool iopEventTestIsActive; // Branching status used when throwing exceptions. extern bool iopIsDelaySlot; -//////////////////////////////////////////////////////////////////// -// R3000A Public Interface / API +// -------------------------------------------------------------------------------------- +// R3000Acpu +// -------------------------------------------------------------------------------------- struct R3000Acpu { - void (*Allocate)(); + void (*Reserve)(); void (*Reset)(); void (*Execute)(); s32 (*ExecuteBlock)( s32 eeCycles ); // executes the given number of EE cycles. diff --git a/pcsx2/R3000AInterpreter.cpp b/pcsx2/R3000AInterpreter.cpp index 106ae9ed8c..dcf6dd1698 100644 --- a/pcsx2/R3000AInterpreter.cpp +++ b/pcsx2/R3000AInterpreter.cpp @@ -150,10 +150,14 @@ static void doBranch(s32 tar) { iopEventTest(); } +static void intReserve() { +} + static void intAlloc() { } static void intReset() { + intAlloc(); } static void intExecute() { @@ -181,7 +185,7 @@ static void intShutdown() { } R3000Acpu psxInt = { - intAlloc, + intReserve, intReset, intExecute, intExecuteBlock, diff --git a/pcsx2/R5900.h b/pcsx2/R5900.h index d865a3b2a8..fa67c562e1 100644 --- a/pcsx2/R5900.h +++ b/pcsx2/R5900.h @@ -273,25 +273,25 @@ extern void __fastcall eeloadReplaceOSDSYS(); struct R5900cpu { // Memory allocation function, for allocating virtual memory spaces needed by - // the emulator. (ints/recs are free to allocate additional memory while running - // code, however any virtual mapped memory should always be allocated as soon - // as possible, to claim the memory before some plugin does..) - // + // the virtual cpu provider. Allocating additional heap memory from this method is + // NOT recommended. Heap allocations should be performed by Reset only. This + // maximizes the likeliness of reservations claiming addresses they prefer. + // // Thread Affinity: - // Can be called from any thread. Execute status must be suspended or stopped - // to prevent multi-thread race conditions. + // Called from the main/UI thread only. Cpu execution status is guaranteed to + // be inactive. No locking is necessary. // // Exception Throws: + // HardwareDeficiency - The host machine's hardware does not support this CPU provider. // OutOfMemory - Not enough memory, or the memory areas required were already // reserved. - // - void (*Allocate)(); + void (*Reserve)(); - // Deallocates ram allocated by Allocate and/or by runtime code execution. + // Deallocates ram allocated by Allocate, Reserve, and/or by runtime code execution. // // Thread Affinity: - // Can be called from any thread. Execute status must be suspended or stopped - // to prevent multi-thread race conditions. + // Called from the main/UI thread only. Cpu execution status is guaranteed to + // be inactive. No locking is necessary. // // Exception Throws: None. This function is a destructor, and should not throw. // @@ -302,8 +302,10 @@ struct R5900cpu // rely on the CPU/VM states almost entirely. // // Thread Affinity: - // Can be called from any thread. Execute status must be suspended or stopped - // to prevent multi-thread race conditions. + // Can be called from any thread. CPU execution status is indeterminate and may + // already be in progress. Implementations should be sure to queue and execute + // resets at the earliest safe convenience (typically right before recompiling a + // new block of code, or after a vsync event). // // Exception Throws: Emulator-defined. Common exception types to expect are // OutOfMemory, Stream Exceptions @@ -365,7 +367,7 @@ struct R5900cpu // better off replaced with some generic API callbacks from VTLB block protection. // Also: the calls from COP0's TLB remap code should be replaced with full recompiler // resets, since TLB remaps affect more than just the code they contain (code that - // may reference the remaped blocks via memory loads/stores, for example). + // may reference the remapped blocks via memory loads/stores, for example). // // Thread Affinity Rule: // Can be called from any thread (namely for being called from debugging threads) diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index 767830000f..411cafe84b 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -142,7 +142,7 @@ void SaveStateBase::FreezeBios() } static const int MainMemorySizeInBytes = - Ps2MemSize::Base + Ps2MemSize::Scratch + Ps2MemSize::Hardware + + Ps2MemSize::MainRam + Ps2MemSize::Scratch + Ps2MemSize::Hardware + Ps2MemSize::IopRam + Ps2MemSize::IopHardware + 0x0100; void SaveStateBase::FreezeMainMemory() @@ -152,7 +152,7 @@ void SaveStateBase::FreezeMainMemory() // First Block - Memory Dumps // --------------------------- - FreezeMem(eeMem->Main, Ps2MemSize::Base); // 32 MB main memory + FreezeMem(eeMem->Main, Ps2MemSize::MainRam); // 32 MB main memory FreezeMem(eeMem->Scratch, Ps2MemSize::Scratch); // scratch pad FreezeMem(eeHw, Ps2MemSize::Hardware); // hardware memory diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index 93779a3d99..02f12fdddb 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -56,6 +56,248 @@ void SrcType_PageFault::_DispatchRaw( ListenerIterator iter, const ListenerItera } 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 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) + { + HostSys::MmapCommit(m_baseptr, m_def_commit*__pagesize); + HostSys::MemProtect(m_baseptr, m_def_commit*__pagesize, m_prot_mode); + } + + 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 +__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( block, m_block_size * __pagesize ); + } +} + +void RecompiledCodeReserve::OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled ) +{ + // 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->Reset(); + + //CpuVU1->SetCacheReserve( (CpuVU1->GetCacheReserve() * 3) / 2 ); + CpuVU1->Reset(); + + //psxCpu->SetCacheReserve( (psxCpu->GetCacheReserve() * 3) / 2 ); + psxCpu->Reset(); + + // 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 + // exceeded the threshold buffer, and reset the buffer on its own. + + // Note: We attempt to commit multiple pages first, since a single block of recompiled + // code can pretty easily surpass 4k. We should have enough for this, since we just + // cleared the other rec caches above -- but who knows what could happen if the user + // has another process sucking up RAM or if the operating system is fickle. If even + // that fails, give up and kill the process. + + try + { + uint cusion = std::min( m_block_size, 4 ); + HostSys::MmapCommit((u8*)blockptr, cusion * __pagesize); + HostSys::MemProtect((u8*)blockptr, cusion * __pagesize, m_prot_mode); + + handled = true; + } + catch (Exception::BaseException&) + { + // Fickle has become our reality. By setting handled to FALSE, the OS should kill + // the process for us. No point trying to log anything; this is a super-awesomely + // serious condition that likely means the system is hosed. ;) + + handled = false; + } +} #if _MSC_VER # include "svnrev.h" @@ -306,27 +548,27 @@ SysAllocVM::~SysAllocVM() throw() // -------------------------------------------------------------------------------------- SysCpuProviderPack::SysCpuProviderPack() { - Console.WriteLn( "Allocating memory for recompilers..." ); + Console.WriteLn( "Reserving memory for recompilers..." ); CpuProviders = new CpuInitializerSet(); try { - recCpu.Allocate(); + recCpu.Reserve(); } catch( Exception::RuntimeError& ex ) { m_RecExceptionEE = ex.Clone(); - Console.Error( L"EE Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() ); + Console.Error( L"EE Recompiler Reservation Failed:\n" + ex.FormatDiagnosticMessage() ); recCpu.Shutdown(); } try { - psxRec.Allocate(); + psxRec.Reserve(); } catch( Exception::RuntimeError& ex ) { m_RecExceptionIOP = ex.Clone(); - Console.Error( L"IOP Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() ); + Console.Error( L"IOP Recompiler Reservation Failed:\n" + ex.FormatDiagnosticMessage() ); psxRec.Shutdown(); } @@ -424,9 +666,11 @@ void SysClearExecutionCache() Cpu->Reset(); psxCpu->Reset(); - // mVU's VU0 needs to be properly initialised for macro mode even if it's not used for micro mode! + + // mVU's VU0 needs to be properly initialized for macro mode even if it's not used for micro mode! if (CHECK_EEREC) ((BaseVUmicroCPU*)GetCpuProviders().CpuProviders->microVU0)->Reset(); + CpuVU0->Reset(); CpuVU1->Reset(); @@ -448,15 +692,13 @@ u8* SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller) { DbgCon.Warning( "First try failed allocating %s at address 0x%x", caller, base ); - // memory allocation *must* have the top bit clear, so let's try again - // with NULL (let the OS pick something for us). - + // Let's try again at an OS-picked memory area, and then hope it meets needed + // boundschecking criteria below. SafeSysMunmap( Mem, size ); - Mem = (u8*)HostSys::Mmap( NULL, size ); } - if( bounds != 0 && (((uptr)Mem + size) > bounds) ) + if( (bounds != 0) && (((uptr)Mem + size) > bounds) ) { DevCon.Warning( "Second try failed allocating %s, block ptr 0x%x does not meet required criteria.", caller, Mem ); SafeSysMunmap( Mem, size ); diff --git a/pcsx2/System.h b/pcsx2/System.h index 1df237c4ba..ac81209ace 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -24,6 +24,42 @@ typedef SafeArray VmStateBuffer; class BaseVUmicroCPU; + +// This is a table of default virtual map addresses for ps2vm components. These locations +// are provided and used to assist in debugging and possibly hacking; as it makes it possible +// for a programmer to know exactly where to look (consistently!) for the base address of +// the various virtual machine components. These addresses can be keyed directly into the +// debugger's disasm window to get disassembl 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) + static const uptr sVUrec = 0x0f1e0000; + + // PS2 main memory, SPR, and ROMs + static const uptr EEmem = 0x20000000; + + // IOP main memory and ROMs + static const uptr IOPmem = 0x28000000; + + // EE recompiler code cache area (64mb) + static const uptr EErec = 0x30000000; + + // IOP recompiler code cache area (16 or 32mb) + static const uptr IOPrec = 0x34000000; + + // microVU1 recompiler code cache area (64mb) + static const uptr mVU0rec = 0x38000000; + + // microVU0 recompiler code cache area (64mb) + static const uptr mVU1rec = 0x40000000; +} + // -------------------------------------------------------------------------------------- // SysAllocVM // -------------------------------------------------------------------------------------- diff --git a/pcsx2/System/PageFaultSource.h b/pcsx2/System/PageFaultSource.h index 46fd059772..2c9bfd5628 100644 --- a/pcsx2/System/PageFaultSource.h +++ b/pcsx2/System/PageFaultSource.h @@ -58,6 +58,9 @@ protected: virtual void OnPageFaultEvent( const PageFaultInfo& evtinfo, bool& handled ) {} }; +// -------------------------------------------------------------------------------------- +// EventListener_PageFault +// -------------------------------------------------------------------------------------- class EventListener_PageFault : public IEventListener_PageFault { public: @@ -84,6 +87,92 @@ protected: virtual void _DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt ); }; +// -------------------------------------------------------------------------------------- +// BaseVirtualMemoryReserve (WIP!!) +// -------------------------------------------------------------------------------------- +class BaseVirtualMemoryReserve : public EventListener_PageFault +{ + DeclareNoncopyableObject( BaseVirtualMemoryReserve ); + +public: + wxString Name; + +protected: + void* m_baseptr; + + // reserved memory (in pages). + uptr m_reserved; + + // Incremental size by which the buffer grows (in pages) + uptr m_block_size; + + // Protection mode to be applied to committed blocks. + PageProtectionMode m_prot_mode; + + // Specifies the number of blocks that should be committed automatically when the + // reserve is created. Typically this chunk is larger than the block size, and + // should be based on whatever typical overhead is needed for basic block use. + uint m_def_commit; + + // Records the number of pages committed to memory. + // (metric for analysis of buffer usage) + uptr m_commited; + +public: + BaseVirtualMemoryReserve( const wxString& name ); + virtual ~BaseVirtualMemoryReserve() throw() + { + Free(); + } + + void* Reserve( uint size, uptr base = 0, uptr upper_bounds = 0 ); + void Reset(); + void Free(); + + uptr GetReserveSizeInBytes() const { return m_reserved * __pagesize; } + uptr GetReserveSizeInPages() const { return m_reserved; } + + u8* GetPtr() { return (u8*)m_baseptr; } + const u8* GetPtr() const { return (u8*)m_baseptr; } + + u8* GetPtrEnd() { return (u8*)m_baseptr + (m_reserved * __pagesize); } + const u8* GetPtrEnd() const { return (u8*)m_baseptr + (m_reserved * __pagesize); } + + 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 OnPageFaultEvent( const PageFaultInfo& info, bool& handled ); + + virtual void OnCommittedBlock( void* block )=0; + virtual void OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled ) + { + throw; + } +}; + +// -------------------------------------------------------------------------------------- +// RecompiledCodeReserve +// -------------------------------------------------------------------------------------- +class RecompiledCodeReserve : public BaseVirtualMemoryReserve +{ +protected: + +public: + RecompiledCodeReserve( const wxString& name, uint defCommit = 0 ); + void OnCommittedBlock( void* block ); + 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; } +}; + #ifdef __LINUX__ # define PCSX2_PAGEFAULT_PROTECT @@ -105,3 +194,4 @@ extern int SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps); extern void InstallSignalHandler(); extern SrcType_PageFault Source_PageFault; + diff --git a/pcsx2/VUmicro.h b/pcsx2/VUmicro.h index 652d9f9afc..81436cdf48 100644 --- a/pcsx2/VUmicro.h +++ b/pcsx2/VUmicro.h @@ -72,6 +72,14 @@ public: virtual const char* GetShortName() const=0; virtual wxString GetLongName() const=0; + // returns the number of bytes committed to the working caches for this CPU + // provider (typically this refers to recompiled code caches, but could also refer + // to other optional growable allocations). + virtual size_t GetCommittedCache() const + { + return 0; + } + virtual void Allocate()=0; virtual void Shutdown()=0; virtual void Reset()=0; diff --git a/pcsx2/gui/App.h b/pcsx2/gui/App.h index 7af5792be8..205b54c075 100644 --- a/pcsx2/gui/App.h +++ b/pcsx2/gui/App.h @@ -107,6 +107,7 @@ enum MenuIdentifiers MenuId_Config_SysSettings, MenuId_Config_McdSettings, MenuId_Config_AppSettings, + MenuId_Config_GameDatabase, MenuId_Config_BIOS, // Plugin ID order is important. Must match the order in tbl_PluginInfo. diff --git a/pcsx2/gui/Dialogs/GameDatabaseDialog.cpp b/pcsx2/gui/Dialogs/GameDatabaseDialog.cpp index c286e3387f..261c750630 100644 --- a/pcsx2/gui/Dialogs/GameDatabaseDialog.cpp +++ b/pcsx2/gui/Dialogs/GameDatabaseDialog.cpp @@ -21,8 +21,6 @@ Dialogs::GameDatabaseDialog::GameDatabaseDialog(wxWindow* parent) : BaseConfigurationDialog( parent, AddAppName(_("Game Database - %s")), 580 ) { ScopedBusyCursor busy( Cursor_ReallyBusy ); - *this += new Panels::GameDatabasePanel(this); - AddOkCancel(); } diff --git a/pcsx2/gui/MainFrame.cpp b/pcsx2/gui/MainFrame.cpp index 2cc10d9c37..6b6d1965f3 100644 --- a/pcsx2/gui/MainFrame.cpp +++ b/pcsx2/gui/MainFrame.cpp @@ -155,6 +155,7 @@ void MainEmuFrame::ConnectMenus() ConnectMenu( MenuId_Config_SysSettings, Menu_SysSettings_Click ); ConnectMenu( MenuId_Config_McdSettings, Menu_McdSettings_Click ); ConnectMenu( MenuId_Config_AppSettings, Menu_WindowSettings_Click ); + ConnectMenu( MenuId_Config_GameDatabase,Menu_GameDatabase_Click ); ConnectMenu( MenuId_Config_BIOS, Menu_SelectPluginsBios_Click ); ConnectMenu( MenuId_Config_ResetAll, Menu_ResetAllSettings_Click ); @@ -421,7 +422,8 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title) m_menuConfig.Append(MenuId_Config_SysSettings, _("Emulation &Settings") ); m_menuConfig.Append(MenuId_Config_McdSettings, _("&Memory cards") ); - m_menuConfig.Append(MenuId_Config_BIOS, _("&Plugin/BIOS Selector...") ); + m_menuConfig.Append(MenuId_Config_BIOS, _("&Plugin/BIOS Selector") ); + m_menuConfig.Append(MenuId_Config_GameDatabase, _("Game Database Editor") ); m_menuConfig.AppendSeparator(); m_menuConfig.Append(MenuId_Config_GS, _("&Video (GS)"), m_PluginMenuPacks[PluginId_GS]); diff --git a/pcsx2/gui/MainFrame.h b/pcsx2/gui/MainFrame.h index 6a7aeb12aa..fda813e5df 100644 --- a/pcsx2/gui/MainFrame.h +++ b/pcsx2/gui/MainFrame.h @@ -162,6 +162,7 @@ protected: void Menu_SysSettings_Click(wxCommandEvent &event); void Menu_McdSettings_Click(wxCommandEvent &event); + void Menu_GameDatabase_Click(wxCommandEvent &event); void Menu_WindowSettings_Click(wxCommandEvent &event); void Menu_GSSettings_Click(wxCommandEvent &event); void Menu_SelectPluginsBios_Click(wxCommandEvent &event); diff --git a/pcsx2/gui/MainMenuClicks.cpp b/pcsx2/gui/MainMenuClicks.cpp index 53458bb244..b4dfbb3ced 100644 --- a/pcsx2/gui/MainMenuClicks.cpp +++ b/pcsx2/gui/MainMenuClicks.cpp @@ -48,6 +48,11 @@ void MainEmuFrame::Menu_McdSettings_Click(wxCommandEvent &event) AppOpenDialog( this ); } +void MainEmuFrame::Menu_GameDatabase_Click(wxCommandEvent &event) +{ + AppOpenDialog( this ); +} + void MainEmuFrame::Menu_WindowSettings_Click(wxCommandEvent &event) { wxCommandEvent evt( pxEvt_SetSettingsPage ); diff --git a/pcsx2/gui/Panels/GameDatabasePanel.cpp b/pcsx2/gui/Panels/GameDatabasePanel.cpp index 56c72d2d1c..aee17c6b04 100644 --- a/pcsx2/gui/Panels/GameDatabasePanel.cpp +++ b/pcsx2/gui/Panels/GameDatabasePanel.cpp @@ -59,7 +59,7 @@ Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent ) gameFixes[i] = new pxCheckBox(this, EnumToString(i), wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER ); *this += Heading(_("Game Database Editor")).Bold() | StdExpand(); - *this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand(); + //*this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand(); wxFlexGridSizer& sizer1(*new wxFlexGridSizer(5, StdPadding)); sizer1.AddGrowableCol(0); diff --git a/pcsx2/ps2/LegacyDmac.cpp b/pcsx2/ps2/LegacyDmac.cpp index 7e67e49275..51e1a1db70 100644 --- a/pcsx2/ps2/LegacyDmac.cpp +++ b/pcsx2/ps2/LegacyDmac.cpp @@ -104,7 +104,7 @@ __fi tDMA_TAG *SPRdmaGetAddr(u32 addr, bool write) // FIXME: Why??? DMA uses physical addresses addr &= 0x1ffffff0; - if (addr < Ps2MemSize::Base) + if (addr < Ps2MemSize::MainRam) { return (tDMA_TAG*)&eeMem->Main[addr]; } @@ -133,7 +133,7 @@ __ri tDMA_TAG *dmaGetAddr(u32 addr, bool write) // FIXME: Why??? DMA uses physical addresses addr &= 0x1ffffff0; - if (addr < Ps2MemSize::Base) + if (addr < Ps2MemSize::MainRam) { return (tDMA_TAG*)&eeMem->Main[addr]; } diff --git a/pcsx2/vtlb.cpp b/pcsx2/vtlb.cpp index b0beb6783c..1695fd5d1e 100644 --- a/pcsx2/vtlb.cpp +++ b/pcsx2/vtlb.cpp @@ -78,9 +78,9 @@ DataType __fastcall vtlb_memRead(u32 addr) switch( DataSize ) { - case 8: return ((vtlbMemR8FP*)vtlbdata.RWFT[0][0][hand])(paddr); - case 16: return ((vtlbMemR16FP*)vtlbdata.RWFT[1][0][hand])(paddr); - case 32: return ((vtlbMemR32FP*)vtlbdata.RWFT[2][0][hand])(paddr); + case 8: return ((vtlbMemR8FP*)vtlbdata.RWFT[0][0][hand])(paddr); + case 16: return ((vtlbMemR16FP*)vtlbdata.RWFT[1][0][hand])(paddr); + case 32: return ((vtlbMemR32FP*)vtlbdata.RWFT[2][0][hand])(paddr); jNO_DEFAULT; } @@ -562,33 +562,46 @@ void vtlb_Term() } // Reserves the vtlb core allocation used by various emulation components! -// -void vtlb_Core_Alloc() +// [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*/ ) { if( vtlbdata.alloc_base != NULL ) return; vtlbdata.alloc_current = 0; + vtlbdata.alloc_base = SysMmapEx( HostMemoryMap::EEmem, VTLB_ALLOC_SIZE, 0x80000000, "Vtlb" ); -#ifdef __LINUX__ - vtlbdata.alloc_base = SysMmapEx( 0x16000000, VTLB_ALLOC_SIZE, 0x80000000, "Vtlb" ); -#else - // Win32 just needs this, since malloc always maps below 2GB. - vtlbdata.alloc_base = (u8*)_aligned_malloc( VTLB_ALLOC_SIZE, 4096 ); - if( vtlbdata.alloc_base == NULL ) - throw Exception::OutOfMemory( pxsFmt(L"PS2 mappable system ram (%u megs)", VTLB_ALLOC_SIZE / _1mb) ); +#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) ); } void vtlb_Core_Shutdown() { - if( vtlbdata.alloc_base == NULL ) return; + safe_aligned_free( vtlbdata.vmap ); -#ifdef __LINUX__ + if (!vtlbdata.alloc_base) return; + SafeSysMunmap( vtlbdata.alloc_base, VTLB_ALLOC_SIZE ); -#else + +#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 ); + //HostSys::MemProtect( vtlbdata.alloc_base, VTLB_ALLOC_SIZE, Protect_ReadWrite ); + //safe_aligned_free( vtlbdata.alloc_base ); #endif } @@ -613,9 +626,8 @@ u8* vtlb_malloc( uint size, uint align ) void vtlb_free( void* pmem, uint size ) { + 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." ); - - return; } diff --git a/pcsx2/vtlb.h b/pcsx2/vtlb.h index 5b048a384e..a80c586879 100644 --- a/pcsx2/vtlb.h +++ b/pcsx2/vtlb.h @@ -87,8 +87,8 @@ extern void vtlb_DynGenRead32_Const( u32 bits, bool sign, u32 addr_const ); namespace vtlb_private { - // Allocate enough memory for both EE and IOP memory space (IOP is roughly 2.5mb, - // so we alloc 4mb for now -- a little more than is needed). + // 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; @@ -101,16 +101,17 @@ namespace vtlb_private struct MapData { - u8* alloc_base; //base of the memory array - int alloc_current; //current base - - s32 pmap[VTLB_PMAP_ITEMS]; //512KB - s32 vmap[VTLB_VMAP_ITEMS]; //4MB - // first indexer -- 8/16/32/64/128 bit tables [values 0-4] // second indexer -- read/write [0 or 1] // third indexer -- 128 possible handlers! void* RWFT[5][2][128]; + + s32 pmap[VTLB_PMAP_ITEMS]; //512KB + + s32* vmap; //4MB (allocated by vtlb_init) + + u8* alloc_base; //base of the memory array + int alloc_current; //current base }; extern __aligned(64) MapData vtlbdata; diff --git a/pcsx2/windows/cheats/browser.cpp b/pcsx2/windows/cheats/browser.cpp index 47454a17ef..3024ec0b13 100644 --- a/pcsx2/windows/cheats/browser.cpp +++ b/pcsx2/windows/cheats/browser.cpp @@ -1083,7 +1083,7 @@ BOOL CALLBACK BrowserProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) case IDC_SKIPMPEG: { u8 *p = eeMem->Main; - u8 *d = p + Ps2MemSize::Base; + u8 *d = p + Ps2MemSize::MainRam; d -= 16; u32 *u; diff --git a/pcsx2/windows/cheats/cheats.cpp b/pcsx2/windows/cheats/cheats.cpp index 070e3dfe54..3446fe3d06 100644 --- a/pcsx2/windows/cheats/cheats.cpp +++ b/pcsx2/windows/cheats/cheats.cpp @@ -59,7 +59,7 @@ bool FirstSearch; bool FirstShow; -char olds[Ps2MemSize::Base]; +char olds[Ps2MemSize::MainRam]; char tn[100]; char to[100]; diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp index 41f836ca56..8b1fb383dc 100644 --- a/pcsx2/x86/iR3000A.cpp +++ b/pcsx2/x86/iR3000A.cpp @@ -22,6 +22,7 @@ #include "iR3000A.h" #include "BaseblockEx.h" +#include "PageFaultSource.h" #include @@ -50,13 +51,8 @@ uptr psxhwLUT[0x10000]; #define HWADDR(mem) (psxhwLUT[mem >> 16] + (mem)) -#define MAPBASE 0x48000000 -#define RECMEM_SIZE (8*1024*1024) +static RecompiledCodeReserve recMem(L"R3000A recompiled code cache", _1mb * 2); -// R3000A statics -int psxreclog = 0; - -static u8 *recMem = NULL; // the recompiled blocks will be here static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here static BASEBLOCK *recROM = NULL; // and here static BASEBLOCK *recROM1 = NULL; // also here @@ -346,7 +342,7 @@ static DynGenFunc* _DynGen_EnterRecompiledCode() static void _DynGen_Dispatchers() { // In case init gets called multiple times: - HostSys::MemProtectStatic( iopRecDispatchers, Protect_ReadWrite, false ); + HostSys::MemProtectStatic( iopRecDispatchers, PageAccess_ReadWrite() ); // clear the buffer to 0xcc (easier debugging). memset_8<0xcc,__pagesize>( iopRecDispatchers ); @@ -363,7 +359,7 @@ static void _DynGen_Dispatchers() iopJITCompileInBlock = _DynGen_JITCompileInBlock(); iopEnterRecompiledCode = _DynGen_EnterRecompiledCode(); - HostSys::MemProtectStatic( iopRecDispatchers, Protect_ReadOnly, true ); + HostSys::MemProtectStatic( iopRecDispatchers, PageAccess_ExecOnly() ); recBlocks.SetJITCompile( iopJITCompile ); } @@ -759,18 +755,13 @@ static u8* m_recBlockAlloc = NULL; static const uint m_recBlockAllocSize = (((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK)); +static void recReserve() +{ + recMem.Reserve( _16mb, HostMemoryMap::IOPrec ); +} + static void recAlloc() { - // Note: the VUrec depends on being able to grab an allocation below the 0x10000000 line, - // so we give the EErec an address above that to try first as it's basemem address, hence - // the 0x28000000 pick (0x20000000 is picked by the EE) - - if( recMem == NULL ) - recMem = (u8*)SysMmapEx( 0x28000000, RECMEM_SIZE, 0, "recAlloc(R3000a)" ); - - if( recMem == NULL ) - throw Exception::OutOfMemory( L"R3000A recompiled code cache" ); - // Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory. // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are // always 4 bytes long). @@ -795,19 +786,17 @@ static void recAlloc() if( s_pInstCache == NULL ) throw Exception::OutOfMemory( L"R3000 InstCache." ); - ProfilerRegisterSource( "IOP Rec", recMem, RECMEM_SIZE ); + ProfilerRegisterSource( "IOP Rec", recMem, recMem.GetReserveSizeInBytes() ); _DynGen_Dispatchers(); } void recResetIOP() { - // calling recResetIOP without first calling recInit is bad mojo. - pxAssert( recMem != NULL ); - pxAssert( m_recBlockAlloc != NULL ); + recAlloc(); + recMem.Reset(); DevCon.WriteLn( "iR3000A Recompiler reset." ); - memset_8<0xcc,RECMEM_SIZE>( recMem ); // 0xcc is INT3 iopClearRecLUT((BASEBLOCK*)m_recBlockAlloc, (((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4))); @@ -854,8 +843,8 @@ void recResetIOP() static void recShutdown() { ProfilerTerminateSource( "IOPRec" ); + recMem.Free(); - SafeSysMunmap(recMem, RECMEM_SIZE); safe_aligned_free( m_recBlockAlloc ); safe_free( s_pInstCache ); @@ -1202,8 +1191,9 @@ static void __fastcall iopRecRecompile( const u32 startpc ) pxAssert( startpc ); // if recPtr reached the mem limit reset whole mem - if (((uptr)recPtr - (uptr)recMem) >= (RECMEM_SIZE - 0x10000)) + if (recPtr >= (recMem.GetPtrEnd() - _64kb)) { recResetIOP(); + } x86SetPtr( recPtr ); x86Align(16); @@ -1390,12 +1380,12 @@ StartRecomp: } } - pxAssert( x86Ptr < recMem+RECMEM_SIZE ); + pxAssert( xGetPtr() < recMem.GetPtrEnd() ); - pxAssert(x86Ptr - recPtr < 0x10000); - s_pCurBlockEx->x86size = x86Ptr - recPtr; + pxAssert(xGetPtr() - recPtr < _64kb); + s_pCurBlockEx->x86size = xGetPtr() - recPtr; - recPtr = x86Ptr; + recPtr = xGetPtr(); pxAssert( (g_psxHasConstReg&g_psxFlushedConstReg) == g_psxHasConstReg ); @@ -1404,7 +1394,7 @@ StartRecomp: } R3000Acpu psxRec = { - recAlloc, + recReserve, recResetIOP, recExecute, recExecuteBlock, diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index b3753a74fd..ff81eee333 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -28,6 +28,7 @@ #include "Dump.h" #include "System/SysThreads.h" +#include "System/PageFaultSource.h" #include "GS.h" #include "CDVD/CDVD.h" @@ -63,7 +64,8 @@ bool g_cpuFlushedPC, g_cpuFlushedCode, g_recompilingDelaySlot, g_maySignalExcept #define X86 static const int RECCONSTBUF_SIZE = 16384 * 2; // 64 bit consts in 32 bit units -static u8 *recMem = NULL; // the recompiled blocks will be here +static RecompiledCodeReserve recMem(L"R5900-32 recompiled code cache", _1mb * 4); + static u32* recConstBuf = NULL; // 64-bit pseudo-immediates static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here static BASEBLOCK *recROM = NULL; // and here @@ -506,7 +508,7 @@ static DynGenFunc* _DynGen_EnterRecompiledCode() static void _DynGen_Dispatchers() { // In case init gets called multiple times: - HostSys::MemProtectStatic( eeRecDispatchers, Protect_ReadWrite, false ); + HostSys::MemProtectStatic( eeRecDispatchers, PageAccess_ReadWrite() ); // clear the buffer to 0xcc (easier debugging). memset_8<0xcc,__pagesize>( eeRecDispatchers ); @@ -523,7 +525,7 @@ static void _DynGen_Dispatchers() JITCompileInBlock = _DynGen_JITCompileInBlock(); EnterRecompiledCode = _DynGen_EnterRecompiledCode(); - HostSys::MemProtectStatic( eeRecDispatchers, Protect_ReadOnly, true ); + HostSys::MemProtectStatic( eeRecDispatchers, PageAccess_ExecOnly() ); recBlocks.SetJITCompile( JITCompile ); } @@ -531,24 +533,23 @@ static void _DynGen_Dispatchers() ////////////////////////////////////////////////////////////////////////////////////////// // -static const int REC_CACHEMEM = 0x01000000; static void __fastcall dyna_block_discard(u32 start,u32 sz); // memory allocation handle for the entire BASEBLOCK and stack allocations. static u8* m_recBlockAlloc = NULL; static const uint m_recBlockAllocSize = - (((Ps2MemSize::Base + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK)) -+ RECCONSTBUF_SIZE * sizeof(u32) + Ps2MemSize::Base; + (((Ps2MemSize::MainRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK)) ++ RECCONSTBUF_SIZE * sizeof(u32) + Ps2MemSize::MainRam; static void recThrowHardwareDeficiency( const wxChar* extFail ) { throw Exception::HardwareDeficiency() - .SetDiagMsg(wxsFormat( L"R5900-32 recompiler init failed: %s is not available.", extFail)) - .SetUserMsg(wxsFormat(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )); + .SetDiagMsg(pxsFmt( L"R5900-32 recompiler init failed: %s is not available.", extFail)) + .SetUserMsg(pxsFmt(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )); } -static void recAlloc() +static void recReserve() { // Hardware Requirements Check... @@ -561,27 +562,14 @@ static void recAlloc() if ( !x86caps.hasStreamingSIMD2Extensions ) recThrowHardwareDeficiency( L"SSE2" ); - if( recMem == NULL ) - { - // It's handy to have a constant base address for the EE recompiler buffer, since it - // allows me to key in the address directly in the debugger, and also recognize EE - // recompiled code from user-provisioned stack traces. But besides those, the recompiler - // has no actual restrictions on where it's compiled code buffer is located. - - // Note: the SuperVU recompiler depends on being able to grab an allocation below the - // 0x10000000 line, so we give the EErec an address above that to try first as it's - // basemem address, hence the 0x20000000 pick. - - const uint cachememsize = REC_CACHEMEM+0x1000; - recMem = (u8*)SysMmapEx( 0x20000000, cachememsize, 0, "recAlloc(R5900)" ); - } - - if( recMem == NULL ) - throw Exception::OutOfMemory( L"R5900-32 recompiled code cache" ); + recMem.Reserve( _64mb, HostMemoryMap::EErec ); +} +static void recAlloc() +{ // Goal: Allocate BASEBLOCKs for every possible branch target in PS2 memory. - // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are - // always 4 bytes long). + // Any 4-byte aligned address makes a valid branch target as per MIPS design (all + // instructions are always 4 bytes long). if( m_recBlockAlloc == NULL ) m_recBlockAlloc = (u8*) _aligned_malloc( m_recBlockAllocSize, 4096 ); @@ -590,7 +578,7 @@ static void recAlloc() throw Exception::OutOfMemory( L"R5900-32 BASEBLOCK tables" ); u8* curpos = m_recBlockAlloc; - recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK); + recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::MainRam / 4) * sizeof(BASEBLOCK); recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK); recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK); recConstBuf = (u32*)curpos; curpos += RECCONSTBUF_SIZE * sizeof(u32); @@ -607,7 +595,7 @@ static void recAlloc() // No errors.. Proceed with initialization: - ProfilerRegisterSource( "EE Rec", recMem, REC_CACHEMEM+0x1000 ); + ProfilerRegisterSource( "EE Rec", recMem, recMem.GetReserveSizeInBytes() ); _DynGen_Dispatchers(); x86FpuState = FPU_STATE; @@ -619,29 +607,31 @@ struct ManualPageTracking u8 counter; }; -static __aligned16 u16 manual_page[Ps2MemSize::Base >> 12]; -static __aligned16 u8 manual_counter[Ps2MemSize::Base >> 12]; +static __aligned16 u16 manual_page[Ps2MemSize::MainRam >> 12]; +static __aligned16 u8 manual_counter[Ps2MemSize::MainRam >> 12]; static u32 eeRecIsReset = false; +static u32 eeRecNeedsReset = false; +static bool eeRecIsActive = false; //////////////////////////////////////////////////// -void recResetEE( void ) +static void recResetRaw() { - //AtomicExchange( eeRecNeedsReset, false ); + recAlloc(); + if( AtomicExchange( eeRecIsReset, true ) ) return; + AtomicExchange( eeRecNeedsReset, false ); Console.WriteLn( Color_StrongBlack, "EE/iR5900-32 Recompiler Reset" ); + recMem.Reset(); + maxrecmem = 0; - if (IsDevBuild) - memset_8<0xcc, REC_CACHEMEM>(recMem); // 0xcc is INT3 - memzero_ptr( m_recBlockAlloc ); // Excluding the 32mb ram copy + memzero_ptr( m_recBlockAlloc ); // Excluding the 32mb ram copy memzero_ptr(recConstBuf); - memzero( manual_page ); - memzero( manual_counter ); ClearRecLUT((BASEBLOCK*)m_recBlockAlloc, - (((Ps2MemSize::Base + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4))); + (((Ps2MemSize::MainRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4))); if( s_pInstCache ) memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize ); @@ -693,12 +683,12 @@ void recResetEE( void ) branch = 0; } -static void recShutdown( void ) +static void recShutdown() { ProfilerTerminateSource( "EERec" ); + recMem.Free(); recBlocks.Reset(); - SafeSysMunmap( recMem, REC_CACHEMEM ); safe_aligned_free( m_recBlockAlloc ); recRAM = recROM = recROM1 = NULL; recConstBuf = NULL; @@ -708,6 +698,17 @@ static void recShutdown( void ) s_nInstCacheSize = 0; } +static void recResetEE() +{ + if (eeRecIsActive) + { + AtomicExchange( eeRecNeedsReset, true ); + return; + } + + recResetRaw(); +} + void recStep( void ) { } @@ -1354,14 +1355,21 @@ static void __fastcall recRecompile( const u32 startpc ) pxAssume( startpc ); // if recPtr reached the mem limit reset whole mem - if ( ( (uptr)recPtr - (uptr)recMem ) >= REC_CACHEMEM-0x40000 || dumplog == 0xffffffff) { - recResetEE(); + if (recPtr >= (recMem.GetPtrEnd() - _64kb)) { + AtomicExchange( eeRecNeedsReset, true ); } - if ( (recConstBufPtr - recConstBuf) >= RECCONSTBUF_SIZE - 64 ) { + else if ((recConstBufPtr - recConstBuf) >= RECCONSTBUF_SIZE - 64) { Console.WriteLn("EE recompiler stack reset"); - recResetEE(); + AtomicExchange( eeRecNeedsReset, true ); } + if (eeRecNeedsReset) recResetRaw(); + + // 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); + xSetPtr( recPtr ); recPtr = xGetAlignedCallTarget(); @@ -1764,7 +1772,7 @@ StartRecomp: pxAssert( (pc-startpc)>>2 <= 0xffff ); s_pCurBlockEx->size = (pc-startpc)>>2; - if (HWADDR(pc) <= Ps2MemSize::Base) { + if (HWADDR(pc) <= Ps2MemSize::MainRam) { BASEBLOCKEX *oldBlock; int i; @@ -1836,11 +1844,11 @@ StartRecomp: } } - pxAssert( xGetPtr() < recMem+REC_CACHEMEM ); + pxAssert( xGetPtr() < recMem.GetPtrEnd() ); pxAssert( recConstBufPtr < recConstBuf + RECCONSTBUF_SIZE ); pxAssert( x86FpuState == 0 ); - pxAssert(xGetPtr() - recPtr < 0x10000); + pxAssert(xGetPtr() - recPtr < _64kb); s_pCurBlockEx->x86size = xGetPtr() - recPtr; recPtr = xGetPtr(); @@ -1878,7 +1886,7 @@ static void recThrowException( const BaseException& ex ) R5900cpu recCpu = { - recAlloc, + recReserve, recShutdown, recResetEE, diff --git a/pcsx2/x86/ix86-32/recVTLB.cpp b/pcsx2/x86/ix86-32/recVTLB.cpp index f2a0daae50..f89bbd3b03 100644 --- a/pcsx2/x86/ix86-32/recVTLB.cpp +++ b/pcsx2/x86/ix86-32/recVTLB.cpp @@ -287,7 +287,7 @@ void vtlb_dynarec_init() hasBeenCalled = true; // In case init gets called multiple times: - HostSys::MemProtectStatic( m_IndirectDispatchers, Protect_ReadWrite, false ); + HostSys::MemProtectStatic( m_IndirectDispatchers, PageAccess_ReadWrite() ); // clear the buffer to 0xcc (easier debugging). memset_8<0xcc,0x1000>( m_IndirectDispatchers ); @@ -309,7 +309,7 @@ void vtlb_dynarec_init() } } - HostSys::MemProtectStatic( m_IndirectDispatchers, Protect_ReadOnly, true ); + HostSys::MemProtectStatic( m_IndirectDispatchers, PageAccess_ExecOnly() ); } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp index 2721e7da9b..114e9ed3d1 100644 --- a/pcsx2/x86/microVU.cpp +++ b/pcsx2/x86/microVU.cpp @@ -123,7 +123,7 @@ void microVU::reset() { x86SetPtr(dispCache); mVUdispatcherA(this); mVUdispatcherB(this); - mVUemitSearch(); + mVUemitSearch(); // Clear All Program Data //memset(&prog, 0, sizeof(prog)); @@ -190,7 +190,7 @@ static void mVUresizeCache(mV, u32 size) { if (mVU->cache) Console.WriteLn(Color_Green, "microVU%d: Attempting to resize Cache [%dmb]", mVU->index, size/_1mb); - u8* cache = SysMmapEx(0, size, 0, (mVU->index ? "Micro VU1 RecCache" : "Micro VU0 RecCache")); + 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) { diff --git a/pcsx2/x86/microVU.h b/pcsx2/x86/microVU.h index df113ce718..5cc8eb8f06 100644 --- a/pcsx2/x86/microVU.h +++ b/pcsx2/x86/microVU.h @@ -171,7 +171,7 @@ struct microVU { u32 progMemMask; // VU Micro Memory Size (in u32's) u32 cacheSize; // VU Cache Size - microProgManager prog; // Micro Program Data + microProgManager prog; // Micro Program Data ScopedPtr regAlloc; // Reg Alloc Class ScopedPtr logFile; // Log File Pointer diff --git a/pcsx2/x86/microVU_Misc.inl b/pcsx2/x86/microVU_Misc.inl index b25ec6b76b..285de1d901 100644 --- a/pcsx2/x86/microVU_Misc.inl +++ b/pcsx2/x86/microVU_Misc.inl @@ -481,7 +481,7 @@ static __pagealigned u8 mVUsearchXMM[__pagesize]; // Generates a custom optimized block-search function // Note: Structs must be 16-byte aligned! (GCC doesn't guarantee this) void mVUcustomSearch() { - HostSys::MemProtectStatic(mVUsearchXMM, Protect_ReadWrite, false); + HostSys::MemProtectStatic(mVUsearchXMM, PageAccess_ReadWrite()); memset_8<0xcc,__pagesize>(mVUsearchXMM); xSetPtr(mVUsearchXMM); @@ -526,5 +526,5 @@ void mVUcustomSearch() { exitPoint.SetTarget(); xRET(); - HostSys::MemProtectStatic(mVUsearchXMM, Protect_ReadOnly, true); + HostSys::MemProtectStatic(mVUsearchXMM, PageAccess_ExecOnly()); } diff --git a/pcsx2/x86/newVif_UnpackSSE.cpp b/pcsx2/x86/newVif_UnpackSSE.cpp index 010913aa97..dc7d7b595b 100644 --- a/pcsx2/x86/newVif_UnpackSSE.cpp +++ b/pcsx2/x86/newVif_UnpackSSE.cpp @@ -295,7 +295,7 @@ static void nVifGen(int usn, int mask, int curCycle) { void VifUnpackSSE_Init() { - HostSys::MemProtectStatic(nVifUpkExec, Protect_ReadWrite, false); + HostSys::MemProtectStatic(nVifUpkExec, PageAccess_ReadWrite()); memset8<0xcc>( nVifUpkExec ); xSetPtr( nVifUpkExec ); @@ -306,5 +306,5 @@ void VifUnpackSSE_Init() nVifGen(a, b, c); }}} - HostSys::MemProtectStatic(nVifUpkExec, Protect_ReadOnly, true); + HostSys::MemProtectStatic(nVifUpkExec, PageAccess_ExecOnly()); } diff --git a/pcsx2/x86/sVU_zerorec.cpp b/pcsx2/x86/sVU_zerorec.cpp index 9a2af40e6b..299e6764a1 100644 --- a/pcsx2/x86/sVU_zerorec.cpp +++ b/pcsx2/x86/sVU_zerorec.cpp @@ -72,7 +72,7 @@ extern void iDumpVU1Registers(); #define SUPERVU_CHECKCONDITION 0 // has to be 0!! -#define VU_EXESIZE 0x00800000 +static const uint VU_EXESIZE = _1mb * 8; #define _Imm11_ (s32)( (vucode & 0x400) ? (0xfffffc00 | (vucode & 0x3ff)) : (vucode & 0x3ff) ) #define _UImm11_ (s32)(vucode & 0x7ff) @@ -352,7 +352,7 @@ static void SuperVUAlloc(int vuindex) { // upper 4 bits must be zero! // Changed "first try base" to 0xf1e0000, since 0x0c000000 liked to fail a lot. (cottonvibes) - s_recVUMem = SysMmapEx(0xf1e0000, VU_EXESIZE, 0x10000000, "SuperVUAlloc"); + s_recVUMem = SysMmapEx(HostMemoryMap::sVUrec, VU_EXESIZE, 0x10000000, "SuperVUAlloc"); // Try again at some other random memory location... whatever. >_< if( s_recVUMem == NULL ) @@ -361,7 +361,7 @@ static void SuperVUAlloc(int vuindex) if (s_recVUMem == NULL) { throw Exception::VirtualMemoryMapConflict() - .SetDiagMsg(wxsFormat( L"SuperVU failed to allocate virtual memory below 256MB." )) + .SetDiagMsg(pxsFmt( L"SuperVU failed to allocate virtual memory below 256MB." )) .SetUserMsg(pxE( ".Error:superVU:VirtualMemoryAlloc", L"Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory " L"ranges required, and will not be available for use. This is not a critical error, since " From bed33749b52caaddc14e7cebb10a11207def83fd Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Fri, 22 Oct 2010 19:47:02 +0000 Subject: [PATCH 03/22] newHostVM branch: (now boots games!) * EE and IOP recompilers are using the new RecompiledCodeReserve class. * PS2 main memory should typically be located at 0x20000000 (code still need some cleanups) VU0/VU1 recompilers will be implemented soon. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@3959 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/src/Utilities/Exceptions.cpp | 16 +++++---- pcsx2/Memory.cpp | 7 ++-- pcsx2/System.cpp | 53 ++++++++++++++++++++++++----- pcsx2/System.h | 13 +++++++ pcsx2/System/PageFaultSource.h | 2 +- pcsx2/gui/App.h | 1 + pcsx2/gui/AppInit.cpp | 2 ++ pcsx2/windows/WinSysExec.cpp | 4 +-- pcsx2/x86/iR3000A.cpp | 20 ++++++----- pcsx2/x86/ix86-32/iR5900-32.cpp | 19 ++++++----- 10 files changed, 99 insertions(+), 38 deletions(-) diff --git a/common/src/Utilities/Exceptions.cpp b/common/src/Utilities/Exceptions.cpp index 893365f039..7050acb005 100644 --- a/common/src/Utilities/Exceptions.cpp +++ b/common/src/Utilities/Exceptions.cpp @@ -68,12 +68,6 @@ wxString DiagnosticOrigin::ToString( const wxChar* msg ) const } -bool pxAssertImpl_LogIt( const DiagnosticOrigin& origin, const wxChar *msg ) -{ - wxLogError( L"%s", origin.ToString( msg ).c_str() ); - return false; -} - // Because wxTrap isn't available on Linux builds of wxWidgets (non-Debug, typically) void pxTrap() { @@ -94,6 +88,16 @@ void pxTrap() #endif // Win/Unix } + +bool pxAssertImpl_LogIt( const DiagnosticOrigin& origin, const wxChar *msg ) +{ + //wxLogError( L"%s", origin.ToString( msg ).c_str() ); + wxMessageOutputDebug().Printf( L"%s", origin.ToString( msg ).c_str() ); + pxTrap(); + return false; +} + + DEVASSERT_INLINE void pxOnAssert( const DiagnosticOrigin& origin, const wxChar* msg ) { // Recursion guard: Allow at least one recursive call. This is useful because sometimes diff --git a/pcsx2/Memory.cpp b/pcsx2/Memory.cpp index 25b3cc3804..626d7d299c 100644 --- a/pcsx2/Memory.cpp +++ b/pcsx2/Memory.cpp @@ -582,7 +582,7 @@ protected: void OnPageFaultEvent( const PageFaultInfo& info, bool& handled ); }; -static mmap_PageFaultHandler mmap_faultHandler; +static mmap_PageFaultHandler* mmap_faultHandler = NULL; EEVM_MemoryAllocMess* eeMem = NULL; @@ -596,12 +596,13 @@ void memAlloc() if( eeMem == NULL) throw Exception::OutOfMemory( L"memAlloc > failed to allocate PS2's base ram/rom/scratchpad." ); - Source_PageFault.Add( mmap_faultHandler ); + pxAssume(Source_PageFault); + mmap_faultHandler = new mmap_PageFaultHandler(); } void memShutdown() { - Source_PageFault.Remove( mmap_faultHandler ); + safe_delete(mmap_faultHandler); vtlb_free( eeMem, sizeof(*eeMem) ); eeMem = NULL; diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index 02f12fdddb..c9433e7914 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -31,16 +31,18 @@ extern void resetNewVif(int idx); template class EventSource< IEventListener_PageFault >; -SrcType_PageFault Source_PageFault; +SrcType_PageFault* Source_PageFault = NULL; EventListener_PageFault::EventListener_PageFault() { - Source_PageFault.Add( *this ); + pxAssume(Source_PageFault); + Source_PageFault->Add( *this ); } EventListener_PageFault::~EventListener_PageFault() throw() { - Source_PageFault.Remove( *this ); + if (Source_PageFault) + Source_PageFault->Remove( *this ); } void SrcType_PageFault::Dispatch( const PageFaultInfo& params ) @@ -108,11 +110,19 @@ void* BaseVirtualMemoryReserve::Reserve( uint size, uptr base, uptr upper_bounds 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) + /*if (m_def_commit) { - HostSys::MmapCommit(m_baseptr, m_def_commit*__pagesize); - HostSys::MemProtect(m_baseptr, m_def_commit*__pagesize, m_prot_mode); - } + 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 m_CpuProviders; + ScopedPtr m_VmReserve; ScopedPtr m_VmAllocs; protected: diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index e064df29cf..8b448aa737 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -252,6 +252,8 @@ void Pcsx2App::AllocateCoreStuffs() SysLogMachineCaps(); AppApplySettings(); + if (!m_VmReserve) m_VmReserve = new SysReserveVM(); + if( !m_CpuProviders ) { // FIXME : Some or all of SysCpuProviderPack should be run from the SysExecutor thread, diff --git a/pcsx2/windows/WinSysExec.cpp b/pcsx2/windows/WinSysExec.cpp index 6a11a70c62..b454bea0d8 100644 --- a/pcsx2/windows/WinSysExec.cpp +++ b/pcsx2/windows/WinSysExec.cpp @@ -25,8 +25,8 @@ 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; + Source_PageFault->Dispatch( PageFaultInfo( (uptr)eps->ExceptionRecord->ExceptionInformation[1] ) ); + return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; } void InstallSignalHandler() diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp index 8b1fb383dc..13724b55ba 100644 --- a/pcsx2/x86/iR3000A.cpp +++ b/pcsx2/x86/iR3000A.cpp @@ -51,7 +51,7 @@ uptr psxhwLUT[0x10000]; #define HWADDR(mem) (psxhwLUT[mem >> 16] + (mem)) -static RecompiledCodeReserve recMem(L"R3000A recompiled code cache", _1mb * 2); +static RecompiledCodeReserve* recMem = NULL; static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here static BASEBLOCK *recROM = NULL; // and here @@ -757,7 +757,11 @@ static const uint m_recBlockAllocSize = static void recReserve() { - recMem.Reserve( _16mb, HostMemoryMap::IOPrec ); + if (!recMem) + { + recMem = new RecompiledCodeReserve(L"R3000A recompiled code cache", _1mb * 2); + recMem->Reserve( _16mb, HostMemoryMap::IOPrec ); + } } static void recAlloc() @@ -786,14 +790,14 @@ static void recAlloc() if( s_pInstCache == NULL ) throw Exception::OutOfMemory( L"R3000 InstCache." ); - ProfilerRegisterSource( "IOP Rec", recMem, recMem.GetReserveSizeInBytes() ); + ProfilerRegisterSource( "IOP Rec", *recMem, recMem->GetReserveSizeInBytes() ); _DynGen_Dispatchers(); } void recResetIOP() { recAlloc(); - recMem.Reset(); + recMem->Reset(); DevCon.WriteLn( "iR3000A Recompiler reset." ); @@ -836,14 +840,14 @@ void recResetIOP() recBlocks.Reset(); g_psxMaxRecMem = 0; - recPtr = recMem; + recPtr = *recMem; psxbranch = 0; } static void recShutdown() { ProfilerTerminateSource( "IOPRec" ); - recMem.Free(); + safe_delete( recMem ); safe_aligned_free( m_recBlockAlloc ); @@ -1191,7 +1195,7 @@ static void __fastcall iopRecRecompile( const u32 startpc ) pxAssert( startpc ); // if recPtr reached the mem limit reset whole mem - if (recPtr >= (recMem.GetPtrEnd() - _64kb)) { + if (recPtr >= (recMem->GetPtrEnd() - _64kb)) { recResetIOP(); } @@ -1380,7 +1384,7 @@ StartRecomp: } } - pxAssert( xGetPtr() < recMem.GetPtrEnd() ); + pxAssert( xGetPtr() < recMem->GetPtrEnd() ); pxAssert(xGetPtr() - recPtr < _64kb); s_pCurBlockEx->x86size = xGetPtr() - recPtr; diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index ff81eee333..b3eb7783a5 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -64,7 +64,7 @@ bool g_cpuFlushedPC, g_cpuFlushedCode, g_recompilingDelaySlot, g_maySignalExcept #define X86 static const int RECCONSTBUF_SIZE = 16384 * 2; // 64 bit consts in 32 bit units -static RecompiledCodeReserve recMem(L"R5900-32 recompiled code cache", _1mb * 4); +static RecompiledCodeReserve* recMem = NULL; static u32* recConstBuf = NULL; // 64-bit pseudo-immediates static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here @@ -562,7 +562,8 @@ static void recReserve() if ( !x86caps.hasStreamingSIMD2Extensions ) recThrowHardwareDeficiency( L"SSE2" ); - recMem.Reserve( _64mb, HostMemoryMap::EErec ); + recMem = new RecompiledCodeReserve(L"R5900-32 recompiled code cache", _1mb * 4); + recMem->Reserve( _64mb, HostMemoryMap::EErec ); } static void recAlloc() @@ -595,7 +596,7 @@ static void recAlloc() // No errors.. Proceed with initialization: - ProfilerRegisterSource( "EE Rec", recMem, recMem.GetReserveSizeInBytes() ); + ProfilerRegisterSource( "EE Rec", *recMem, recMem->GetReserveSizeInBytes() ); _DynGen_Dispatchers(); x86FpuState = FPU_STATE; @@ -624,7 +625,7 @@ static void recResetRaw() Console.WriteLn( Color_StrongBlack, "EE/iR5900-32 Recompiler Reset" ); - recMem.Reset(); + recMem->Reset(); maxrecmem = 0; @@ -674,9 +675,9 @@ static void recResetRaw() recLUT_SetPage(recLUT, hwLUT, recROM1, 0xa000, i, i - 0x1e00); } - x86SetPtr(recMem); + x86SetPtr(*recMem); - recPtr = recMem; + recPtr = *recMem; recConstBufPtr = recConstBuf; x86FpuState = FPU_STATE; @@ -686,7 +687,7 @@ static void recResetRaw() static void recShutdown() { ProfilerTerminateSource( "EERec" ); - recMem.Free(); + safe_delete( recMem ); recBlocks.Reset(); safe_aligned_free( m_recBlockAlloc ); @@ -1355,7 +1356,7 @@ static void __fastcall recRecompile( const u32 startpc ) pxAssume( startpc ); // if recPtr reached the mem limit reset whole mem - if (recPtr >= (recMem.GetPtrEnd() - _64kb)) { + if (recPtr >= (recMem->GetPtrEnd() - _64kb)) { AtomicExchange( eeRecNeedsReset, true ); } else if ((recConstBufPtr - recConstBuf) >= RECCONSTBUF_SIZE - 64) { @@ -1844,7 +1845,7 @@ StartRecomp: } } - pxAssert( xGetPtr() < recMem.GetPtrEnd() ); + pxAssert( xGetPtr() < recMem->GetPtrEnd() ); pxAssert( recConstBufPtr < recConstBuf + RECCONSTBUF_SIZE ); pxAssert( x86FpuState == 0 ); From 4bee22a4cd07ea356573a6c62d370a493341eb20 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Wed, 27 Oct 2010 19:18:46 +0000 Subject: [PATCH 04/22] 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 --- common/build/Utilities/Utilities.cbp | 3 + common/build/Utilities/utilities.vcproj | 8 + common/include/Utilities/Dependencies.h | 15 +- common/include/Utilities/MemsetFast.inl | 85 ++++++ .../include/Utilities}/PageFaultSource.h | 62 ++++- common/include/Utilities/Path.h | 3 +- common/src/Utilities/CMakeLists.txt | 3 + common/src/Utilities/PathUtils.cpp | 2 +- common/src/Utilities/VirtualMemory.cpp | 203 ++++++++++++++ common/src/Utilities/Windows/WinHostSys.cpp | 1 + pcsx2/CMakeLists.txt | 2 +- pcsx2/IPU/IPU.cpp | 2 + pcsx2/IPU/mpeg2lib/Mpeg.cpp | 2 + pcsx2/IPU/mpeg2lib/Mpeg.h | 42 --- pcsx2/Linux/pcsx2.cbp | 2 +- pcsx2/Memory.cpp | 3 +- pcsx2/PrecompiledHeader.h | 17 +- pcsx2/SaveState.cpp | 2 +- pcsx2/System.cpp | 257 ++---------------- pcsx2/System.h | 8 +- pcsx2/System/RecTypes.h | 46 ++++ pcsx2/System/SysCoreThread.cpp | 2 +- pcsx2/VUmicro.h | 53 +++- pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 4 + pcsx2/windows/WinSysExec.cpp | 2 +- pcsx2/x86/iR3000A.cpp | 10 +- pcsx2/x86/ix86-32/iR5900-32.cpp | 24 +- pcsx2/x86/microVU.cpp | 135 +++++---- pcsx2/x86/microVU.h | 16 +- pcsx2/x86/microVU_Execute.inl | 10 +- pcsx2/x86/microVU_Misc.h | 9 - pcsx2/x86/sVU_zerorec.cpp | 204 +++++++------- 32 files changed, 703 insertions(+), 534 deletions(-) create mode 100644 common/include/Utilities/MemsetFast.inl rename {pcsx2/System => common/include/Utilities}/PageFaultSource.h (66%) create mode 100644 common/src/Utilities/VirtualMemory.cpp create mode 100644 pcsx2/System/RecTypes.h diff --git a/common/build/Utilities/Utilities.cbp b/common/build/Utilities/Utilities.cbp index 585bc4c499..cfb00c78c8 100644 --- a/common/build/Utilities/Utilities.cbp +++ b/common/build/Utilities/Utilities.cbp @@ -155,6 +155,8 @@ + + @@ -200,6 +202,7 @@ + diff --git a/common/build/Utilities/utilities.vcproj b/common/build/Utilities/utilities.vcproj index 6d7bf5ee1f..f14e0f9ff9 100644 --- a/common/build/Utilities/utilities.vcproj +++ b/common/build/Utilities/utilities.vcproj @@ -291,6 +291,10 @@ RelativePath="..\..\src\Utilities\StringHelpers.cpp" > + + @@ -417,6 +421,10 @@ RelativePath="..\..\include\Utilities\MemcpyFast.h" > + + diff --git a/common/include/Utilities/Dependencies.h b/common/include/Utilities/Dependencies.h index 98b3e7e8a9..69018be958 100644 --- a/common/include/Utilities/Dependencies.h +++ b/common/include/Utilities/Dependencies.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! // =========================================================================================== diff --git a/common/include/Utilities/MemsetFast.inl b/common/include/Utilities/MemsetFast.inl new file mode 100644 index 0000000000..64b4a91266 --- /dev/null +++ b/common/include/Utilities/MemsetFast.inl @@ -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 . + */ + +#pragma once + +#include + +#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( 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( &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) ); +} diff --git a/pcsx2/System/PageFaultSource.h b/common/include/Utilities/PageFaultSource.h similarity index 66% rename from pcsx2/System/PageFaultSource.h rename to common/include/Utilities/PageFaultSource.h index 94cc9a0bd8..bf64331fe2 100644 --- a/pcsx2/System/PageFaultSource.h +++ b/common/include/Utilities/PageFaultSource.h @@ -13,6 +13,8 @@ * If not, see . */ +// [TODO] Rename this file to VirtualMemory.h !! + #pragma once // ===================================================================================================== @@ -20,8 +22,9 @@ // ===================================================================================================== // Win32 platforms use the SEH model: __try {} __except {} // Linux platforms use the POSIX Signals model: sigaction() +// [TODO] OS-X (Darwin) platforms should use the Mach exception model (not implemented) -#include "Utilities/EventSource.h" +#include "EventSource.h" struct PageFaultInfo { @@ -125,9 +128,11 @@ public: Free(); } - void* Reserve( uint size, uptr base = 0, uptr upper_bounds = 0 ); - void Reset(); - void Free(); + virtual void* Reserve( uint size, uptr base = 0, uptr upper_bounds = 0 ); + virtual void Reset(); + virtual void Free(); + + bool IsOk() const { return m_baseptr != NULL; } uptr GetReserveSizeInBytes() const { return m_reserved * __pagesize; } uptr GetReserveSizeInPages() const { return m_reserved; } @@ -155,16 +160,58 @@ protected: }; // -------------------------------------------------------------------------------------- -// RecompiledCodeReserve +// SpatialArrayReserve // -------------------------------------------------------------------------------------- -class RecompiledCodeReserve : public BaseVirtualMemoryReserve +// A spatial array is one where large areas of the memory reserve will remain unused during +// process execution. Only areas put to use will be committed to virtual memory. +// +// Spatial array efficiency depends heavily on selecting the right parameters for the array's +// primary intended use. Memory in a spatial array is arranged by blocks, with each block +// containing some number of pages (pages are 4096 bytes each on most platforms). When the +// array is accessed, the entire block containing the addressed memory will be committed at +// once. Blocks can be a single page in size (4096 bytes), though this is highly discouraged +// due to overhead and fragmentation penalties. +// +// Balancing block sizes: +// Larger blocks are good for reducing memory fragmentation and block-tracking overhead, but +// can also result in a lot of otherwise unused memory being committed to memory. Smaller +// blocks are good for arrays that will tend toward more sequential behavior, as they reduce +// the amount of unused memory being committed. However, since every block requires a +// tracking entry, assigning small blocks to a very large array can result in quite a bit of +// unwanted overhead. Furthermore, if the array is accessed randomly, system physical memory +// will become very fragmented, which will also hurt performance. +// +// By default, the base block size is based on a heuristic that balances the size of the spatial +// array reserve against a best-guess performance profile for the target platform. +// +class SpatialArrayReserve : public BaseVirtualMemoryReserve { + typedef BaseVirtualMemoryReserve __parent; + protected: public: - RecompiledCodeReserve( const wxString& name, uint defCommit = 0 ); + SpatialArrayReserve( const wxString& name, uint defCommit = 0 ); + + virtual void* Reserve( uint size, uptr base = 0, uptr upper_bounds = 0 ); + void OnCommittedBlock( void* block ); void OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled ); + + // This method allows the programmer to specify the block size of the array as a function + // of its reserved size. This function *must* be called *after* the reserve has been made. + // Calls to this function prior to initializing the reserve will be ignored (and will + // generate an assertion in debug builds). + SpatialArrayReserve& SetBlockCount( uint blocks ); + + // Sets the block size via pages (pages are defined by the __pagesize global, which is + // typically 4096). + SpatialArrayReserve& SetBlockSizeInPages( uint bytes ); + + // This method assigns the block size of the spatial array, in bytes. The actual size of + // each block will be rounded up to the nearest page size. The resulting size is returned. + uint SetBlockSize( uint bytes ); + operator void*() { return m_baseptr; } operator const void*() const { return m_baseptr; } @@ -190,7 +237,6 @@ extern int SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps); # error PCSX2 - Unsupported operating system platform. #endif - extern void InstallSignalHandler(); extern SrcType_PageFault* Source_PageFault; diff --git a/common/include/Utilities/Path.h b/common/include/Utilities/Path.h index 351e99d851..334dc2bca2 100644 --- a/common/include/Utilities/Path.h +++ b/common/include/Utilities/Path.h @@ -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 { diff --git a/common/src/Utilities/CMakeLists.txt b/common/src/Utilities/CMakeLists.txt index 72c51a5a53..a659c5b4c0 100644 --- a/common/src/Utilities/CMakeLists.txt +++ b/common/src/Utilities/CMakeLists.txt @@ -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 diff --git a/common/src/Utilities/PathUtils.cpp b/common/src/Utilities/PathUtils.cpp index 800576b76e..3b6daaa2ff 100644 --- a/common/src/Utilities/PathUtils.cpp +++ b/common/src/Utilities/PathUtils.cpp @@ -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. diff --git a/common/src/Utilities/VirtualMemory.cpp b/common/src/Utilities/VirtualMemory.cpp new file mode 100644 index 0000000000..8eab5a1edc --- /dev/null +++ b/common/src/Utilities/VirtualMemory.cpp @@ -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 . + */ + +#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= 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 +#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; diff --git a/pcsx2/IPU/mpeg2lib/Mpeg.cpp b/pcsx2/IPU/mpeg2lib/Mpeg.cpp index 4a2c3f00d2..f2fd7e3ac8 100644 --- a/pcsx2/IPU/mpeg2lib/Mpeg.cpp +++ b/pcsx2/IPU/mpeg2lib/Mpeg.cpp @@ -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, diff --git a/pcsx2/IPU/mpeg2lib/Mpeg.h b/pcsx2/IPU/mpeg2lib/Mpeg.h index b4741d9574..982007ed6c 100644 --- a/pcsx2/IPU/mpeg2lib/Mpeg.h +++ b/pcsx2/IPU/mpeg2lib/Mpeg.h @@ -24,48 +24,6 @@ #pragma once -#include - -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 - + diff --git a/pcsx2/Memory.cpp b/pcsx2/Memory.cpp index 626d7d299c..5efe544ea4 100644 --- a/pcsx2/Memory.cpp +++ b/pcsx2/Memory.cpp @@ -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 diff --git a/pcsx2/PrecompiledHeader.h b/pcsx2/PrecompiledHeader.h index e24bcfc556..5788d481cd 100644 --- a/pcsx2/PrecompiledHeader.h +++ b/pcsx2/PrecompiledHeader.h @@ -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__ diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index 411cafe84b..c9a547942e 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -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& memblock ) diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index c9433e7914..ecb33f9d90 100644 --- a/pcsx2/System.cpp +++ b/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= 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 -__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; iSetCacheReserve( (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( m_block_size, 4 ); HostSys::MmapCommit((u8*)blockptr, cusion * __pagesize); HostSys::MemProtect((u8*)blockptr, cusion * __pagesize, m_prot_mode); @@ -442,7 +241,7 @@ CpuInitializer< CpuType >::CpuInitializer() { try { MyCpu = new CpuType(); - MyCpu->Allocate(); + MyCpu->Reserve(); } catch( Exception::RuntimeError& ex ) { @@ -461,7 +260,7 @@ CpuInitializer< CpuType >::CpuInitializer() template< typename CpuType > CpuInitializer< CpuType >::~CpuInitializer() throw() { - if( MyCpu ) + if (MyCpu) MyCpu->Shutdown(); } @@ -608,11 +407,6 @@ SysCpuProviderPack::SysCpuProviderPack() } // hmm! : VU0 and VU1 pre-allocations should do sVU and mVU separately? Sounds complicated. :( - - // If both VUrecs failed, then make sure the SuperVU is totally closed out, because it - // actually initializes everything once and then shares it between both VU recs. - if( !IsRecAvailable_SuperVU0() && !IsRecAvailable_SuperVU1() ) - SuperVUDestroy( -1 ); } bool SysCpuProviderPack::IsRecAvailable_MicroVU0() const { return CpuProviders->microVU0.IsAvailable(); } @@ -633,9 +427,6 @@ void SysCpuProviderPack::CleanupMess() throw() closeNewVif(0); closeNewVif(1); - // Special SuperVU "complete" terminator (stupid hacky recompiler) - SuperVUDestroy( -1 ); - psxRec.Shutdown(); recCpu.Shutdown(); } @@ -695,10 +486,6 @@ void SysClearExecutionCache() { GetCpuProviders().ApplyConfig(); - // SuperVUreset will do nothing is none of the recs are initialized. - // But it's needed if one or the other is initialized. - SuperVUReset(-1); - Cpu->Reset(); psxCpu->Reset(); diff --git a/pcsx2/System.h b/pcsx2/System.h index cec9cc0c66..f0e1fc1db5 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -22,8 +22,9 @@ #include "CDVD/CDVDaccess.h" typedef SafeArray 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; diff --git a/pcsx2/System/RecTypes.h b/pcsx2/System/RecTypes.h new file mode 100644 index 0000000000..995444669d --- /dev/null +++ b/pcsx2/System/RecTypes.h @@ -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 . + */ + +#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; +}; diff --git a/pcsx2/System/SysCoreThread.cpp b/pcsx2/System/SysCoreThread.cpp index 1238275900..a1f59ded4e 100644 --- a/pcsx2/System/SysCoreThread.cpp +++ b/pcsx2/System/SysCoreThread.cpp @@ -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__ diff --git a/pcsx2/VUmicro.h b/pcsx2/VUmicro.h index 81436cdf48..8270c17714 100644 --- a/pcsx2/VUmicro.h +++ b/pcsx2/VUmicro.h @@ -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; diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index 1affaf6adf..c72c18c5cb 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -459,6 +459,10 @@ RelativePath="..\..\Plugins.h" > + + diff --git a/pcsx2/windows/WinSysExec.cpp b/pcsx2/windows/WinSysExec.cpp index b454bea0d8..5d1f482fba 100644 --- a/pcsx2/windows/WinSysExec.cpp +++ b/pcsx2/windows/WinSysExec.cpp @@ -18,7 +18,7 @@ #include #include "Common.h" -#include "System/PageFaultSource.h" +#include "Utilities/PageFaultSource.h" int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps ) { diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp index 13724b55ba..2886d53080 100644 --- a/pcsx2/x86/iR3000A.cpp +++ b/pcsx2/x86/iR3000A.cpp @@ -22,7 +22,7 @@ #include "iR3000A.h" #include "BaseblockEx.h" -#include "PageFaultSource.h" +#include "System/RecTypes.h" #include @@ -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))); diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index b3eb7783a5..3c90e9a28b 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -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 diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp index 114e9ed3d1..f6c409cb99 100644 --- a/pcsx2/x86/microVU.cpp +++ b/pcsx2/x86/microVU.cpp @@ -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(); - } 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(); + continue; + } + deque::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::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) - microVU0.init(0); - } +void recMicroVU0::Reserve() { + if (AtomicExchange(m_Reserved, 1) == 0) + microVU0.init(0); } -void recMicroVU1::Allocate() { - if(!m_AllocCount) { - m_AllocCount++; - if (AtomicExchange(mvu1_allocated, 1) == 0) - microVU1.init(1); - } +void recMicroVU1::Reserve() { + if (AtomicExchange(m_Reserved, 1) == 0) + microVU1.init(1); } void recMicroVU0::Shutdown() throw() { - if (m_AllocCount > 0) { - m_AllocCount--; - if (AtomicExchange(mvu0_allocated, 0) == 1) - microVU0.close(); - } + if (AtomicExchange(m_Reserved, 0) == 1) + microVU0.close(); } void recMicroVU1::Shutdown() throw() { - if (m_AllocCount > 0) { - m_AllocCount--; - if (AtomicExchange(mvu1_allocated, 0) == 1) - microVU1.close(); - } + if (AtomicExchange(m_Reserved, 0) == 1) + microVU1.close(); } void recMicroVU0::Reset() { - if(!pxAssertDev(m_AllocCount, "MicroVU0 CPU Provider has not been allocated prior to reset!")) return; + if(!pxAssertDev(m_Reserved, "MicroVU0 CPU Provider has not been reserved prior to reset!")) return; microVU0.reset(); } void recMicroVU1::Reset() { - if(!pxAssertDev(m_AllocCount, "MicroVU1 CPU Provider has not been allocated prior to reset!")) return; + if(!pxAssertDev(m_Reserved, "MicroVU1 CPU Provider has not been reserved prior to reset!")) return; microVU1.reset(); } void recMicroVU0::Execute(u32 cycles) { - pxAssert(mvu0_allocated); // please allocate me first! :| + pxAssert(m_Reserved); // please allocate me first! :| if(!(VU0.VI[REG_VPU_STAT].UL & 1)) return; @@ -381,17 +350,35 @@ void recMicroVU0::Execute(u32 cycles) { ((mVUrecCall)microVU0.startFunct)(VU0.VI[REG_TPC].UL, cycles); } void recMicroVU1::Execute(u32 cycles) { - pxAssert(mvu1_allocated); // please allocate me first! :| + pxAssert(m_Reserved); // please allocate me first! :| if(!(VU0.VI[REG_VPU_STAT].UL & 0x100)) return; ((mVUrecCall)microVU1.startFunct)(VU1.VI[REG_TPC].UL, vu1RunCycles); } void recMicroVU0::Clear(u32 addr, u32 size) { - pxAssert(mvu0_allocated); // please allocate me first! :| + pxAssert(m_Reserved); // please allocate me first! :| mVUclear(µ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; +} diff --git a/pcsx2/x86/microVU.h b/pcsx2/x86/microVU.h index 5cc8eb8f06..57cd99a092 100644 --- a/pcsx2/x86/microVU.h +++ b/pcsx2/x86/microVU.h @@ -150,7 +150,7 @@ struct microProgManager { microRegInfo lpState; // Pipeline state from where program left off (useful for continuing execution) }; -#define mVUdispCacheSize (0x1000) // Dispatcher Cache Size +#define mVUdispCacheSize (__pagesize) // Dispatcher Cache Size #define mVUcacheSize ((index) ? (_1mb * 17) : (_1mb * 7)) // Initial Size (Excluding Safe-Zone) #define mVUcacheMaxSize ((mVU->index) ? (_1mb * 100) : (_1mb * 50)) // Max Size allowed to grow to #define mVUcacheGrowBy ((mVU->index) ? (_1mb * 15) : (_1mb * 10)) // Grows by this amount @@ -175,7 +175,9 @@ struct microVU { ScopedPtr regAlloc; // Reg Alloc Class ScopedPtr logFile; // Log File Pointer - u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to) + + RecompiledCodeReserve* cache_reserve; + u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to) u8* dispCache; // Dispatchers Cache (where startFunct and exitFunct are written to) u8* startFunct; // Ptr Function to the Start code for recompiled programs u8* exitFunct; // Ptr Function to the Exit code for recompiled programs @@ -224,6 +226,15 @@ struct microVU { pxAssumeDev((prog.IRinfo.curPC & 1) == 0, "microVU recompiler: Upper instructions cannot have valid branch addresses."); return (((prog.IRinfo.curPC + 4) + (Imm11() * 2)) & progMemMask) * 4; } + + microVU() + { + cacheSize = _1mb * 64; + cache = NULL; + dispCache = NULL; + startFunct = NULL; + exitFunct = NULL; + } void init(uint vuIndex); void reset(); @@ -239,7 +250,6 @@ int mVUdebugNow = 0; // Main Functions static void mVUclear(mV, u32, u32); -static void mVUresizeCache(mV, u32); static void* mVUblockFetch(microVU* mVU, u32 startPC, uptr pState); _mVUt extern void* __fastcall mVUcompileJIT(u32 startPC, uptr pState); diff --git a/pcsx2/x86/microVU_Execute.inl b/pcsx2/x86/microVU_Execute.inl index 198ab530da..cca83ed6ba 100644 --- a/pcsx2/x86/microVU_Execute.inl +++ b/pcsx2/x86/microVU_Execute.inl @@ -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; diff --git a/pcsx2/x86/microVU_Misc.h b/pcsx2/x86/microVU_Misc.h index ef58dbe8ef..ff6b1b40e0 100644 --- a/pcsx2/x86/microVU_Misc.h +++ b/pcsx2/x86/microVU_Misc.h @@ -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); diff --git a/pcsx2/x86/sVU_zerorec.cpp b/pcsx2/x86/sVU_zerorec.cpp index 299e6764a1..43e1bf55e6 100644 --- a/pcsx2/x86/sVU_zerorec.cpp +++ b/pcsx2/x86/sVU_zerorec.cpp @@ -35,6 +35,7 @@ #include "R5900.h" #include "iR5900.h" +#include "System/RecTypes.h" #include "sVU_zerorec.h" #include "SamplProf.h" @@ -72,7 +73,7 @@ extern void iDumpVU1Registers(); #define SUPERVU_CHECKCONDITION 0 // has to be 0!! -static const uint VU_EXESIZE = _1mb * 8; +static const uint sVU_EXESIZE = _8mb; #define _Imm11_ (s32)( (vucode & 0x400) ? (0xfffffc00 | (vucode & 0x3ff)) : (vucode & 0x3ff) ) #define _UImm11_ (s32)(vucode & 0x7ff) @@ -90,7 +91,9 @@ static const u32 PWaitTimes[] = { 53, 43, 28, 23, 17, 11, 10 }; static u32 s_vuInfo; // info passed into rec insts static const u32 s_MemSize[2] = {VU0_MEMSIZE, VU1_MEMSIZE}; -static u8* s_recVUMem = NULL, *s_recVUPtr = NULL; +//static u8* s_recVUMem = NULL, *s_recVUPtr = NULL; +static RecompiledCodeReserve* s_recVUMem[2] = { NULL, NULL }; +static u8* s_recVUPtr[2] = { NULL, NULL }; // tables which are defined at the bottom of this massive file. extern void (*recVU_UPPER_OPCODE[64])(VURegs* VU, s32 info); @@ -315,9 +318,11 @@ VuBaseBlock::VuBaseBlock() static list s_listVUHeaders[2]; static list* s_plistCachedHeaders[2] = {NULL, NULL}; -static VuFunctionHeader** recVUHeaders[2] = {NULL, NULL}; -static VuBlockHeader* recVUBlocks[2] = {NULL, NULL}; -static u8* recVUStack = NULL, *recVUStackPtr = NULL; +static VuFunctionHeader** recVUHeaders[2] = { NULL, NULL }; +static VuBlockHeader* recVUBlocks[2] = { NULL, NULL }; +static u8* recVUStack[2] = { NULL, NULL }; +static u8* recVUStackPtr[2] = { NULL, NULL }; + static vector<_x86regs> s_vecRegArray(128); static VURegs* VU = NULL; @@ -343,47 +348,24 @@ static void SuperVURecompile(); // allocate VU resources static void SuperVUAlloc(int vuindex) { - // The old -1 crap has been depreciated on this function. Please - // specify either 0 or 1, thanks. - pxAssert(vuindex >= 0); + if (s_recVUMem[vuindex]) return; + s_recVUMem[vuindex] = new RecompiledCodeReserve( L"SuperVU Recompiler Cache", 0 ); + s_recVUMem[vuindex]->Reserve( sVU_EXESIZE, vuindex ? HostMemoryMap::sVU1rec : HostMemoryMap::sVU0rec, _256mb ); + // upper 4 bits must be zero! - if (s_recVUMem == NULL) + if (!s_recVUMem[vuindex]->IsOk()) { - // upper 4 bits must be zero! - // Changed "first try base" to 0xf1e0000, since 0x0c000000 liked to fail a lot. (cottonvibes) - s_recVUMem = SysMmapEx(HostMemoryMap::sVUrec, VU_EXESIZE, 0x10000000, "SuperVUAlloc"); + safe_delete(s_recVUMem[vuindex]); + throw Exception::VirtualMemoryMapConflict() + .SetDiagMsg(pxsFmt( L"SuperVU failed to allocate virtual memory below 256MB." )) + .SetUserMsg(pxE( ".Error:superVU:VirtualMemoryAlloc", + L"Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory " + L"ranges required, and will not be available for use. This is not a critical error, since " + L"the sVU rec is obsolete, and you should use microVU instead anyway. :)" + )); - // Try again at some other random memory location... whatever. >_< - if( s_recVUMem == NULL ) - s_recVUMem = SysMmapEx(0xc2b0000, VU_EXESIZE, 0x10000000, "SuperVUAlloc"); - - if (s_recVUMem == NULL) - { - throw Exception::VirtualMemoryMapConflict() - .SetDiagMsg(pxsFmt( L"SuperVU failed to allocate virtual memory below 256MB." )) - .SetUserMsg(pxE( ".Error:superVU:VirtualMemoryAlloc", - L"Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory " - L"ranges required, and will not be available for use. This is not a critical error, since " - L"the sVU rec is obsolete, and you should use microVU instead anyway. :)" - )); - } - - ProfilerRegisterSource("sVU Rec", s_recVUMem, VU_EXESIZE); - - if (recVUStack == NULL) recVUStack = new u8[SUPERVU_STACKSIZE * 4]; - } - - if (vuindex >= 0) - { - pxAssert(s_recVUMem != NULL); - - if (recVUHeaders[vuindex] == NULL) - recVUHeaders[vuindex] = new VuFunctionHeader* [s_MemSize[vuindex] / 8]; - if (recVUBlocks[vuindex] == NULL) - recVUBlocks[vuindex] = new VuBlockHeader[s_MemSize[vuindex] / 8]; - if (s_plistCachedHeaders[vuindex] == NULL) - s_plistCachedHeaders[vuindex] = new list[s_MemSize[vuindex] / 8]; + ProfilerRegisterSource("sVU Rec", *s_recVUMem[vuindex], sVU_EXESIZE); } } @@ -416,72 +398,66 @@ void DestroyVUHeaders(int vuindex) // destroy VU resources void SuperVUDestroy(int vuindex) { - list::iterator it; + pxAssumeDev(vuindex >= 0 && vuindex <= 2, "Invalid VU index parameter!"); - if (vuindex < 0) - { - SuperVUDestroy(0); - SuperVUDestroy(1); - ProfilerTerminateSource("VURec"); - SafeSysMunmap(s_recVUMem, VU_EXESIZE); - safe_delete_array(recVUStack); - } - else - { - safe_delete_array(recVUHeaders[vuindex]); - safe_delete_array(recVUBlocks[vuindex]); + safe_delete_array(recVUHeaders[vuindex]); + safe_delete_array(recVUBlocks[vuindex]); - if (s_plistCachedHeaders[vuindex] != NULL) + if (s_plistCachedHeaders[vuindex] != NULL) + { + for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j) { - for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j) - { - DestroyCachedHeaders(vuindex, j); - } - safe_delete_array(s_plistCachedHeaders[vuindex]); + DestroyCachedHeaders(vuindex, j); } - DestroyVUHeaders(vuindex); + safe_delete_array(s_plistCachedHeaders[vuindex]); } + DestroyVUHeaders(vuindex); + + ProfilerTerminateSource(vuindex ? "sVU1Rec" : "sVU0Rec"); + + safe_delete(s_recVUMem[vuindex]); + safe_delete_array(recVUStack[vuindex]); } // reset VU void SuperVUReset(int vuindex) { + pxAssumeDev(vuindex >= 0 && vuindex <= 2, "Invalid VU index parameter!"); + #ifdef PCSX2_DEBUG s_vucount = 0; #endif - if (s_recVUMem == NULL) - return; + DevCon.WriteLn("SuperVU%d: Resetting function and block lists.", vuindex); - //pxAssume( s_recVUMem != NULL ); + if (recVUHeaders[vuindex] == NULL) + recVUHeaders[vuindex] = new VuFunctionHeader* [s_MemSize[vuindex] / 8]; + if (recVUBlocks[vuindex] == NULL) + recVUBlocks[vuindex] = new VuBlockHeader[s_MemSize[vuindex] / 8]; + if (s_plistCachedHeaders[vuindex] == NULL) + s_plistCachedHeaders[vuindex] = new std::list[s_MemSize[vuindex] / 8]; - if (vuindex < 0) + if (recVUHeaders[vuindex]) memset(recVUHeaders[vuindex], 0, sizeof(VuFunctionHeader*) * (s_MemSize[vuindex] / 8)); + if (recVUBlocks[vuindex]) memset(recVUBlocks[vuindex], 0, sizeof(VuBlockHeader) * (s_MemSize[vuindex] / 8)); + + if (s_plistCachedHeaders[vuindex] != NULL) { - DbgCon.WriteLn("SuperVU: Resetting recompiler memory and structures."); - - // Does this cause problems on VU recompiler resets? It could, if the VU works like - // the EE used to, and actually tries to re-enter the recBlock after issuing a clear. (air) - - //memset_8<0xcd, VU_EXESIZE>(s_recVUMem); - memzero_ptr(recVUStack); - - s_recVUPtr = s_recVUMem; - } - else - { - DbgCon.WriteLn("SuperVU [VU%d]: Resetting the recs and junk", vuindex); - if (recVUHeaders[vuindex]) memset(recVUHeaders[vuindex], 0, sizeof(VuFunctionHeader*) * (s_MemSize[vuindex] / 8)); - if (recVUBlocks[vuindex]) memset(recVUBlocks[vuindex], 0, sizeof(VuBlockHeader) * (s_MemSize[vuindex] / 8)); - - if (s_plistCachedHeaders[vuindex] != NULL) + for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j) { - for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j) - { - DestroyCachedHeaders(vuindex, j); - } + DestroyCachedHeaders(vuindex, j); } - DestroyVUHeaders(vuindex); } + DestroyVUHeaders(vuindex); + + if (!s_recVUMem[vuindex] || !s_recVUMem[vuindex]->IsOk()) return; + + DevCon.WriteLn("SuperVU%u: Resetting recompiler cache.", vuindex); + + if (!recVUStack[vuindex]) recVUStack[vuindex] = new u8[SUPERVU_STACKSIZE * 4]; + memzero_ptr(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& listinsts) static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex) { pxAssert(vuindex < 2); - pxAssert(s_recVUPtr != NULL); + pxAssert(s_recVUPtr[vuindex] != NULL); //Console.WriteLn("svu%c rec: %x", '0'+vuindex, startpc); // if recPtr reached the mem limit reset whole mem - if (((uptr)s_recVUPtr - (uptr)s_recVUMem) >= VU_EXESIZE - 0x40000) + if ((s_recVUPtr[vuindex] < s_recVUMem[vuindex]->GetPtr()) || (s_recVUPtr[vuindex] >= s_recVUMem[vuindex]->GetPtrEnd() - _256kb)) { - //Console.WriteLn("SuperVU reset mem"); + Console.WriteLn("SuperVU%u: Recompiler cache reset...", vuindex); SuperVUReset(0); SuperVUReset(1); - SuperVUReset(-1); if (s_TotalVUCycles > 0) { // already executing, so return NULL @@ -912,12 +887,12 @@ static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex) #endif // code generation - x86SetPtr(s_recVUPtr); + xSetPtr(s_recVUPtr[vuindex]); branch = 0; SuperVURecompile(); - s_recVUPtr = x86Ptr; + s_recVUPtr[vuindex] = xGetPtr(); // set the function's range VuFunctionHeader::RANGE r; @@ -947,7 +922,7 @@ static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex) } s_listBlocks.clear(); - pxAssert(s_recVUPtr < s_recVUMem + VU_EXESIZE); + pxAssertDev(s_recVUPtr[vuindex] < s_recVUMem[vuindex]->GetPtrEnd(), "SuperVU recompiler cache exceeded! (possible memory corruption)"); return s_pFnHeader; } @@ -2697,18 +2672,18 @@ void SuperVUFlush(int p, int wait) // executed only once per program static u32* SuperVUStaticAlloc(u32 size) { - pxAssert(recVUStackPtr + size <= recVUStack + SUPERVU_STACKSIZE); + pxAssert(recVUStackPtr[s_vu] + size <= recVUStack[s_vu] + SUPERVU_STACKSIZE); // always zero - if (size == 4) *(u32*)recVUStackPtr = 0; - else memset(recVUStackPtr, 0, size); - recVUStackPtr += size; - return (u32*)(recVUStackPtr - size); + if (size == 4) *(u32*)recVUStackPtr[s_vu] = 0; + else memset(recVUStackPtr[s_vu], 0, size); + recVUStackPtr[s_vu] += size; + return (u32*)(recVUStackPtr[s_vu] - size); } static void SuperVURecompile() { // save cpu state - recVUStackPtr = recVUStack; + recVUStackPtr[s_vu] = recVUStack[s_vu]; _initXMMregs(); @@ -4617,9 +4592,9 @@ recSuperVU0::recSuperVU0() IsInterpreter = false; } -void recSuperVU0::Allocate() +void recSuperVU0::Reserve() { - SuperVUAlloc( 0 ); + SuperVUAlloc(0); } void recSuperVU0::Shutdown() throw() @@ -4645,6 +4620,15 @@ void recSuperVU0::Clear(u32 Addr, u32 Size) SuperVUClear(Addr, Size, 0); } +uint recSuperVU0::GetCacheReserve() const +{ + return sVU_EXESIZE / _1mb; +} + +void recSuperVU0::SetCacheReserve( uint reserveInMegs ) const +{ + //microVU0.cacheSize = reserveInMegs * _1mb; +} // -------------------------------------------------------------------------------------- // recSuperVU1 Interface @@ -4655,9 +4639,9 @@ recSuperVU1::recSuperVU1() IsInterpreter = false; } -void recSuperVU1::Allocate() +void recSuperVU1::Reserve() { - SuperVUAlloc( 1 ); + SuperVUAlloc(1); } void recSuperVU1::Shutdown() throw() @@ -4670,6 +4654,16 @@ void recSuperVU1::Reset() SuperVUReset( 1 ); } +uint recSuperVU1::GetCacheReserve() const +{ + return sVU_EXESIZE / _1mb; +} + +void recSuperVU1::SetCacheReserve( uint reserveInMegs ) const +{ + //microVU0.cacheSize = reserveInMegs * _1mb; +} + #if 0 #include "sVU_Compare.h" #else From 4dec10976d1ee220987d3f287f31bcd74bd2ef6f Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Wed, 27 Oct 2010 23:22:19 +0000 Subject: [PATCH 05/22] newHostVM: Working on linux side now ... (WIP) git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@3976 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/src/Utilities/VirtualMemory.cpp | 28 +++++++++++++++++++++ common/src/Utilities/Windows/WinHostSys.cpp | 14 ----------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/common/src/Utilities/VirtualMemory.cpp b/common/src/Utilities/VirtualMemory.cpp index 8eab5a1edc..6e6915b677 100644 --- a/common/src/Utilities/VirtualMemory.cpp +++ b/common/src/Utilities/VirtualMemory.cpp @@ -201,3 +201,31 @@ void* SpatialArrayReserve::Reserve( uint size, uptr base, uptr upper_bounds ) { return __parent::Reserve( size, base, upper_bounds ); } + +void SpatialArrayReserve::OnCommittedBlock( void* block ) +{ + +} + +void SpatialArrayReserve::OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled ) +{ + +} + + +// -------------------------------------------------------------------------------------- +// PageProtectionMode (implementations) +// -------------------------------------------------------------------------------------- +wxString PageProtectionMode::ToString() const +{ + wxString modeStr; + + if (m_read) modeStr += L"Read"; + if (m_write) modeStr += L"Write"; + if (m_exec) modeStr += L"Exec"; + + if (modeStr.IsEmpty()) return L"NoAccess"; + if (modeStr.Length() <= 5) modeStr += L"Only"; + + return modeStr; +} diff --git a/common/src/Utilities/Windows/WinHostSys.cpp b/common/src/Utilities/Windows/WinHostSys.cpp index 5a63dad085..22237ba0a4 100644 --- a/common/src/Utilities/Windows/WinHostSys.cpp +++ b/common/src/Utilities/Windows/WinHostSys.cpp @@ -82,17 +82,3 @@ void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& )); } } - -wxString PageProtectionMode::ToString() const -{ - wxString modeStr; - - if (m_read) modeStr += L"Read"; - if (m_write) modeStr += L"Write"; - if (m_exec) modeStr += L"Exec"; - - if (modeStr.IsEmpty()) return L"NoAccess"; - if (modeStr.Length() <= 5) modeStr += L"Only"; - - return modeStr; -} From 283224290de99808de71276304a8ec62b8ec6827 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Wed, 27 Oct 2010 23:58:10 +0000 Subject: [PATCH 06/22] newHostVM: Fix linux/gcc compilation errors. PCSX2 doesn't work yet tho -- crashes on startup and I don't have a proper debug environment setup to trace and troubleshoot it. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@3977 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/src/Utilities/CMakeLists.txt | 2 +- common/src/Utilities/Linux/LnxHostSys.cpp | 25 ++++++++++++----------- pcsx2/Linux/LnxHostSys.cpp | 8 +++++--- pcsx2/System.cpp | 4 ++-- pcsx2/x86/microVU.cpp | 2 +- 5 files changed, 22 insertions(+), 19 deletions(-) diff --git a/common/src/Utilities/CMakeLists.txt b/common/src/Utilities/CMakeLists.txt index a659c5b4c0..7b61fcd33b 100644 --- a/common/src/Utilities/CMakeLists.txt +++ b/common/src/Utilities/CMakeLists.txt @@ -146,7 +146,7 @@ set(UtilitiesHeaders ../../include/Utilities/HashMap.h ../../include/Utilities/lnx_memzero.h ../../include/Utilities/MemcpyFast.h - ../../include/Utilities/MemsetFast.h + ../../include/Utilities/MemsetFast.inl ../../include/Utilities/Path.h ../../include/Utilities/PageFaultSource.h ../../include/Utilities/pxCheckBox.h diff --git a/common/src/Utilities/Linux/LnxHostSys.cpp b/common/src/Utilities/Linux/LnxHostSys.cpp index a453b03e8f..16c5a22161 100644 --- a/common/src/Utilities/Linux/LnxHostSys.cpp +++ b/common/src/Utilities/Linux/LnxHostSys.cpp @@ -18,10 +18,11 @@ #include #include +#include static __ri void PageSizeAssertionTest( size_t size ) { - pxAssert( (__pagesize == getpagesize()), pxsFmt( + pxAssertMsg( (__pagesize == getpagesize()), pxsFmt( "Internal system error: Operating system pagesize does not match compiled pagesize.\n\t" L"\tOS Page Size: 0x%x (%d), Compiled Page Size: 0x%x (%u)", getpagesize(), getpagesize(), __pagesize, __pagesize ) @@ -64,26 +65,26 @@ void HostSys::MmapReset(void* base, size_t size) // pretty well stops all PCSX2 threads anyway). Munmap(base, size); - void* result = Mmap(base, size); + void* result = Mmap((uptr)base, size); - pxAssertRel (result != base, pxsFmt( + pxAssertRel ((uptr)result != (uptr)base, pxsFmt( "Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped. " "This is likely caused by multi-thread memory contention.", base, base+size )); } -void* HostSys::Mmap(void* base, size_t size) +void* HostSys::Mmap(uptr base, size_t size) { PageSizeAssertionTest(size); // MAP_ANONYMOUS - means we have no associated file handle (or device). - return mmap(base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + return mmap((void*)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } -void HostSys::Munmap(void* base, size_t size) +void HostSys::Munmap(uptr base, size_t size) { - munmap(base, size); + munmap((void*)base, size); } void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode ) @@ -103,20 +104,20 @@ void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& switch(errno) { case EINVAL: - pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)"), - baseaddr, (uptr)baseaddr+size, mode.ToString().c_str() + pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)", + baseaddr, (uptr)baseaddr+size, mode.ToString().c_str()) ); break; case ENOMEM: - throw Exception::OutOfMemory( psxFmt( L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)"), - baseaddr, (uptr)baseaddr+size, mode.ToString().c_str() + throw Exception::OutOfMemory( pxsFmt( L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)", + baseaddr, (uptr)baseaddr+size, mode.ToString().c_str()) ); break; case EACCES: break; } - throw Exception::OutOfMemory() + throw Exception::OutOfMemory(); } } diff --git a/pcsx2/Linux/LnxHostSys.cpp b/pcsx2/Linux/LnxHostSys.cpp index 709539334f..1d46634e7d 100644 --- a/pcsx2/Linux/LnxHostSys.cpp +++ b/pcsx2/Linux/LnxHostSys.cpp @@ -18,7 +18,8 @@ #include #include #include "Common.h" -#include "System/PageFaultSource.h" + +#include "Utilities/PageFaultSource.h" extern void SignalExit(int sig); @@ -30,11 +31,11 @@ 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 ) ); + 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( 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. @@ -45,6 +46,7 @@ static void SysPageFaultSignalFilter( int signal, siginfo_t *siginfo, void * ) void InstallSignalHandler() { + Console.WriteLn("Installing POSIX SIGSEGV handler..."); struct sigaction sa; sigemptyset(&sa.sa_mask); diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index ecb33f9d90..9a4a349650 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -510,14 +510,14 @@ u8* SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller) if( (Mem == NULL) || (bounds != 0 && (((uptr)Mem + size) > bounds)) ) { - if( base != NULL ) + if( base ) { DbgCon.Warning( "First try failed allocating %s at address 0x%x", caller, base ); // Let's try again at an OS-picked memory area, and then hope it meets needed // boundschecking criteria below. SafeSysMunmap( Mem, size ); - Mem = (u8*)HostSys::Mmap( NULL, size ); + Mem = (u8*)HostSys::Mmap( 0, size ); } if( (bounds != 0) && (((uptr)Mem + size) > bounds) ) diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp index f6c409cb99..976f4f9306 100644 --- a/pcsx2/x86/microVU.cpp +++ b/pcsx2/x86/microVU.cpp @@ -18,7 +18,7 @@ #include "PrecompiledHeader.h" #include "Common.h" #include "microVU.h" -#include "RecTypes.h" +#include "System/RecTypes.h" // Include all the *.inl files (Needed because C++ sucks with templates and *.cpp files) #include "microVU_Clamp.inl" From a61e678a12231d8a3852fa5f55701aa74aa3b15c Mon Sep 17 00:00:00 2001 From: arcum42 Date: Thu, 28 Oct 2010 10:49:45 +0000 Subject: [PATCH 07/22] newHostVM: Fix linux/gcc crash on startup. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@3978 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/src/Utilities/Linux/LnxHostSys.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/Utilities/Linux/LnxHostSys.cpp b/common/src/Utilities/Linux/LnxHostSys.cpp index 16c5a22161..8a7b451531 100644 --- a/common/src/Utilities/Linux/LnxHostSys.cpp +++ b/common/src/Utilities/Linux/LnxHostSys.cpp @@ -99,7 +99,7 @@ void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& int result = mprotect( baseaddr, size, lnxmode ); - if (!result) + if (result != 0) { switch(errno) { From b568256653da1975b69db3ca074822b1fe57aed9 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Thu, 28 Oct 2010 13:14:18 +0000 Subject: [PATCH 08/22] newHostVM: improving error handling and memory management (WIP) git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@3979 96395faa-99c1-11dd-bbfe-3dabce05a288 --- pcsx2/R3000A.h | 3 ++ pcsx2/R5900.h | 3 ++ pcsx2/x86/iR3000A.cpp | 16 +++++++++- pcsx2/x86/ix86-32/iR5900-32.cpp | 54 +++++++++++++++++++++++++++++++-- 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/pcsx2/R3000A.h b/pcsx2/R3000A.h index b384a17253..143abc101a 100644 --- a/pcsx2/R3000A.h +++ b/pcsx2/R3000A.h @@ -189,6 +189,9 @@ struct R3000Acpu { s32 (*ExecuteBlock)( s32 eeCycles ); // executes the given number of EE cycles. void (*Clear)(u32 Addr, u32 Size); void (*Shutdown)(); + + uint (*GetCacheReserve)(); + void (*SetCacheReserve)( uint reserveInMegs ); }; extern R3000Acpu *psxCpu; diff --git a/pcsx2/R5900.h b/pcsx2/R5900.h index fa67c562e1..227bc9018f 100644 --- a/pcsx2/R5900.h +++ b/pcsx2/R5900.h @@ -376,6 +376,9 @@ struct R5900cpu // doesn't matter if we're stripping it out soon. ;) // void (*Clear)(u32 Addr, u32 Size); + + uint (*GetCacheReserve)(); + void (*SetCacheReserve)( uint reserveInMegs ); }; extern R5900cpu *Cpu; diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp index 2886d53080..83bd77cbea 100644 --- a/pcsx2/x86/iR3000A.cpp +++ b/pcsx2/x86/iR3000A.cpp @@ -1397,12 +1397,26 @@ StartRecomp: s_pCurBlockEx = NULL; } +static void recSetCacheReserve( uint reserveInMegs ) +{ + //m_ConfiguredCacheReserve = reserveInMegs * _1mb; +} + +static uint recGetCacheReserve() +{ + return 0; + //return m_ConfiguredCacheReserve / _1mb; +} + R3000Acpu psxRec = { recReserve, recResetIOP, recExecute, recExecuteBlock, recClearIOP, - recShutdown + recShutdown, + + recGetCacheReserve, + recSetCacheReserve }; diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index 3c90e9a28b..d30b998a65 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -64,6 +64,7 @@ bool g_cpuFlushedPC, g_cpuFlushedCode, g_recompilingDelaySlot, g_maySignalExcept static const int RECCONSTBUF_SIZE = 16384 * 2; // 64 bit consts in 32 bit units static RecompiledCodeReserve* recMem = NULL; +static uptr m_ConfiguredCacheReserve = _64mb; static u32* recConstBuf = NULL; // 64-bit pseudo-immediates static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here @@ -548,6 +549,42 @@ static void recThrowHardwareDeficiency( const wxChar* extFail ) .SetUserMsg(pxsFmt(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )); } +// This error message is shared by R5900, R3000, and microVU recompilers. It is not used by the +// SuperVU recompiler, since it has its own customized message. +wxString GetMsg_RecVmFailed( const char* recName ) +{ + return pxE( ".Error:Recompiler:VirtualMemoryAlloc", + pxsFmt( + "The %s recompiler was unable to reserve contiguous memory required " + "for internal caches. This problem may be fixable by reducing the default " + "cache sizes for all PCSX2 recompilers, found under Host Settings.", + recName + ) + ); +} + +static void recReserveCache() +{ + if (!recMem) recMem = new RecompiledCodeReserve(L"R5900-32 Recompiler Cache", _1mb * 4); + + recMem->Reserve( m_ConfiguredCacheReserve, HostMemoryMap::EErec ); + + while (!recMem->IsOk() && (m_ConfiguredCacheReserve >= 16)) + { + m_ConfiguredCacheReserve /= 2; + recMem->Reserve( m_ConfiguredCacheReserve * _1mb, HostMemoryMap::EErec ); + } + + if (!recMem->IsOk()) + { + throw Exception::VirtualMemoryMapConflict() + .SetDiagMsg(pxsFmt( L"R5900-32 recompiled code cache could not be mapped." )) + .SetUserMsg(GetMsg_RecVmFailed("R5900-32")); + } + + ProfilerRegisterSource( "EE Rec", *recMem, recMem->GetReserveSizeInBytes() ); +} + static void recReserve() { // Hardware Requirements Check... @@ -561,8 +598,7 @@ static void recReserve() if ( !x86caps.hasStreamingSIMD2Extensions ) recThrowHardwareDeficiency( L"SSE2" ); - recMem = new RecompiledCodeReserve(L"R5900-32 Recompiler Cache", _1mb * 4); - recMem->Reserve( _64mb, HostMemoryMap::EErec ); + recReserveCache(); } static void recAlloc() @@ -595,7 +631,6 @@ static void recAlloc() // No errors.. Proceed with initialization: - ProfilerRegisterSource( "EE Rec", *recMem, recMem->GetReserveSizeInBytes() ); _DynGen_Dispatchers(); x86FpuState = FPU_STATE; @@ -1885,6 +1920,16 @@ static void recThrowException( const BaseException& ex ) #endif } +static void recSetCacheReserve( uint reserveInMegs ) +{ + m_ConfiguredCacheReserve = reserveInMegs * _1mb; +} + +static uint recGetCacheReserve() +{ + return m_ConfiguredCacheReserve / _1mb; +} + R5900cpu recCpu = { recReserve, @@ -1898,4 +1943,7 @@ R5900cpu recCpu = recThrowException, recThrowException, recClear, + + recGetCacheReserve, + recSetCacheReserve, }; From bd8127f75e7fbd865af8b82cfc01545c658785ac Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Fri, 29 Oct 2010 02:49:01 +0000 Subject: [PATCH 09/22] newHostVM: More error/exception handling WIP stuff. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@3980 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/include/Utilities/Exceptions.h | 9 ++++-- common/include/Utilities/PageFaultSource.h | 3 +- common/include/Utilities/SafeArray.inl | 21 +++++++------ common/src/Utilities/Exceptions.cpp | 34 ++++++++++++++++++++-- pcsx2/Memory.cpp | 3 +- pcsx2/gui/AppInit.cpp | 3 +- pcsx2/x86/ix86-32/iR5900-32.cpp | 2 +- pcsx2/x86/sVU_zerorec.cpp | 2 +- 8 files changed, 56 insertions(+), 21 deletions(-) diff --git a/common/include/Utilities/Exceptions.h b/common/include/Utilities/Exceptions.h index ca73656774..be7951c720 100644 --- a/common/include/Utilities/Exceptions.h +++ b/common/include/Utilities/Exceptions.h @@ -209,7 +209,7 @@ public: \ // class OutOfMemory : public RuntimeError { - DEFINE_RUNTIME_EXCEPTION( OutOfMemory, RuntimeError, wxLt("Out of memory?!") ) + DEFINE_RUNTIME_EXCEPTION( OutOfMemory, RuntimeError, wxEmptyString ) public: wxString AllocDescription; @@ -236,7 +236,12 @@ public: \ // we'd really like to have access to. class VirtualMemoryMapConflict : public OutOfMemory { - DEFINE_RUNTIME_EXCEPTION( VirtualMemoryMapConflict, OutOfMemory, wxLt("Virtual memory map confict: Unable to claim specific required memory regions.") ) + DEFINE_RUNTIME_EXCEPTION( VirtualMemoryMapConflict, OutOfMemory, wxEmptyString ) + + VirtualMemoryMapConflict( const wxString& allocdesc ); + + virtual wxString FormatDisplayMessage() const; + virtual wxString FormatDiagnosticMessage() const; }; class HardwareDeficiency : public RuntimeError diff --git a/common/include/Utilities/PageFaultSource.h b/common/include/Utilities/PageFaultSource.h index bf64331fe2..5073744c51 100644 --- a/common/include/Utilities/PageFaultSource.h +++ b/common/include/Utilities/PageFaultSource.h @@ -133,7 +133,8 @@ public: virtual void Free(); 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; } diff --git a/common/include/Utilities/SafeArray.inl b/common/include/Utilities/SafeArray.inl index 259651176f..a381c47422 100644 --- a/common/include/Utilities/SafeArray.inl +++ b/common/include/Utilities/SafeArray.inl @@ -31,7 +31,8 @@ SafeArray::SafeArray( const wxChar* name, T* allocated_mem, int initSize ) m_size = initSize; if( m_ptr == NULL ) - throw Exception::OutOfMemory(name + wxsFormat(L" (SafeArray::constructor) [size=%d]", initSize)); + throw Exception::OutOfMemory(name) + .SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initSize)); } template< typename T > @@ -79,7 +80,8 @@ SafeArray::SafeArray( int initialSize, const wxChar* name ) m_size = initialSize; if( (initialSize != 0) && (m_ptr == NULL) ) - throw Exception::OutOfMemory(name + wxsFormat(L" (SafeArray::constructor) [size=%d]", initialSize)); + throw Exception::OutOfMemory(name) + .SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initialSize)); } // Clears the contents of the array to zero, and frees all memory allocations. @@ -106,9 +108,8 @@ void SafeArray::ExactAlloc( int newsize ) m_ptr = _virtual_realloc( newsize ); if( m_ptr == NULL ) - throw Exception::OutOfMemory(Name + - wxsFormat(L" (SafeArray::ExactAlloc) [oldsize=%d] [newsize=%d]", m_size, newsize) - ); + throw Exception::OutOfMemory(Name) + .SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ExactAlloc' [oldsize=%d] [newsize=%d]", m_size, newsize)); m_size = newsize; } @@ -199,9 +200,8 @@ SafeList::SafeList( int initialSize, const wxChar* name ) m_ptr = (T*)malloc( initialSize * sizeof(T) ); if( m_ptr == NULL ) - throw Exception::OutOfMemory(Name + - wxsFormat(L" (SafeList::Constructor) [length=%d]", m_length) - ); + throw Exception::OutOfMemory(Name) + .SetDiagMsg(wxsFormat(L"called from 'SafeList::ctor' [length=%d]", m_length)); for( int i=0; i::MakeRoomFor( int blockSize ) const int newalloc = blockSize + ChunkSize; m_ptr = _virtual_realloc( newalloc ); if( m_ptr == NULL ) - throw Exception::OutOfMemory(Name + - wxsFormat(L" (SafeList::MakeRoomFor) [oldlen=%d] [newlen=%d]", m_length, blockSize) - ); + throw Exception::OutOfMemory(Name) + .SetDiagMsg(wxsFormat(L"Called from 'SafeList::MakeRoomFor' [oldlen=%d] [newlen=%d]", m_length, blockSize)); for( ; m_allocsize failed to allocate PS2's base ram/rom/scratchpad." ); + 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(); diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index 8b448aa737..755907a65b 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -531,8 +531,9 @@ bool Pcsx2App::OnInit() g_Conf = new AppConfig(); wxInitAllImageHandlers(); - Console.WriteLn("Begin parsing commandline..."); + Console.WriteLn("Command line parsing..."); if( !_parent::OnInit() ) return false; + Console.WriteLn("Command line parsed!"); wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() ); diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index d30b998a65..d07e3039b2 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -577,7 +577,7 @@ static void recReserveCache() if (!recMem->IsOk()) { - throw Exception::VirtualMemoryMapConflict() + throw Exception::VirtualMemoryMapConflict(recMem->GetName()) .SetDiagMsg(pxsFmt( L"R5900-32 recompiled code cache could not be mapped." )) .SetUserMsg(GetMsg_RecVmFailed("R5900-32")); } diff --git a/pcsx2/x86/sVU_zerorec.cpp b/pcsx2/x86/sVU_zerorec.cpp index 43e1bf55e6..5183167940 100644 --- a/pcsx2/x86/sVU_zerorec.cpp +++ b/pcsx2/x86/sVU_zerorec.cpp @@ -357,7 +357,7 @@ static void SuperVUAlloc(int vuindex) if (!s_recVUMem[vuindex]->IsOk()) { safe_delete(s_recVUMem[vuindex]); - throw Exception::VirtualMemoryMapConflict() + throw Exception::VirtualMemoryMapConflict( s_recVUMem[vuindex]->GetName() ) .SetDiagMsg(pxsFmt( L"SuperVU failed to allocate virtual memory below 256MB." )) .SetUserMsg(pxE( ".Error:superVU:VirtualMemoryAlloc", L"Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory " From 5579350d2260639110e76783b04db85d030a7991 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Wed, 3 Nov 2010 14:18:30 +0000 Subject: [PATCH 10/22] newHostVM: * Moved profiler management to the RecompiledCodeReserve class. * Improved error handling some more. * Numerous minor cleanups. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@3991 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/include/Utilities/Dependencies.h | 1 + common/include/Utilities/General.h | 11 ++- common/src/Utilities/Linux/LnxHostSys.cpp | 31 +++++-- common/src/Utilities/VirtualMemory.cpp | 24 +---- common/src/Utilities/Windows/WinHostSys.cpp | 69 ++++++++------ pcsx2/Interpreter.cpp | 11 +++ pcsx2/R3000AInterpreter.cpp | 14 ++- pcsx2/R5900.cpp | 1 - pcsx2/SamplProf.h | 4 + pcsx2/System.cpp | 99 ++++++++++++++++++++- pcsx2/System/RecTypes.h | 21 ++++- pcsx2/gui/AppInit.cpp | 12 +-- pcsx2/windows/SamplProf.cpp | 44 +++++---- pcsx2/x86/iR3000A.cpp | 41 ++++++--- pcsx2/x86/ix86-32/iR5900-32.cpp | 35 ++++---- pcsx2/x86/microVU.cpp | 43 ++++----- pcsx2/x86/microVU.h | 11 +-- pcsx2/x86/sVU_zerorec.cpp | 10 +-- 18 files changed, 328 insertions(+), 154 deletions(-) diff --git a/common/include/Utilities/Dependencies.h b/common/include/Utilities/Dependencies.h index 69018be958..25fd3bd22c 100644 --- a/common/include/Utilities/Dependencies.h +++ b/common/include/Utilities/Dependencies.h @@ -185,6 +185,7 @@ static const sptr _256kb = _128kb * 2; static const s64 _1mb = 0x100000; static const s64 _8mb = _1mb * 8; static const s64 _16mb = _1mb * 16; +static const s64 _32mb = _1mb * 32; static const s64 _64mb = _1mb * 64; static const s64 _256mb = _1mb * 256; static const s64 _1gb = _256mb * 4; diff --git a/common/include/Utilities/General.h b/common/include/Utilities/General.h index cc66993397..4946f33c6c 100644 --- a/common/include/Utilities/General.h +++ b/common/include/Utilities/General.h @@ -172,10 +172,11 @@ public: m_read = m_write = m_exec = allow; return *this; } - + bool CanRead() const { return m_read; } bool CanWrite() const { return m_write; } bool CanExecute() const { return m_exec && m_read; } + bool IsNone() const { return !m_read && !m_write; } wxString ToString() const; }; @@ -218,8 +219,12 @@ static __fi PageProtectionMode PageAccess_Any() namespace HostSys { void* MmapReserve(uptr base, size_t size); - void MmapCommit(void* base, size_t size); - void MmapReset(void* base, size_t size); + void MmapCommit(uptr base, size_t size, const PageProtectionMode& mode); + void MmapReset(uptr base, size_t size); + + void* MmapReservePtr(void* base, size_t size); + void MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode); + void MmapResetPtr(void* base, size_t size); // Maps a block of memory for use as a recompiled code buffer. // Returns NULL on allocation failure. diff --git a/common/src/Utilities/Linux/LnxHostSys.cpp b/common/src/Utilities/Linux/LnxHostSys.cpp index 8a7b451531..4b9689b5d4 100644 --- a/common/src/Utilities/Linux/LnxHostSys.cpp +++ b/common/src/Utilities/Linux/LnxHostSys.cpp @@ -35,7 +35,7 @@ static __ri void PageSizeAssertionTest( size_t size ) ); } -void* HostSys::MmapReserve(uptr base, size_t size) +void* HostSys::MmapReservePtr(void* base, size_t size) { PageSizeAssertionTest(size); @@ -43,17 +43,21 @@ void* HostSys::MmapReserve(uptr base, size_t size) // or anonymous source, with PROT_NONE (no-access) permission. Since the mapping // is completely inaccessible, the OS will simply reserve it and will not put it // against the commit table. - return mmap((void*)base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + return mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } -void HostSys::MmapCommit(void* base, size_t size) +void HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode) { // In linux, reserved memory is automatically committed when its permissions are - // changed to something other than PROT_NONE. Since PCSX2 code *must* do that itself - // prior to making use of memory anyway, this call should be a NOP. + // changed to something other than PROT_NONE. If the user is committing memory + // as PROT_NONE, then just ignore this call (memory will be committed automatically + // later when the user changes permissions to something useful via calls to MemProtect). + + if (mode.IsNone()) return; + MemProtect( base, size, mode ); } -void HostSys::MmapReset(void* base, size_t size) +void HostSys::MmapResetPtr(void* base, size_t size) { // On linux the only way to reset the memory is to unmap and remap it as PROT_NONE. // That forces linux to unload all committed pages and start from scratch. @@ -73,6 +77,21 @@ void HostSys::MmapReset(void* base, size_t size) )); } +void* HostSys::MmapReserve(uptr base, size_t size) +{ + return MmapReservePtr((void*)base, size); +} + +void HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode) +{ + MmapCommitPtr( (void*)base, size, mode ); +} + +void HostSys::MmapReset(uptr base, size_t size) +{ + MmapResetPtr((void*)base, size); +} + void* HostSys::Mmap(uptr base, size_t size) { PageSizeAssertionTest(size); diff --git a/common/src/Utilities/VirtualMemory.cpp b/common/src/Utilities/VirtualMemory.cpp index 6e6915b677..393d1d602e 100644 --- a/common/src/Utilities/VirtualMemory.cpp +++ b/common/src/Utilities/VirtualMemory.cpp @@ -85,7 +85,7 @@ void* BaseVirtualMemoryReserve::Reserve( uint size, uptr base, uptr upper_bounds // 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 ); + m_baseptr = HostSys::MmapReserve( 0, reserved_bytes ); } if ((upper_bounds != 0) && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)) @@ -100,20 +100,6 @@ void* BaseVirtualMemoryReserve::Reserve( uint size, uptr base, uptr upper_bounds 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 -void* HostSys::MmapReserve(uptr base, size_t size) +static DWORD ConvertToWinApi( const PageProtectionMode& mode ) { - return VirtualAlloc((void*)base, size, MEM_RESERVE, PAGE_NOACCESS); + DWORD winmode = PAGE_NOACCESS; + + // Windows has some really bizarre memory protection enumeration that uses bitwise + // numbering (like flags) but is in fact not a flag value. *Someone* from the early + // microsoft days wasn't a very good coder, me thinks. --air + + if (mode.CanExecute()) + { + winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ; + } + else if (mode.CanRead()) + { + winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY; + } + + return winmode; } -void HostSys::MmapCommit(void* base, size_t size) +void* HostSys::MmapReservePtr(void* base, size_t size) { - // Execution flag for this and the Reserve should match... ? - void* result = VirtualAlloc(base, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + return VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS); +} + +void HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode) +{ + void* result = VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)); pxAssumeDev(result, L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows()); } -void HostSys::MmapReset(void* base, size_t size) +void HostSys::MmapResetPtr(void* base, size_t size) { - // Execution flag is actually irrelevant for this operation, but whatever. - //void* result = VirtualAlloc((void*)base, size, MEM_RESET, PAGE_EXECUTE_READWRITE); - //pxAssumeDev(result, L"VirtualAlloc RESET failed: " + Exception::WinApiError().GetMsgFromWindows()); - VirtualFree(base, size, MEM_DECOMMIT); } + +void* HostSys::MmapReserve(uptr base, size_t size) +{ + return MmapReservePtr((void*)base, size); +} + +void HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode) +{ + MmapCommitPtr( (void*)base, size, mode ); +} + +void HostSys::MmapReset(uptr base, size_t size) +{ + MmapResetPtr((void*)base, size); +} + + void* HostSys::Mmap(uptr base, size_t size) { return VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); @@ -57,24 +89,9 @@ void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)", __pagesize, __pagesize, size, size ) ); - - DWORD winmode = PAGE_NOACCESS; - - // Windows has some really bizarre memory protection enumeration that uses bitwise - // numbering (like flags) but is in fact not a flag value. *Someone* from the early - // microsoft days wasn't a very good coder, me thinks. --air - - if (mode.CanExecute()) - { - winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ; - } - else if (mode.CanRead()) - { - winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY; - } DWORD OldProtect; // enjoy my uselessness, yo! - if (!VirtualProtect( baseaddr, size, winmode, &OldProtect )) + if (!VirtualProtect( baseaddr, size, ConvertToWinApi(mode), &OldProtect )) { throw Exception::WinApiError().SetDiagMsg( pxsFmt(L"VirtualProtect failed @ 0x%08X -> 0x%08X (mode=%s)", diff --git a/pcsx2/Interpreter.cpp b/pcsx2/Interpreter.cpp index ddc463d37b..9744295304 100644 --- a/pcsx2/Interpreter.cpp +++ b/pcsx2/Interpreter.cpp @@ -437,6 +437,14 @@ static void intThrowException( const BaseException& ex ) ex.Rethrow(); } +static void intSetCacheReserve( uint reserveInMegs ) +{ +} + +static uint intGetCacheReserve() +{ + return 0; +} R5900cpu intCpu = { @@ -451,4 +459,7 @@ R5900cpu intCpu = intThrowException, intThrowException, intClear, + + intGetCacheReserve, + intSetCacheReserve, }; diff --git a/pcsx2/R3000AInterpreter.cpp b/pcsx2/R3000AInterpreter.cpp index dcf6dd1698..1722932123 100644 --- a/pcsx2/R3000AInterpreter.cpp +++ b/pcsx2/R3000AInterpreter.cpp @@ -184,11 +184,23 @@ static void intClear(u32 Addr, u32 Size) { static void intShutdown() { } +static void intSetCacheReserve( uint reserveInMegs ) +{ +} + +static uint intGetCacheReserve() +{ + return 0; +} + R3000Acpu psxInt = { intReserve, intReset, intExecute, intExecuteBlock, intClear, - intShutdown + intShutdown, + + intGetCacheReserve, + intSetCacheReserve }; diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index 6c5d915256..d093da9fcb 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -32,7 +32,6 @@ #include "CDVD/CDVD.h" #include "Patch.h" #include "GameDatabase.h" -#include "SamplProf.h" using namespace R5900; // for R5900 disasm tools diff --git a/pcsx2/SamplProf.h b/pcsx2/SamplProf.h index 5ad112293d..7fa918d7c6 100644 --- a/pcsx2/SamplProf.h +++ b/pcsx2/SamplProf.h @@ -30,6 +30,10 @@ void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz); void ProfilerRegisterSource(const char* Name, const void* function); void ProfilerTerminateSource( const char* Name ); +void ProfilerRegisterSource(const wxString& Name, const void* buff, u32 sz); +void ProfilerRegisterSource(const wxString& Name, const void* function); +void ProfilerTerminateSource( const wxString& Name ); + #else // Disables the profiler in Debug & Linux builds. diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index 9a4a349650..b27563f54c 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -18,6 +18,8 @@ #include "IopCommon.h" #include "VUmicro.h" +#include "SamplProf.h" + // Includes needed for cleanup, since we don't have a good system (yet) for // cleaning up these things. #include "GameDatabase.h" @@ -34,14 +36,104 @@ extern void resetNewVif(int idx); // -------------------------------------------------------------------------------------- // RecompiledCodeReserve (implementations) // -------------------------------------------------------------------------------------- + +// Constructor! +// Parameters: +// name - a nice long name that accurately describes the contents of this reserve. RecompiledCodeReserve::RecompiledCodeReserve( const wxString& name, uint defCommit ) : BaseVirtualMemoryReserve( name ) { m_block_size = (1024 * 128) / __pagesize; m_prot_mode = PageAccess_Any(); m_def_commit = defCommit / __pagesize; + + m_profiler_registered = false; } +RecompiledCodeReserve::~RecompiledCodeReserve() throw() +{ + _termProfiler(); +} + +void RecompiledCodeReserve::_registerProfiler() +{ + if (m_profiler_name.IsEmpty() || !IsOk()) return; + ProfilerRegisterSource( m_profiler_name, m_baseptr, GetReserveSizeInBytes() ); + m_profiler_registered = true; +} + +void RecompiledCodeReserve::_termProfiler() +{ + if (m_profiler_registered) + ProfilerTerminateSource( m_profiler_name ); +} + +void* RecompiledCodeReserve::Reserve( uint size, uptr base, uptr upper_bounds ) +{ + if (!__parent::Reserve(size, base, upper_bounds)) return NULL; + _registerProfiler(); + return m_baseptr; +} + + +// If growing the array, or if shrinking the array to some point that's still *greater* than the +// committed memory range, then attempt a passive "on-the-fly" resize that maps/unmaps some portion +// of the reserve. +// +// If the above conditions are not met, or if the map/unmap fails, this method returns false. +// The caller will be responsible for manually resetting the reserve. +// +// Parameters: +// newsize - new size of the reserved buffer, in bytes. +bool RecompiledCodeReserve::TryResize( uint newsize ) +{ + uint newPages = (newsize + __pagesize - 1) / __pagesize; + + if (newPages > m_reserved) + { + uint toReservePages = newPages - m_reserved; + uint toReserveBytes = toReservePages * __pagesize; + + DevCon.WriteLn( L"%-32s is being expanded by %u pages.", Name.c_str(), toReservePages); + + m_baseptr = (void*)HostSys::MmapReserve((uptr)GetPtrEnd(), toReserveBytes); + + if (!m_baseptr) + { + Console.Warning("%-32s could not be passively resized due to virtual memory conflict!"); + Console.Indent().Warning("(attempted to map memory @ 0x%08X -> 0x%08X", m_baseptr, (uptr)m_baseptr+toReserveBytes); + } + + 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) + { + if (m_commited > newsize) return false; + + uint toRemovePages = m_reserved - newPages; + uint toRemoveBytes = toRemovePages * __pagesize; + + DevCon.WriteLn( L"%-32s is being shrunk by %u pages.", Name.c_str(), toRemovePages); + + HostSys::MmapResetPtr(GetPtrEnd(), toRemoveBytes); + + DevCon.WriteLn( Color_Blue, L"%-32s @ 0x%08X -> 0x%08X [%umb]", Name.c_str(), + m_baseptr, (uptr)m_baseptr+toRemoveBytes, toRemoveBytes / _1mb); + } + + return true; +} + +// Sets the abbreviated name used by the profiler. Name should be under 10 characters long. +// After a name has been set, a profiler source will be automatically registered and cleared +// in accordance with changes in the reserve area. +RecompiledCodeReserve& RecompiledCodeReserve::SetProfilerName( const wxString& shortname ) +{ + m_profiler_name = shortname; + _registerProfiler(); + return *this; +} void RecompiledCodeReserve::OnCommittedBlock( void* block ) { @@ -57,7 +149,7 @@ void RecompiledCodeReserve::OnCommittedBlock( void* block ) void RecompiledCodeReserve::ResetProcessReserves() const { - //Cpu->SetCacheReserve( (Cpu->GetCacheReserve() * 3) / 2 ); + Cpu->SetCacheReserve( (Cpu->GetCacheReserve() * 3) / 2 ); Cpu->Reset(); CpuVU0->SetCacheReserve( (CpuVU0->GetCacheReserve() * 3) / 2 ); @@ -66,7 +158,7 @@ void RecompiledCodeReserve::ResetProcessReserves() const CpuVU1->SetCacheReserve( (CpuVU1->GetCacheReserve() * 3) / 2 ); CpuVU1->Reset(); - //psxCpu->SetCacheReserve( (psxCpu->GetCacheReserve() * 3) / 2 ); + psxCpu->SetCacheReserve( (psxCpu->GetCacheReserve() * 3) / 2 ); psxCpu->Reset(); } @@ -93,8 +185,7 @@ void RecompiledCodeReserve::OnOutOfMemory( const Exception::OutOfMemory& ex, voi ResetProcessReserves(); uint cusion = std::min( m_block_size, 4 ); - HostSys::MmapCommit((u8*)blockptr, cusion * __pagesize); - HostSys::MemProtect((u8*)blockptr, cusion * __pagesize, m_prot_mode); + HostSys::MmapCommitPtr((u8*)blockptr, cusion * __pagesize, m_prot_mode); handled = true; } diff --git a/pcsx2/System/RecTypes.h b/pcsx2/System/RecTypes.h index 995444669d..b44c2f46e6 100644 --- a/pcsx2/System/RecTypes.h +++ b/pcsx2/System/RecTypes.h @@ -27,20 +27,37 @@ // class RecompiledCodeReserve : public BaseVirtualMemoryReserve { + typedef BaseVirtualMemoryReserve __parent; + protected: + wxString m_profiler_name; + bool m_profiler_registered; 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 OnCommittedBlock( void* block ); virtual void OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled ); + virtual RecompiledCodeReserve& SetProfilerName( const wxString& shortname ); + virtual RecompiledCodeReserve& SetProfilerName( const char* shortname ) + { + return SetProfilerName( fromUTF8(shortname) ); + } + + virtual bool TryResize( uint newsize ); + operator void*() { return m_baseptr; } operator const void*() const { return m_baseptr; } operator u8*() { return (u8*)m_baseptr; } operator const u8*() const { return (u8*)m_baseptr; } - + protected: void ResetProcessReserves() const; + + void _registerProfiler(); + void _termProfiler(); }; diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index 755907a65b..d0a4288d8e 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -286,40 +286,40 @@ void Pcsx2App::AllocateCoreStuffs() if( BaseException* ex = m_CpuProviders->GetException_EE() ) { - scrollableTextArea->AppendText( L"* R5900 (EE)\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" ); + scrollableTextArea->AppendText( L"* R5900 (EE)\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); recOps.EnableEE = false; } if( BaseException* ex = m_CpuProviders->GetException_IOP() ) { - scrollableTextArea->AppendText( L"* R3000A (IOP)\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" ); + scrollableTextArea->AppendText( L"* R3000A (IOP)\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); recOps.EnableIOP = false; } if( BaseException* ex = m_CpuProviders->GetException_MicroVU0() ) { - scrollableTextArea->AppendText( L"* microVU0\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" ); + scrollableTextArea->AppendText( L"* microVU0\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); recOps.UseMicroVU0 = false; recOps.EnableVU0 = recOps.EnableVU0 && m_CpuProviders->IsRecAvailable_SuperVU0(); } if( BaseException* ex = m_CpuProviders->GetException_MicroVU1() ) { - scrollableTextArea->AppendText( L"* microVU1\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" ); + scrollableTextArea->AppendText( L"* microVU1\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); recOps.UseMicroVU1 = false; recOps.EnableVU1 = recOps.EnableVU1 && m_CpuProviders->IsRecAvailable_SuperVU1(); } if( BaseException* ex = m_CpuProviders->GetException_SuperVU0() ) { - scrollableTextArea->AppendText( L"* SuperVU0\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" ); + scrollableTextArea->AppendText( L"* SuperVU0\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); recOps.UseMicroVU0 = m_CpuProviders->IsRecAvailable_MicroVU0(); recOps.EnableVU0 = recOps.EnableVU0 && recOps.UseMicroVU0; } if( BaseException* ex = m_CpuProviders->GetException_SuperVU1() ) { - scrollableTextArea->AppendText( L"* SuperVU1\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" ); + scrollableTextArea->AppendText( L"* SuperVU1\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); recOps.UseMicroVU1 = m_CpuProviders->IsRecAvailable_MicroVU1(); recOps.EnableVU1 = recOps.EnableVU1 && recOps.UseMicroVU1; } diff --git a/pcsx2/windows/SamplProf.cpp b/pcsx2/windows/SamplProf.cpp index 74e3dfaf4b..89ea7302b1 100644 --- a/pcsx2/windows/SamplProf.cpp +++ b/pcsx2/windows/SamplProf.cpp @@ -119,40 +119,47 @@ static bool _registeredName( const wxString& name ) return false; } -void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz) +void ProfilerRegisterSource(const wxString& Name, const void* buff, u32 sz) { if( ProfRunning ) EnterCriticalSection( &ProfModulesLock ); - wxString strName( fromUTF8(Name) ); - if( !_registeredName( strName ) ) - ProfModules.push_back( Module( strName, buff, sz ) ); + if( !_registeredName( Name ) ) + ProfModules.push_back( Module( Name, buff, sz ) ); if( ProfRunning ) LeaveCriticalSection( &ProfModulesLock ); } +void ProfilerRegisterSource(const wxString& Name, const void* function) +{ + if( ProfRunning ) + EnterCriticalSection( &ProfModulesLock ); + + if( !_registeredName( Name ) ) + ProfModules.push_back( Module(Name,function) ); + + if( ProfRunning ) + LeaveCriticalSection( &ProfModulesLock ); +} + +void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz) +{ + ProfilerRegisterSource( fromUTF8(Name), buff, sz ); +} + void ProfilerRegisterSource(const char* Name, const void* function) { - if( ProfRunning ) - EnterCriticalSection( &ProfModulesLock ); - - wxString strName( fromUTF8(Name) ); - if( !_registeredName( strName ) ) - ProfModules.push_back( Module(strName,function) ); - - if( ProfRunning ) - LeaveCriticalSection( &ProfModulesLock ); + ProfilerRegisterSource( fromUTF8(Name), function ); } -void ProfilerTerminateSource( const char* Name ) +void ProfilerTerminateSource( const wxString& Name ) { - wxString strName( fromUTF8(Name) ); for( vector::const_iterator iter = ProfModules.begin(), end = ProfModules.end(); itername.compare( strName ) == 0 ) + if( iter->name.compare( Name ) == 0 ) { ProfModules.erase( iter ); break; @@ -160,6 +167,11 @@ void ProfilerTerminateSource( const char* Name ) } } +void ProfilerTerminateSource( const char* Name ) +{ + ProfilerTerminateSource( fromUTF8(Name) ); +} + static bool DispatchKnownModules( uint Eip ) { bool retval = false; diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp index 83bd77cbea..757b49a4f7 100644 --- a/pcsx2/x86/iR3000A.cpp +++ b/pcsx2/x86/iR3000A.cpp @@ -33,7 +33,6 @@ #include "IopCommon.h" #include "iCore.h" -#include "SamplProf.h" #include "NakedAsm.h" #include "AppConfig.h" @@ -750,19 +749,41 @@ void psxRecompileCodeConst3(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, noconstcode(0); } +static uptr m_ConfiguredCacheReserve = 32; static u8* m_recBlockAlloc = NULL; static const uint m_recBlockAllocSize = (((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK)); +static void recReserveCache() +{ + extern wxString GetMsg_RecVmFailed(); + + if (!recMem) recMem = new RecompiledCodeReserve(L"R3000A Recompiler Cache", _1mb * 2); + recMem->SetProfilerName("IOPrec"); + + while (!recMem->IsOk()) + { + if (recMem->Reserve( m_ConfiguredCacheReserve * _1mb, HostMemoryMap::IOPrec ) != NULL) break; + + // If it failed, then try again (if possible): + if (m_ConfiguredCacheReserve < 4) break; + m_ConfiguredCacheReserve /= 2; + } + + if (!recMem->IsOk()) + { + throw Exception::VirtualMemoryMapConflict(recMem->GetName()) + .SetDiagMsg(pxsFmt( L"Recompiled code cache could not be mapped." )) + .SetUserMsg(GetMsg_RecVmFailed()); + } +} + static void recReserve() { - if (!recMem) - { - recMem = new RecompiledCodeReserve(L"R3000A Recompiler Cache", _1mb * 2); - recMem->Reserve( _16mb, HostMemoryMap::IOPrec ); - ProfilerRegisterSource( "IOP Rec", *recMem, recMem->GetReserveSizeInBytes() ); - } + // IOP has no hardware requirements! + + recReserveCache(); } static void recAlloc() @@ -846,7 +867,6 @@ void recResetIOP() static void recShutdown() { - ProfilerTerminateSource( "IOPRec" ); safe_delete( recMem ); safe_aligned_free( m_recBlockAlloc ); @@ -1399,13 +1419,12 @@ StartRecomp: static void recSetCacheReserve( uint reserveInMegs ) { - //m_ConfiguredCacheReserve = reserveInMegs * _1mb; + m_ConfiguredCacheReserve = reserveInMegs; } static uint recGetCacheReserve() { - return 0; - //return m_ConfiguredCacheReserve / _1mb; + return m_ConfiguredCacheReserve; } R3000Acpu psxRec = { diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index d07e3039b2..6a605c59d0 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -25,7 +25,6 @@ #include "System/RecTypes.h" #include "vtlb.h" -#include "SamplProf.h" #include "Dump.h" #include "System/SysThreads.h" @@ -64,7 +63,7 @@ bool g_cpuFlushedPC, g_cpuFlushedCode, g_recompilingDelaySlot, g_maySignalExcept static const int RECCONSTBUF_SIZE = 16384 * 2; // 64 bit consts in 32 bit units static RecompiledCodeReserve* recMem = NULL; -static uptr m_ConfiguredCacheReserve = _64mb; +static uptr m_ConfiguredCacheReserve = 64; static u32* recConstBuf = NULL; // 64-bit pseudo-immediates static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here @@ -551,38 +550,35 @@ static void recThrowHardwareDeficiency( const wxChar* extFail ) // This error message is shared by R5900, R3000, and microVU recompilers. It is not used by the // SuperVU recompiler, since it has its own customized message. -wxString GetMsg_RecVmFailed( const char* recName ) +wxString GetMsg_RecVmFailed() { return pxE( ".Error:Recompiler:VirtualMemoryAlloc", - pxsFmt( - "The %s recompiler was unable to reserve contiguous memory required " - "for internal caches. This problem may be fixable by reducing the default " - "cache sizes for all PCSX2 recompilers, found under Host Settings.", - recName - ) + L"This recompiler was unable to reserve contiguous memory required " + L"for internal caches. This problem may be fixable by reducing the default " + L"cache sizes for all PCSX2 recompilers, found under Host Settings." ); } static void recReserveCache() { if (!recMem) recMem = new RecompiledCodeReserve(L"R5900-32 Recompiler Cache", _1mb * 4); + recMem->SetProfilerName("EErec"); - recMem->Reserve( m_ConfiguredCacheReserve, HostMemoryMap::EErec ); - - while (!recMem->IsOk() && (m_ConfiguredCacheReserve >= 16)) + while (!recMem->IsOk()) { + if (recMem->Reserve( m_ConfiguredCacheReserve * _1mb, HostMemoryMap::EErec ) != NULL) break; + + // If it failed, then try again (if possible): + if (m_ConfiguredCacheReserve < 16) break; m_ConfiguredCacheReserve /= 2; - recMem->Reserve( m_ConfiguredCacheReserve * _1mb, HostMemoryMap::EErec ); } if (!recMem->IsOk()) { throw Exception::VirtualMemoryMapConflict(recMem->GetName()) - .SetDiagMsg(pxsFmt( L"R5900-32 recompiled code cache could not be mapped." )) - .SetUserMsg(GetMsg_RecVmFailed("R5900-32")); + .SetDiagMsg(pxsFmt( L"Recompiled code cache could not be mapped." )) + .SetUserMsg(GetMsg_RecVmFailed()); } - - ProfilerRegisterSource( "EE Rec", *recMem, recMem->GetReserveSizeInBytes() ); } static void recReserve() @@ -721,7 +717,6 @@ static void recResetRaw() static void recShutdown() { - ProfilerTerminateSource( "EERec" ); safe_delete( recMem ); recBlocks.Reset(); @@ -1922,12 +1917,12 @@ static void recThrowException( const BaseException& ex ) static void recSetCacheReserve( uint reserveInMegs ) { - m_ConfiguredCacheReserve = reserveInMegs * _1mb; + m_ConfiguredCacheReserve = reserveInMegs; } static uint recGetCacheReserve() { - return m_ConfiguredCacheReserve / _1mb; + return m_ConfiguredCacheReserve; } R5900cpu recCpu = diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp index 976f4f9306..479311a7d0 100644 --- a/pcsx2/x86/microVU.cpp +++ b/pcsx2/x86/microVU.cpp @@ -85,6 +85,19 @@ static __fi void mVUthrowHardwareDeficiency(const wxChar* extFail, int vuIndex) .SetUserMsg(wxsFormat(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )); } +void microVU::reserveCache() +{ + cache_reserve = new RecompiledCodeReserve( pxsFmt("Micro VU%u Recompiler Cache", index) ); + cache_reserve->SetProfilerName( pxsFmt("mVU%urec", index) ); + + cache = index ? + (u8*)cache_reserve->Reserve( cacheSize, 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 )); +} + // Only run this once per VU! ;) void microVU::init(uint vuIndex) { @@ -105,16 +118,6 @@ void microVU::init(uint vuIndex) { if (!dispCache) throw Exception::OutOfMemory( index ? L"Micro VU1 Dispatcher" : L"Micro VU0 Dispatcher" ); memset(dispCache, 0xcc, mVUdispCacheSize); - 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); } @@ -130,10 +133,6 @@ void microVU::reset() { //memset(&prog, 0, sizeof(prog)); memset(&prog.lpState, 0, sizeof(prog.lpState)); - if (IsDevBuild) { // Release builds shouldn't need this - memset(cache, 0xcc, cacheSize); - } - // Program Variables prog.cleared = 1; prog.isSame = -1; @@ -145,7 +144,7 @@ void microVU::reset() { u8* z = cache; prog.x86start = z; prog.x86ptr = z; - prog.x86end = z + (cacheSize - mVUcacheSafeZone); + prog.x86end = z + ((cacheSize - mVUcacheSafeZone) * _1mb); for (u32 i = 0; i < (progSize / 2); i++) { if (!prog.prog[i]) @@ -168,11 +167,7 @@ void microVU::reset() { // Free Allocated Resources void microVU::close() { - if (cache_reserve && cache_reserve->IsOk()) - { - ProfilerTerminateSource (index ? "mVU1 Rec" : "mVU0 Rec"); - safe_delete(cache_reserve); - } + safe_delete(cache_reserve); SafeSysMunmap(dispCache, mVUdispCacheSize); @@ -367,18 +362,18 @@ void recMicroVU1::Clear(u32 addr, u32 size) { uint recMicroVU0::GetCacheReserve() const { - return microVU0.cacheSize / _1mb; + return microVU0.cacheSize; } uint recMicroVU1::GetCacheReserve() const { - return microVU1.cacheSize / _1mb; + return microVU1.cacheSize; } void recMicroVU0::SetCacheReserve( uint reserveInMegs ) const { - microVU0.cacheSize = reserveInMegs * _1mb; + microVU0.cacheSize = reserveInMegs; } void recMicroVU1::SetCacheReserve( uint reserveInMegs ) const { - microVU1.cacheSize = reserveInMegs * _1mb; + microVU1.cacheSize = reserveInMegs; } diff --git a/pcsx2/x86/microVU.h b/pcsx2/x86/microVU.h index 57cd99a092..ce33e897d3 100644 --- a/pcsx2/x86/microVU.h +++ b/pcsx2/x86/microVU.h @@ -28,7 +28,6 @@ using namespace x86Emitter; #include "iR5900.h" #include "R5900OpcodeTables.h" #include "x86emitter/x86emitter.h" -#include "SamplProf.h" #include "microVU_Misc.h" #include "microVU_IR.h" @@ -150,11 +149,8 @@ struct microProgManager { microRegInfo lpState; // Pipeline state from where program left off (useful for continuing execution) }; -#define mVUdispCacheSize (__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 -#define mVUcacheSafeZone ((index) ? (_1mb * 3) : (_1mb * 3)) // Safe-Zone for last program +static const uint mVUdispCacheSize = __pagesize; // Dispatcher Cache Size (in bytes) +static const uint mVUcacheSafeZone = 3; // Safe-Zone for program recompilation (in megabytes) struct microVU { @@ -229,13 +225,14 @@ struct microVU { microVU() { - cacheSize = _1mb * 64; + cacheSize = 64; cache = NULL; dispCache = NULL; startFunct = NULL; exitFunct = NULL; } + void reserveCache(); void init(uint vuIndex); void reset(); void close(); diff --git a/pcsx2/x86/sVU_zerorec.cpp b/pcsx2/x86/sVU_zerorec.cpp index 5183167940..ff0b03f4ff 100644 --- a/pcsx2/x86/sVU_zerorec.cpp +++ b/pcsx2/x86/sVU_zerorec.cpp @@ -38,7 +38,6 @@ #include "System/RecTypes.h" #include "sVU_zerorec.h" -#include "SamplProf.h" #include "NakedAsm.h" #include "AppConfig.h" @@ -350,9 +349,10 @@ static void SuperVUAlloc(int vuindex) { if (s_recVUMem[vuindex]) return; - s_recVUMem[vuindex] = new RecompiledCodeReserve( L"SuperVU Recompiler Cache", 0 ); + s_recVUMem[vuindex] = new RecompiledCodeReserve( pxsFmt("SuperVU%u Recompiler Cache", vuindex), 0 ); s_recVUMem[vuindex]->Reserve( sVU_EXESIZE, vuindex ? HostMemoryMap::sVU1rec : HostMemoryMap::sVU0rec, _256mb ); - + s_recVUMem[vuindex]->SetProfilerName(pxsFmt("sVU%urec",vuindex)); + // upper 4 bits must be zero! if (!s_recVUMem[vuindex]->IsOk()) { @@ -364,8 +364,6 @@ 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[vuindex], sVU_EXESIZE); } } @@ -413,8 +411,6 @@ void SuperVUDestroy(int vuindex) } DestroyVUHeaders(vuindex); - ProfilerTerminateSource(vuindex ? "sVU1Rec" : "sVU0Rec"); - safe_delete(s_recVUMem[vuindex]); safe_delete_array(recVUStack[vuindex]); } From dc7f00d05e9867d2852a3f7a5f320513dee48934 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Wed, 3 Nov 2010 17:37:29 +0000 Subject: [PATCH 11/22] newHostVM: * Preliminary implementation for the SpatialArrayReserve class, which will be used for recompiler lookup tables (large portions of these tables are never used by many games). Will put it to use and test it soon. * Finished implementation of TryResize method for reservations, which will be used by PCSX2 if the operating system runs low on ram. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@3992 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/build/Utilities/utilities.vcproj | 4 + common/include/Utilities/PageFaultSource.h | 42 +++--- common/src/Utilities/VirtualMemory.cpp | 160 +++++++++++++++++---- pcsx2/System.cpp | 65 ++------- pcsx2/System/RecTypes.h | 12 +- pcsx2/x86/microVU.cpp | 10 +- 6 files changed, 190 insertions(+), 103 deletions(-) diff --git a/common/build/Utilities/utilities.vcproj b/common/build/Utilities/utilities.vcproj index f14e0f9ff9..c7f540d764 100644 --- a/common/build/Utilities/utilities.vcproj +++ b/common/build/Utilities/utilities.vcproj @@ -425,6 +425,10 @@ RelativePath="..\..\include\Utilities\MemsetFast.inl" > + + diff --git a/common/include/Utilities/PageFaultSource.h b/common/include/Utilities/PageFaultSource.h index 5073744c51..2d4bf70bb8 100644 --- a/common/include/Utilities/PageFaultSource.h +++ b/common/include/Utilities/PageFaultSource.h @@ -107,16 +107,11 @@ protected: uptr m_reserved; // Incremental size by which the buffer grows (in pages) - uptr m_block_size; + uptr m_blocksize; // Protection mode to be applied to committed blocks. PageProtectionMode m_prot_mode; - // Specifies the number of blocks that should be committed automatically when the - // reserve is created. Typically this chunk is larger than the block size, and - // should be based on whatever typical overhead is needed for basic block use. - uint m_def_commit; - // Records the number of pages committed to memory. // (metric for analysis of buffer usage) uptr m_commited; @@ -131,6 +126,9 @@ public: 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 CommitBlocks( uptr page, uint blocks ); bool IsOk() const { return m_baseptr != NULL; } wxString GetName() const { return Name; } @@ -153,6 +151,17 @@ public: protected: void OnPageFaultEvent( const PageFaultInfo& info, bool& handled ); + // This function is called from OnPageFaultEvent after the address has been translated + // and confirmed to apply to this reserved area in question. OnPageFaultEvent contains + // a try/catch exception handler, which ensures "reasonable" error response behavior if + // this function throws exceptions. + // + // Important: This method is called from the context of an exception/signal handler. On + // Windows this isn't a big deal (most operations are ok). On Linux, however, logging + // and other facilities are probably not a good idea. + virtual void DoCommitAndProtect( uptr offset )=0; + + // This function is called for every committed block. virtual void OnCommittedBlock( void* block )=0; virtual void OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled ) { @@ -190,27 +199,25 @@ class SpatialArrayReserve : public BaseVirtualMemoryReserve typedef BaseVirtualMemoryReserve __parent; protected: + uint m_numblocks; + + // Array of block bits, each bit indicating if the block has been committed to memory + // or not. The array length is typically determined via ((numblocks+7) / 8), though the + // actual array size may be larger in order to accommodate 32-bit or 128-bit accelerated + // operations. + ScopedAlignedAlloc m_blockbits; public: SpatialArrayReserve( const wxString& name, uint defCommit = 0 ); virtual void* Reserve( uint size, uptr base = 0, uptr upper_bounds = 0 ); + virtual void Reset(); 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 ); @@ -219,6 +226,9 @@ public: operator u8*() { return (u8*)m_baseptr; } operator const u8*() const { return (u8*)m_baseptr; } + +protected: + uint _calcBlockBitArrayLength() const; }; #ifdef __LINUX__ diff --git a/common/src/Utilities/VirtualMemory.cpp b/common/src/Utilities/VirtualMemory.cpp index 393d1d602e..52a1592479 100644 --- a/common/src/Utilities/VirtualMemory.cpp +++ b/common/src/Utilities/VirtualMemory.cpp @@ -58,7 +58,7 @@ BaseVirtualMemoryReserve::BaseVirtualMemoryReserve( const wxString& name ) m_commited = 0; m_reserved = 0; m_baseptr = NULL; - m_block_size = __pagesize; + m_blocksize = __pagesize; m_prot_mode = PageAccess_None(); } @@ -118,45 +118,84 @@ void BaseVirtualMemoryReserve::Free() HostSys::Munmap((uptr)m_baseptr, m_reserved*__pagesize); } -void BaseVirtualMemoryReserve::OnPageFaultEvent(const PageFaultInfo& info, bool& handled) +// If growing the array, or if shrinking the array to some point that's still *greater* than the +// committed memory range, then attempt a passive "on-the-fly" resize that maps/unmaps some portion +// of the reserve. +// +// If the above conditions are not met, or if the map/unmap fails, this method returns false. +// The caller will be responsible for manually resetting the reserve. +// +// Parameters: +// newsize - new size of the reserved buffer, in bytes. +bool BaseVirtualMemoryReserve::TryResize( uint newsize ) { - uptr offset = (info.addr - (uptr)m_baseptr) / __pagesize; - if (offset >= m_reserved) return; + uint newPages = (newsize + __pagesize - 1) / __pagesize; - try { + if (newPages > m_reserved) + { + uint toReservePages = newPages - m_reserved; + uint toReserveBytes = toReservePages * __pagesize; - if (!m_commited && m_def_commit) + DevCon.WriteLn( L"%-32s is being expanded by %u pages.", Name.c_str(), toReservePages); + + m_baseptr = (void*)HostSys::MmapReserve((uptr)GetPtrEnd(), toReserveBytes); + + if (!m_baseptr) { - const uint camt = m_def_commit * __pagesize; - // first block being committed! Commit the default requested - // amount if its different from the blocksize. - - HostSys::MmapCommitPtr(m_baseptr, camt, m_prot_mode); - - u8* init = (u8*)m_baseptr; - u8* endpos = init + camt; - for( ; init 0x%08X", m_baseptr, (uptr)m_baseptr+toReserveBytes); } - void* bleh = (u8*)m_baseptr + (offset * __pagesize); + 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) + { + if (m_commited > newsize) return false; - // 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::MmapCommitPtr(bleh, m_block_size*__pagesize, m_prot_mode); + uint toRemovePages = m_reserved - newPages; + uint toRemoveBytes = toRemovePages * __pagesize; - m_commited += m_block_size; - OnCommittedBlock(bleh); + DevCon.WriteLn( L"%-32s is being shrunk by %u pages.", Name.c_str(), toRemovePages); + HostSys::MmapResetPtr(GetPtrEnd(), toRemoveBytes); + + DevCon.WriteLn( Color_Blue, L"%-32s @ 0x%08X -> 0x%08X [%umb]", Name.c_str(), + m_baseptr, (uptr)m_baseptr+toRemoveBytes, toRemoveBytes / _1mb); + } + + return true; +} + +void BaseVirtualMemoryReserve::CommitBlocks( uptr page, uint blocks ) +{ + const uint blocksbytes = blocks * m_blocksize * __pagesize; + void* blockptr = (u8*)m_baseptr + (page * __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::MmapCommitPtr(blockptr, blocksbytes, m_prot_mode); + + u8* init = (u8*)blockptr; + u8* endpos = init + blocksbytes; + for( ; init= m_reserved)) return; + + try { + DoCommitAndProtect( offset ); handled = true; } catch (Exception::OutOfMemory& ex) { + handled = false; OnOutOfMemory( ex, (u8*)m_baseptr + (offset * __pagesize), handled ); } #ifndef __WXMSW__ @@ -170,8 +209,8 @@ void BaseVirtualMemoryReserve::OnPageFaultEvent(const PageFaultInfo& info, bool& // *unless* its attached to a debugger; then we can, at a bare minimum, trap it. catch (Exception::BaseException& ex) { - wxTrap(); handled = false; + wxTrap(); } #endif } @@ -181,14 +220,79 @@ void BaseVirtualMemoryReserve::OnPageFaultEvent(const PageFaultInfo& info, bool& // SpatialArrayReserve (implementations) // -------------------------------------------------------------------------------------- +uint SpatialArrayReserve::_calcBlockBitArrayLength() const +{ + return (m_numblocks + 127) / 128; +} + void* SpatialArrayReserve::Reserve( uint size, uptr base, uptr upper_bounds ) { return __parent::Reserve( size, base, upper_bounds ); } +// Resets/clears the spatial array, reducing the memory commit pool overhead to zero (0). +void SpatialArrayReserve::Reset() +{ + __parent::Reset(); + memzero_sse_a(m_blockbits.GetPtr(), _calcBlockBitArrayLength()); +} + +// This method allows the programmer to specify the block size of the array as a function +// of its reserved size. This function *must* be called *after* the reserve has been made, +// and *before* the array contents have been accessed. +// +// Calls to this function prior to initializing the reserve or after the reserve has been +// accessed (resulting in committed blocks) will be ignored -- and will generate an assertion +// in debug builds. +SpatialArrayReserve& SpatialArrayReserve::SetBlockCount( uint blocks ) +{ + pxAssumeDev( !m_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; + + return *this; +} + +// Sets the block size via pages (pages are defined by the __pagesize global, which is +// typically 4096). +// +// This method must be called prior to accessing or modifying the array contents. Calls to +// a modified buffer will be ignored (and generate an assertion in dev/debug modes). +SpatialArrayReserve& SpatialArrayReserve::SetBlockSizeInPages( uint pages ) +{ + if (pxAssertDev(m_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_blockbits.Alloc( _calcBlockBitArrayLength() ); + } + return *this; +} + +// 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. +// +// This method must be called prior to accessing or modifying the array contents. Calls to +// a modified buffer will be ignored (and generate an assertion in dev/debug modes). +uint SpatialArrayReserve::SetBlockSize( uint bytes ) +{ + SetBlockSizeInPages((bytes + __pagesize - 1) / __pagesize); + return m_blocksize * __pagesize; +} + void SpatialArrayReserve::OnCommittedBlock( void* block ) { + // Determine the block position in the blockbits array, flag it, and be done! + + uptr relative = (uptr)m_baseptr - (uptr)block; + pxAssume( (relative % (m_blocksize * __pagesize)) == 0); + relative /= m_blocksize * __pagesize; + m_blockbits[relative/32] |= 1 << (relative & 31); + m_commited += m_blocksize; } void SpatialArrayReserve::OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled ) diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index b27563f54c..0083ae6235 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -43,7 +43,7 @@ extern void resetNewVif(int idx); RecompiledCodeReserve::RecompiledCodeReserve( const wxString& name, uint defCommit ) : BaseVirtualMemoryReserve( name ) { - m_block_size = (1024 * 128) / __pagesize; + m_blocksize = (1024 * 128) / __pagesize; m_prot_mode = PageAccess_Any(); m_def_commit = defCommit / __pagesize; @@ -68,6 +68,11 @@ void RecompiledCodeReserve::_termProfiler() ProfilerTerminateSource( m_profiler_name ); } +uint RecompiledCodeReserve::_calcDefaultCommitInBlocks() const +{ + return (m_def_commit + m_blocksize - 1) / m_blocksize; +} + void* RecompiledCodeReserve::Reserve( uint size, uptr base, uptr upper_bounds ) { if (!__parent::Reserve(size, base, upper_bounds)) return NULL; @@ -76,55 +81,6 @@ void* RecompiledCodeReserve::Reserve( uint size, uptr base, uptr upper_bounds ) } -// If growing the array, or if shrinking the array to some point that's still *greater* than the -// committed memory range, then attempt a passive "on-the-fly" resize that maps/unmaps some portion -// of the reserve. -// -// If the above conditions are not met, or if the map/unmap fails, this method returns false. -// The caller will be responsible for manually resetting the reserve. -// -// Parameters: -// newsize - new size of the reserved buffer, in bytes. -bool RecompiledCodeReserve::TryResize( uint newsize ) -{ - uint newPages = (newsize + __pagesize - 1) / __pagesize; - - if (newPages > m_reserved) - { - uint toReservePages = newPages - m_reserved; - uint toReserveBytes = toReservePages * __pagesize; - - DevCon.WriteLn( L"%-32s is being expanded by %u pages.", Name.c_str(), toReservePages); - - m_baseptr = (void*)HostSys::MmapReserve((uptr)GetPtrEnd(), toReserveBytes); - - if (!m_baseptr) - { - Console.Warning("%-32s could not be passively resized due to virtual memory conflict!"); - Console.Indent().Warning("(attempted to map memory @ 0x%08X -> 0x%08X", m_baseptr, (uptr)m_baseptr+toReserveBytes); - } - - 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) - { - if (m_commited > newsize) return false; - - uint toRemovePages = m_reserved - newPages; - uint toRemoveBytes = toRemovePages * __pagesize; - - DevCon.WriteLn( L"%-32s is being shrunk by %u pages.", Name.c_str(), toRemovePages); - - HostSys::MmapResetPtr(GetPtrEnd(), toRemoveBytes); - - DevCon.WriteLn( Color_Blue, L"%-32s @ 0x%08X -> 0x%08X [%umb]", Name.c_str(), - m_baseptr, (uptr)m_baseptr+toRemoveBytes, toRemoveBytes / _1mb); - } - - return true; -} - // Sets the abbreviated name used by the profiler. Name should be under 10 characters long. // After a name has been set, a profiler source will be automatically registered and cleared // in accordance with changes in the reserve area. @@ -135,6 +91,11 @@ RecompiledCodeReserve& RecompiledCodeReserve::SetProfilerName( const wxString& s return *this; } +void RecompiledCodeReserve::DoCommitAndProtect( uptr page ) +{ + CommitBlocks(page, (m_commited || !m_def_commit) ? 1 : _calcDefaultCommitInBlocks() ); +} + void RecompiledCodeReserve::OnCommittedBlock( void* block ) { if (IsDevBuild) @@ -143,7 +104,7 @@ void RecompiledCodeReserve::OnCommittedBlock( void* block ) // the assembly dump more cleanly. We don't clear the block on Release builds since // it can add a noticeable amount of overhead to large block recompilations. - memset_sse_a<0xcc>( block, m_block_size * __pagesize ); + memset_sse_a<0xcc>( block, m_blocksize * __pagesize ); } } @@ -184,7 +145,7 @@ void RecompiledCodeReserve::OnOutOfMemory( const Exception::OutOfMemory& ex, voi ResetProcessReserves(); - uint cusion = std::min( m_block_size, 4 ); + uint cusion = std::min( m_blocksize, 4 ); HostSys::MmapCommitPtr((u8*)blockptr, cusion * __pagesize, m_prot_mode); handled = true; diff --git a/pcsx2/System/RecTypes.h b/pcsx2/System/RecTypes.h index b44c2f46e6..c4367437f7 100644 --- a/pcsx2/System/RecTypes.h +++ b/pcsx2/System/RecTypes.h @@ -30,6 +30,11 @@ class RecompiledCodeReserve : public BaseVirtualMemoryReserve typedef BaseVirtualMemoryReserve __parent; protected: + // Specifies the number of blocks that should be committed automatically when the + // reserve is created. Typically this chunk is larger than the block size, and + // should be based on whatever typical overhead is needed for basic block use. + uint m_def_commit; + wxString m_profiler_name; bool m_profiler_registered; @@ -47,8 +52,6 @@ public: return SetProfilerName( fromUTF8(shortname) ); } - virtual bool TryResize( uint newsize ); - operator void*() { return m_baseptr; } operator const void*() const { return m_baseptr; } @@ -57,7 +60,10 @@ public: protected: void ResetProcessReserves() const; - + void DoCommitAndProtect( uptr page ); + void _registerProfiler(); void _termProfiler(); + + uint _calcDefaultCommitInBlocks() const; }; diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp index 479311a7d0..b01d1cb904 100644 --- a/pcsx2/x86/microVU.cpp +++ b/pcsx2/x86/microVU.cpp @@ -81,8 +81,8 @@ const __aligned(32) mVU_Globals mVUglob = { static __fi void mVUthrowHardwareDeficiency(const wxChar* extFail, int vuIndex) { throw Exception::HardwareDeficiency() - .SetDiagMsg(wxsFormat(L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail)) - .SetUserMsg(wxsFormat(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )); + .SetDiagMsg(pxsFmt(L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail)) + .SetUserMsg(pxsFmt(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )); } void microVU::reserveCache() @@ -91,8 +91,8 @@ void microVU::reserveCache() cache_reserve->SetProfilerName( pxsFmt("mVU%urec", index) ); cache = index ? - (u8*)cache_reserve->Reserve( cacheSize, HostMemoryMap::mVU1rec ) : - (u8*)cache_reserve->Reserve( cacheSize, HostMemoryMap::mVU0rec ); + (u8*)cache_reserve->Reserve( cacheSize * _1mb, HostMemoryMap::mVU1rec ) : + (u8*)cache_reserve->Reserve( cacheSize * _1mb, HostMemoryMap::mVU0rec ); if(!cache_reserve->IsOk()) throw Exception::VirtualMemoryMapConflict().SetDiagMsg(pxsFmt( L"Micro VU%u Recompiler Cache", index )); @@ -114,6 +114,8 @@ void microVU::init(uint vuIndex) { progSize = (index ? 0x4000 : 0x1000) / 4; progMemMask = progSize-1; + reserveCache(); + dispCache = SysMmapEx(0, mVUdispCacheSize, 0, (index ? "Micro VU1 Dispatcher" : "Micro VU0 Dispatcher")); if (!dispCache) throw Exception::OutOfMemory( index ? L"Micro VU1 Dispatcher" : L"Micro VU0 Dispatcher" ); memset(dispCache, 0xcc, mVUdispCacheSize); From a7726871dcc91a351e6281ab9bfaae66eb87357c Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Fri, 5 Nov 2010 01:33:01 +0000 Subject: [PATCH 12/22] newHostVM: More exception / error handling mess. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@3994 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/include/Utilities/Exceptions.h | 50 +++--- common/include/Utilities/General.h | 4 +- common/include/Utilities/PageFaultSource.h | 6 +- common/include/Utilities/ScopedAlloc.h | 20 +++ common/src/Utilities/Exceptions.cpp | 173 +++++++++++++++++--- common/src/Utilities/Linux/LnxHostSys.cpp | 86 ++++++---- common/src/Utilities/VirtualMemory.cpp | 88 +++++++--- common/src/Utilities/Windows/WinHostSys.cpp | 24 ++- pcsx2/Elfheader.cpp | 10 +- pcsx2/PluginManager.cpp | 32 +++- pcsx2/Plugins.h | 7 +- pcsx2/System.cpp | 70 +++----- pcsx2/System.h | 1 + pcsx2/System/RecTypes.h | 5 +- pcsx2/gui/AppInit.cpp | 4 +- pcsx2/gui/Panels/PluginSelectorPanel.cpp | 10 +- pcsx2/gui/SysState.cpp | 15 -- pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 4 - pcsx2/windows/WinCompressNTFS.cpp | 4 +- 19 files changed, 411 insertions(+), 202 deletions(-) diff --git a/common/include/Utilities/Exceptions.h b/common/include/Utilities/Exceptions.h index be7951c720..dd0a1610f9 100644 --- a/common/include/Utilities/Exceptions.h +++ b/common/include/Utilities/Exceptions.h @@ -259,43 +259,40 @@ public: \ virtual classname& SetStreamName( const wxString& name ) { StreamName = name; return *this; } \ virtual classname& SetStreamName( const char* name ) { StreamName = fromUTF8(name); return *this; } - #define DEFINE_STREAM_EXCEPTION( classname, parent, message ) \ - DEFINE_RUNTIME_EXCEPTION( classname, parent, message ) \ + #define DEFINE_STREAM_EXCEPTION( classname, parent ) \ + DEFINE_RUNTIME_EXCEPTION( classname, parent, wxEmptyString ) \ classname( const wxString& filename ) { \ StreamName = filename; \ - SetBothMsgs(message); \ } \ DEFINE_STREAM_EXCEPTION_ACCESSORS( classname ) - // Generic stream error. Contains the name of the stream and a message. - // This exception is usually thrown via derived classes, except in the (rare) case of a - // generic / unknown error. + // A generic base error class for bad streams -- corrupted data, sudden closures, loss of + // connection, or anything else that would indicate a failure to open a stream or read the + // data after the stream was successfully opened. // - class Stream : public RuntimeError + class BadStream : public RuntimeError { - DEFINE_STREAM_EXCEPTION( Stream, RuntimeError, wxLt("General file operation error.") ) + DEFINE_STREAM_EXCEPTION( BadStream, RuntimeError ) public: wxString StreamName; // name of the stream (if applicable) virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDisplayMessage() const; - }; - // A generic base error class for bad streams -- corrupted data, sudden closures, loss of - // connection, or anything else that would indicate a failure to read the data after the - // stream was successfully opened. - // - class BadStream : public Stream - { - DEFINE_STREAM_EXCEPTION( BadStream, Stream, wxLt("File data is corrupted or incomplete, or the stream connection closed unexpectedly.") ) + protected: + void _formatDiagMsg( FastFormatUnicode& dest ) const; + void _formatUserMsg( FastFormatUnicode& dest ) const; }; // A generic exception for odd-ball stream creation errors. // - class CannotCreateStream : public Stream + class CannotCreateStream : public BadStream { - DEFINE_STREAM_EXCEPTION( CannotCreateStream, Stream, wxLt("File could not be created or opened.") ) + DEFINE_STREAM_EXCEPTION( CannotCreateStream, BadStream ) + + virtual wxString FormatDiagnosticMessage() const; + virtual wxString FormatDisplayMessage() const; }; // Exception thrown when an attempt to open a non-existent file is made. @@ -304,22 +301,31 @@ public: \ class FileNotFound : public CannotCreateStream { public: - DEFINE_STREAM_EXCEPTION( FileNotFound, CannotCreateStream, wxLt("File not found.") ) + DEFINE_STREAM_EXCEPTION( FileNotFound, CannotCreateStream ) + + virtual wxString FormatDiagnosticMessage() const; + virtual wxString FormatDisplayMessage() const; }; class AccessDenied : public CannotCreateStream { public: - DEFINE_STREAM_EXCEPTION( AccessDenied, CannotCreateStream, wxLt("Permission denied to file.") ) + DEFINE_STREAM_EXCEPTION( AccessDenied, CannotCreateStream ) + + virtual wxString FormatDiagnosticMessage() const; + virtual wxString FormatDisplayMessage() const; }; // EndOfStream can be used either as an error, or used just as a shortcut for manual // feof checks. // - class EndOfStream : public Stream + class EndOfStream : public BadStream { public: - DEFINE_STREAM_EXCEPTION( EndOfStream, Stream, wxLt("Unexpected end of file or stream.") ); + DEFINE_STREAM_EXCEPTION( EndOfStream, BadStream ) + + virtual wxString FormatDiagnosticMessage() const; + virtual wxString FormatDisplayMessage() const; }; #ifdef __WXMSW__ diff --git a/common/include/Utilities/General.h b/common/include/Utilities/General.h index 4946f33c6c..d405f9472d 100644 --- a/common/include/Utilities/General.h +++ b/common/include/Utilities/General.h @@ -219,11 +219,11 @@ static __fi PageProtectionMode PageAccess_Any() namespace HostSys { void* MmapReserve(uptr base, size_t size); - void MmapCommit(uptr base, size_t size, const PageProtectionMode& mode); + bool MmapCommit(uptr base, size_t size, const PageProtectionMode& mode); void MmapReset(uptr base, size_t size); void* MmapReservePtr(void* base, size_t size); - void MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode); + bool MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode); void MmapResetPtr(void* base, size_t size); // Maps a block of memory for use as a recompiled code buffer. diff --git a/common/include/Utilities/PageFaultSource.h b/common/include/Utilities/PageFaultSource.h index 2d4bf70bb8..cf4bb313a6 100644 --- a/common/include/Utilities/PageFaultSource.h +++ b/common/include/Utilities/PageFaultSource.h @@ -163,10 +163,6 @@ protected: // This function is called for every committed block. virtual void OnCommittedBlock( void* block )=0; - virtual void OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled ) - { - throw; - } }; // -------------------------------------------------------------------------------------- @@ -212,9 +208,9 @@ public: virtual void* Reserve( uint size, uptr base = 0, uptr upper_bounds = 0 ); virtual void Reset(); + virtual bool TryResize( uint newsize ); void OnCommittedBlock( void* block ); - void OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled ); SpatialArrayReserve& SetBlockCount( uint blocks ); SpatialArrayReserve& SetBlockSizeInPages( uint bytes ); diff --git a/common/include/Utilities/ScopedAlloc.h b/common/include/Utilities/ScopedAlloc.h index 8aa2084e96..285e6c39b4 100644 --- a/common/include/Utilities/ScopedAlloc.h +++ b/common/include/Utilities/ScopedAlloc.h @@ -60,6 +60,26 @@ extern void pcsx2_aligned_free(void* pmem); # define _aligned_realloc pcsx2_aligned_realloc #endif +// -------------------------------------------------------------------------------------- +// pxDoOutOfMemory +// -------------------------------------------------------------------------------------- + +typedef void FnType_OutOfMemory( uptr blocksize ); +typedef FnType_OutOfMemory* Fnptr_OutOfMemory; + +// This method is meant to be assigned by applications that link against pxWex. It is called +// (invoked) prior to most pxWex built-in memory/array classes throwing exceptions, and can be +// used by an application to remove unneeded memory allocations and/or reduce internal cache +// reserves. +// +// Example: PCSX2 uses several bloated recompiler code caches. Larger caches improve performance, +// however a rouge cache growth could cause memory constraints in the operating system. If an out- +// of-memory error occurs, PCSX2's implementation of this function attempts to reset all internal +// recompiler caches. This can typically free up 100-150 megs of memory, and will allow the app +// to continue running without crashing or hanging the operating system, etc. +// +extern Fnptr_OutOfMemory pxDoOutOfMemory; + // -------------------------------------------------------------------------------------- // BaseScopedAlloc diff --git a/common/src/Utilities/Exceptions.cpp b/common/src/Utilities/Exceptions.cpp index e4d0d45f4d..64037aa4d1 100644 --- a/common/src/Utilities/Exceptions.cpp +++ b/common/src/Utilities/Exceptions.cpp @@ -23,6 +23,9 @@ #include #endif +// for lack of a better place... +Fnptr_OutOfMemory pxDoOutOfMemory = NULL; + static wxString GetTranslation( const wxChar* msg ) { return msg ? wxGetTranslation( msg ) : wxEmptyString; @@ -195,22 +198,30 @@ Exception::RuntimeError::RuntimeError( const std::exception& ex, const wxString& Exception::OutOfMemory::OutOfMemory( const wxString& allocdesc ) { AllocDescription = allocdesc; - m_message_user = _("Memory allocation failure! Your system has insufficient memory or resources to meet PCSX2's lofty needs."); } wxString Exception::OutOfMemory::FormatDiagnosticMessage() const { - FastFormatUnicode details; - if (!m_message_diag.IsEmpty()) - details.Write(":\n%s",m_message_diag.c_str()); + FastFormatUnicode retmsg; + retmsg.Write(L"Out of memory"); + if (!AllocDescription.IsEmpty()) + retmsg.Write(L" while allocating '%s'", AllocDescription.c_str()); - return pxsFmt(L"Out of memory while allocating '%s'%s", AllocDescription.c_str(), details.c_str()); + if (!m_message_diag.IsEmpty()) + retmsg.Write(L":\n%s", m_message_diag.c_str()); + + return retmsg; } wxString Exception::OutOfMemory::FormatDisplayMessage() const { - if (m_message_user.IsEmpty()) return FormatDisplayMessage(); - return m_message_user; + FastFormatUnicode retmsg; + retmsg.Write( L"%s", _("Oh noes! Out of memory!") ); + + if (!m_message_diag.IsEmpty()) + retmsg.Write(L"\n\n%s", m_message_diag.c_str()); + + return retmsg; } @@ -225,17 +236,31 @@ Exception::VirtualMemoryMapConflict::VirtualMemoryMapConflict( const wxString& a wxString Exception::VirtualMemoryMapConflict::FormatDiagnosticMessage() const { - FastFormatUnicode details; - if (!m_message_diag.IsEmpty()) - details.Write(":\n%s",m_message_diag.c_str()); + FastFormatUnicode retmsg; + retmsg.Write(L"Virtual memory map failed"); + if (!AllocDescription.IsEmpty()) + retmsg.Write(L" while reserving '%s'", AllocDescription.c_str()); - return pxsFmt(L"Out of virtual memory while reserving '%s'%s", AllocDescription.c_str(), details.c_str()); + if (!m_message_diag.IsEmpty()) + retmsg.Write(L":\n%s", m_message_diag.c_str()); + + return retmsg; } wxString Exception::VirtualMemoryMapConflict::FormatDisplayMessage() const { - if (m_message_user.IsEmpty()) return FormatDisplayMessage(); - return m_message_user; + FastFormatUnicode retmsg; + retmsg.Write( L"%s", + pxE( ".Error:VirtualMemoryMap", + L"There is not enough virtual memory available, or necessary virtual memory " + L"mappings have already been reserved by other processes, services, or DLLs." + ) + ); + + if (!m_message_diag.IsEmpty()) + retmsg.Write(L"\n\n%s", m_message_diag.c_str()); + + return retmsg; } @@ -250,20 +275,120 @@ wxString Exception::CancelEvent::FormatDisplayMessage() const return L"Action canceled: " + m_message_diag; } -wxString Exception::Stream::FormatDiagnosticMessage() const +// -------------------------------------------------------------------------------------- +// Exception::BadStream (implementations) +// -------------------------------------------------------------------------------------- +wxString Exception::BadStream::FormatDiagnosticMessage() const { - return pxsFmt( - L"%s\n\tFile/Object: %s", - m_message_diag.c_str(), StreamName.c_str() - ); + FastFormatUnicode retval; + _formatDiagMsg(retval); + return retval; } -wxString Exception::Stream::FormatDisplayMessage() const +wxString Exception::BadStream::FormatDisplayMessage() const { - wxString retval( m_message_user ); - if (!StreamName.IsEmpty()) - retval += L"\n\n" + pxsFmt( _("Path: %s"), StreamName.c_str() ); + FastFormatUnicode retval; + _formatUserMsg(retval); + return retval; +} +void Exception::BadStream::_formatDiagMsg( FastFormatUnicode& dest ) const +{ + dest.Write( L"Path: " ); + if (!StreamName.IsEmpty()) + dest.Write( L"%s", StreamName.c_str() ); + else + dest.Write( L"[Unnamed or unknown]" ); + + if (!m_message_diag.IsEmpty()) + dest.Write(L"\n%s", m_message_diag.c_str()); +} + +void Exception::BadStream::_formatUserMsg( FastFormatUnicode& dest ) const +{ + dest.Write( _("Path: ") ); + if (!StreamName.IsEmpty()) + dest.Write( L"%s", StreamName.c_str() ); + else + dest.Write( _("[Unnamed or unknown]") ); + + if (!m_message_user.IsEmpty()) + dest.Write(L"\n%s", m_message_user.c_str()); +} + +// -------------------------------------------------------------------------------------- +// Exception::CannotCreateStream (implementations) +// -------------------------------------------------------------------------------------- +wxString Exception::CannotCreateStream::FormatDiagnosticMessage() const +{ + FastFormatUnicode retval; + retval.Write("File could not be created."); + _formatDiagMsg(retval); + return retval; +} + +wxString Exception::CannotCreateStream::FormatDisplayMessage() const +{ + FastFormatUnicode retval; + retval.Write(_("A file could not be created.")); + _formatUserMsg(retval); + return retval; +} + +// -------------------------------------------------------------------------------------- +// Exception::FileNotFound (implementations) +// -------------------------------------------------------------------------------------- +wxString Exception::FileNotFound::FormatDiagnosticMessage() const +{ + FastFormatUnicode retval; + retval.Write("File not found."); + _formatDiagMsg(retval); + return retval; +} + +wxString Exception::FileNotFound::FormatDisplayMessage() const +{ + FastFormatUnicode retval; + retval.Write(_("File not found.")); + _formatUserMsg(retval); + return retval; +} + +// -------------------------------------------------------------------------------------- +// Exception::AccessDenied (implementations) +// -------------------------------------------------------------------------------------- +wxString Exception::AccessDenied::FormatDiagnosticMessage() const +{ + FastFormatUnicode retval; + retval.Write("Permission denied to file."); + _formatDiagMsg(retval); + return retval; +} + +wxString Exception::AccessDenied::FormatDisplayMessage() const +{ + FastFormatUnicode retval; + retval.Write(_("Permission denied while trying to open file, likely due to insufficient user account rights.")); + _formatUserMsg(retval); + return retval; +} + +// -------------------------------------------------------------------------------------- +// Exception::EndOfStream (implementations) +// -------------------------------------------------------------------------------------- +wxString Exception::EndOfStream::FormatDiagnosticMessage() const +{ + FastFormatUnicode retval; + retval.Write("Unexpected end of file or stream."); + _formatDiagMsg(retval); + return retval; +} + +wxString Exception::EndOfStream::FormatDisplayMessage() const +{ + FastFormatUnicode retval; + retval.Write(_("Unexpected end of file or stream encountered. File is probably truncated or corrupted.")); + _formatUserMsg(retval); return retval; } @@ -281,7 +406,7 @@ BaseException* Exception::FromErrno( const wxString& streamname, int errcode ) { case EINVAL: pxFailDev( L"Invalid argument" ); - return &(new Exception::Stream( streamname ))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)" ); + return &(new Exception::BadStream( streamname ))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)" ); case EACCES: // Access denied! return new Exception::AccessDenied( streamname ); @@ -302,6 +427,6 @@ BaseException* Exception::FromErrno( const wxString& streamname, int errcode ) return &(new Exception::BadStream( streamname ))->SetDiagMsg(L"Bad file number"); default: - return &(new Exception::Stream( streamname ))->SetDiagMsg(pxsFmt( L"General file/stream error [errno: %d]", errcode )); + return &(new Exception::BadStream( streamname ))->SetDiagMsg(pxsFmt( L"General file/stream error [errno: %d]", errcode )); } } diff --git a/common/src/Utilities/Linux/LnxHostSys.cpp b/common/src/Utilities/Linux/LnxHostSys.cpp index 4b9689b5d4..5c224431f4 100644 --- a/common/src/Utilities/Linux/LnxHostSys.cpp +++ b/common/src/Utilities/Linux/LnxHostSys.cpp @@ -35,6 +35,44 @@ static __ri void PageSizeAssertionTest( size_t size ) ); } +// returns FALSE if the mprotect call fails with an ENOMEM. +// Raises assertions on other types of POSIX errors (since those typically reflect invalid object +// or memory states). +static bool _memprotect( void* baseaddr, size_t size, const PageProtectionMode& mode ) +{ + PageSizeAssertionTest(size); + + uint lnxmode = 0; + + if (mode.CanWrite()) lnxmode |= PROT_WRITE; + if (mode.CanRead()) lnxmode |= PROT_READ; + if (mode.CanExecute()) lnxmode |= PROT_EXEC | PROT_READ; + + const int result = mprotect( baseaddr, size, lnxmode ); + + if (result == 0) return true; + + switch(errno) + { + case EINVAL: + pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)", + baseaddr, (uptr)baseaddr+size, mode.ToString().c_str()) + ); + break; + + case EACCES: + pxFailDev(pxsFmt(L"mprotect returned EACCES @ 0x%08X -> 0x%08X (mode=%s)", + baseaddr, (uptr)baseaddr+size, mode.ToString().c_str()) + ); + break; + + case ENOMEM: + // caller handles assertion or exception, or whatever. + break; + } + return false; +} + void* HostSys::MmapReservePtr(void* base, size_t size) { PageSizeAssertionTest(size); @@ -46,7 +84,7 @@ void* HostSys::MmapReservePtr(void* base, size_t size) return mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } -void HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode) +bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode) { // In linux, reserved memory is automatically committed when its permissions are // changed to something other than PROT_NONE. If the user is committing memory @@ -54,7 +92,12 @@ void HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& m // later when the user changes permissions to something useful via calls to MemProtect). if (mode.IsNone()) return; - MemProtect( base, size, mode ); + + if (_memprotect( base, size, mode )) return true; + + if (!pxDoOutOfMemory) return false; + pxDoOutOfMemory(size); + return _memprotect( base, size, mode ); } void HostSys::MmapResetPtr(void* base, size_t size) @@ -82,9 +125,9 @@ void* HostSys::MmapReserve(uptr base, size_t size) return MmapReservePtr((void*)base, size); } -void HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode) +bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode) { - MmapCommitPtr( (void*)base, size, mode ); + return MmapCommitPtr( (void*)base, size, mode ); } void HostSys::MmapReset(uptr base, size_t size) @@ -108,35 +151,12 @@ void HostSys::Munmap(uptr base, size_t size) void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode ) { - PageSizeAssertionTest(size); - - uint lnxmode = 0; - - if (mode.CanWrite()) lnxmode |= PROT_WRITE; - if (mode.CanRead()) lnxmode |= PROT_READ; - if (mode.CanExecute()) lnxmode |= PROT_EXEC | PROT_READ; - - int result = mprotect( baseaddr, size, lnxmode ); - - if (result != 0) + if (!_memprotect(baseaddr, size, mode)) { - switch(errno) - { - case EINVAL: - pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)", - baseaddr, (uptr)baseaddr+size, mode.ToString().c_str()) - ); - break; - - case ENOMEM: - throw Exception::OutOfMemory( pxsFmt( L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)", - baseaddr, (uptr)baseaddr+size, mode.ToString().c_str()) - ); - break; - - case EACCES: - break; - } - throw Exception::OutOfMemory(); + throw Exception::OutOfMemory( "MemProtect" ) + .SetDiagMsg(pxsFmt( L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)", + baseaddr, (uptr)baseaddr+size, mode.ToString().c_str() + ) + ); } } diff --git a/common/src/Utilities/VirtualMemory.cpp b/common/src/Utilities/VirtualMemory.cpp index 52a1592479..2c7086c57d 100644 --- a/common/src/Utilities/VirtualMemory.cpp +++ b/common/src/Utilities/VirtualMemory.cpp @@ -167,14 +167,19 @@ bool BaseVirtualMemoryReserve::TryResize( uint newsize ) return true; } + void BaseVirtualMemoryReserve::CommitBlocks( uptr page, uint blocks ) { - const uint blocksbytes = blocks * m_blocksize * __pagesize; + const uptr blocksbytes = blocks * m_blocksize * __pagesize; void* blockptr = (u8*)m_baseptr + (page * __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::MmapCommitPtr(blockptr, blocksbytes, m_prot_mode); + // Depending on the operating system, this call could fail if the system is low on either + // physical ram or virtual memory. + if (!HostSys::MmapCommitPtr(blockptr, blocksbytes, m_prot_mode)) + { + throw Exception::OutOfMemory(Name) + .SetDiagMsg(pxsFmt("An additional %u blocks @ 0x%08x were requested, but could not be committed!", blocks, blockptr)); + } u8* init = (u8*)blockptr; u8* endpos = init + blocksbytes; @@ -189,28 +194,37 @@ void BaseVirtualMemoryReserve::OnPageFaultEvent(const PageFaultInfo& info, bool& sptr offset = (info.addr - (uptr)m_baseptr) / __pagesize; if ((offset < 0) || ((uptr)offset >= m_reserved)) return; - try { - DoCommitAndProtect( offset ); - handled = true; - } - catch (Exception::OutOfMemory& ex) - { - handled = false; - OnOutOfMemory( ex, (u8*)m_baseptr + (offset * __pagesize), handled ); - } - #ifndef __WXMSW__ + // Linux Note! the SIGNAL handler is very limited in what it can do, and not only can't + // we let the C++ exception try to unwind the stack, we may not be able to log it either. + // (but we might as well try -- kernel/posix rules says not to do it, but Linux kernel + // implementations seem to support it). + // Note also that logging the exception and/or issuing an assertion dialog are always + // possible if the thread handling the signal is not the main thread. + // In windows we can let exceptions bubble out of the page fault handler. SEH will more // or less handle them in a semi-expected way, and might even avoid a GPF long enough // for the system to log the error or something. - - // 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. + + #ifndef __WXMSW__ + try { + #endif + throw Exception::OutOfMemory( L"Right Here" ); + DoCommitAndProtect( offset ); + handled = true; + + #ifndef __WXMSW__ + } catch (Exception::BaseException& ex) { handled = false; - wxTrap(); + if (!wxThread::IsMain()) + { + pxFailRel( ex.FormatDiagnosticMessage() ); + } + else + { + wxTrap(); + } } #endif } @@ -237,6 +251,33 @@ void SpatialArrayReserve::Reset() memzero_sse_a(m_blockbits.GetPtr(), _calcBlockBitArrayLength()); } +// Important! The number of blocks of the array will be altered when using this method. +// +bool SpatialArrayReserve::TryResize( uint newsize ) +{ + uint newpages = (newsize + __pagesize - 1) / __pagesize; + + // find the last allocated block -- we cannot be allowed to resize any smaller than that: + + uint i; + for (i=m_numblocks-1; i; --i) + { + uint bit = i & 7; + if (m_blockbits[i / 8] & bit) break; + } + + uint pages_in_use = i * m_blocksize; + if (newpages < pages_in_use) return false; + + if (!__parent::TryResize( newsize )) return false; + + // On success, we must re-calibrate the internal blockbits array. + + m_blockbits.Resize( (m_numblocks + 7) / 8 ); + + return true; +} + // This method allows the programmer to specify the block size of the array as a function // of its reserved size. This function *must* be called *after* the reserve has been made, // and *before* the array contents have been accessed. @@ -272,7 +313,7 @@ SpatialArrayReserve& SpatialArrayReserve::SetBlockSizeInPages( uint pages ) return *this; } -// This method assigns the block size of the spatial array, in bytes. The actual size of +// SetBlockSize assigns the block size of the spatial array, in bytes. The actual size of // each block will be rounded up to the nearest page size. The resulting size is returned. // // This method must be called prior to accessing or modifying the array contents. Calls to @@ -295,11 +336,6 @@ void SpatialArrayReserve::OnCommittedBlock( void* block ) m_commited += m_blocksize; } -void SpatialArrayReserve::OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled ) -{ - -} - // -------------------------------------------------------------------------------------- // PageProtectionMode (implementations) diff --git a/common/src/Utilities/Windows/WinHostSys.cpp b/common/src/Utilities/Windows/WinHostSys.cpp index 6c137bee7f..fc0f9b5842 100644 --- a/common/src/Utilities/Windows/WinHostSys.cpp +++ b/common/src/Utilities/Windows/WinHostSys.cpp @@ -42,10 +42,26 @@ void* HostSys::MmapReservePtr(void* base, size_t size) return VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS); } -void HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode) +bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode) { void* result = VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)); - pxAssumeDev(result, L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows()); + if (result) return true; + + const DWORD errcode = GetLastError(); + if (errcode == ERROR_COMMITMENT_MINIMUM) + { + Console.Warning("(MmapCommit) Received windows error %u {Virtual Memory Minimum Too Low}.", ERROR_COMMITMENT_MINIMUM); + Sleep(1000); // Cut windows some time to rework its memory... + } + else if (errcode != ERROR_NOT_ENOUGH_MEMORY && errcode != ERROR_OUTOFMEMORY) + { + pxFailDev(L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows()); + return false; + } + + if (!pxDoOutOfMemory) return false; + pxDoOutOfMemory(size); + return VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)) != NULL; } void HostSys::MmapResetPtr(void* base, size_t size) @@ -59,9 +75,9 @@ void* HostSys::MmapReserve(uptr base, size_t size) return MmapReservePtr((void*)base, size); } -void HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode) +bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode) { - MmapCommitPtr( (void*)base, size, mode ); + return MmapCommitPtr( (void*)base, size, mode ); } void HostSys::MmapReset(uptr base, size_t size) diff --git a/pcsx2/Elfheader.cpp b/pcsx2/Elfheader.cpp index 756962c4f5..5a820bf830 100644 --- a/pcsx2/Elfheader.cpp +++ b/pcsx2/Elfheader.cpp @@ -472,16 +472,16 @@ int GetPS2ElfName( wxString& name ) return 0; } } - catch (Exception::BadStream& ex) - { - Console.Error(ex.FormatDiagnosticMessage()); - return 0; // ISO error - } catch( Exception::FileNotFound& ) { //Console.Warning(ex.FormatDiagnosticMessage()); return 0; // no SYSTEM.CNF, not a PS1/PS2 disc. } + catch (Exception::BadStream& ex) + { + Console.Error(ex.FormatDiagnosticMessage()); + return 0; // ISO error + } #ifdef PCSX2_DEVBUILD FILE *fp; diff --git a/pcsx2/PluginManager.cpp b/pcsx2/PluginManager.cpp index c9822f1b24..da172756a8 100644 --- a/pcsx2/PluginManager.cpp +++ b/pcsx2/PluginManager.cpp @@ -674,18 +674,34 @@ SysCorePlugins *g_plugins = NULL; // Plugin-related Exception Implementations // --------------------------------------------------------------------------------- +wxString Exception::SaveStateLoadError::FormatDiagnosticMessage() const +{ + FastFormatUnicode retval; + retval.Write("Savestate is corrupt or incomplete!"); + _formatDiagMsg(retval); + return retval; +} + +wxString Exception::SaveStateLoadError::FormatDisplayMessage() const +{ + FastFormatUnicode retval; + retval.Write(_("The savestate cannot be loaded, as it appears to be corrupt or incomplete.")); + _formatUserMsg(retval); + return retval; +} + Exception::PluginOpenError::PluginOpenError( PluginsEnum_t pid ) { PluginId = pid; m_message_diag = L"%s plugin failed to open!"; - m_message_user = L"%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers."; + m_message_user = _("%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers."); } Exception::PluginInitError::PluginInitError( PluginsEnum_t pid ) { PluginId = pid; m_message_diag = L"%s plugin initialization failed!"; - m_message_user = L"%s plugin failed to initialize. Your system may have insufficient memory or resources needed."; + m_message_user = _("%s plugin failed to initialize. Your system may have insufficient memory or resources needed."); } Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid ) @@ -695,29 +711,29 @@ Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid ) wxString Exception::PluginLoadError::FormatDiagnosticMessage() const { - return wxsFormat( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() ) + + return pxsFmt( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() ) + L"\n\n" + StreamName; } wxString Exception::PluginLoadError::FormatDisplayMessage() const { - return wxsFormat( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() ) + + return pxsFmt( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() ) + L"\n\n" + StreamName; } wxString Exception::PluginError::FormatDiagnosticMessage() const { - return wxsFormat( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() ); + return pxsFmt( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() ); } wxString Exception::PluginError::FormatDisplayMessage() const { - return wxsFormat( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() ); + return pxsFmt( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() ); } wxString Exception::FreezePluginFailure::FormatDiagnosticMessage() const { - return wxsFormat( + return pxsFmt( L"%s plugin returned an error while saving the state.\n\n", tbl_PluginInfo[PluginId].shortname ); @@ -731,7 +747,7 @@ wxString Exception::FreezePluginFailure::FormatDisplayMessage() const wxString Exception::ThawPluginFailure::FormatDiagnosticMessage() const { - return wxsFormat( + return pxsFmt( L"%s plugin returned an error while loading the state.\n\n", tbl_PluginInfo[PluginId].shortname ); diff --git a/pcsx2/Plugins.h b/pcsx2/Plugins.h index fd2443874b..80b445a730 100644 --- a/pcsx2/Plugins.h +++ b/pcsx2/Plugins.h @@ -57,12 +57,15 @@ namespace Exception // Exception thrown when a corrupted or truncated savestate is encountered. class SaveStateLoadError : public BadStream { - DEFINE_STREAM_EXCEPTION( SaveStateLoadError, BadStream, wxLt("The savestate appears to be corrupt or incomplete.") ) + DEFINE_STREAM_EXCEPTION( SaveStateLoadError, BadStream ) + + virtual wxString FormatDiagnosticMessage() const; + virtual wxString FormatDisplayMessage() const; }; class PluginError : public RuntimeError { - DEFINE_RUNTIME_EXCEPTION( PluginError, RuntimeError, L"Generic plugin error") + DEFINE_RUNTIME_EXCEPTION( PluginError, RuntimeError, L"Generic plugin error!" ) public: PluginsEnum_t PluginId; diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index 0083ae6235..c55047efa3 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -108,58 +108,40 @@ void RecompiledCodeReserve::OnCommittedBlock( void* block ) } } -void RecompiledCodeReserve::ResetProcessReserves() const +void SysOutOfMemory_EmergencyResponse(uptr blocksize) { - Cpu->SetCacheReserve( (Cpu->GetCacheReserve() * 3) / 2 ); - Cpu->Reset(); + // An out of memory error occurred. All we can try to do in response is reset the various + // recompiler caches (which can sometimes total over 120megs, so it can be quite helpful). + // If the user is using interpreters, or if the memory allocation failure was on a very small + // allocation, then this code could fail; but that's fine. We're already trying harder than + // 99.995% of all programs ever written. -- air - CpuVU0->SetCacheReserve( (CpuVU0->GetCacheReserve() * 3) / 2 ); - CpuVU0->Reset(); - - 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 - // exceeded the threshold buffer, and reset the buffer on its own. - - // Note: We attempt to commit multiple pages first, since a single block of recompiled - // code can pretty easily surpass 4k. We should have enough for this, since we just - // cleared the other rec caches above -- but who knows what could happen if the user - // has another process sucking up RAM or if the operating system is fickle. If even - // that fails, give up and kill the process. - - try + if (Cpu) { - // 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( m_blocksize, 4 ); - HostSys::MmapCommitPtr((u8*)blockptr, cusion * __pagesize, m_prot_mode); - - handled = true; + Cpu->SetCacheReserve( (Cpu->GetCacheReserve() * 3) / 2 ); + Cpu->Reset(); } - catch (Exception::BaseException&) - { - // Fickle has become our reality. By setting handled to FALSE, the OS should kill - // the process for us. No point trying to log anything; this is a super-awesomely - // serious condition that likely means the system is hosed. ;) - handled = false; + if (CpuVU0) + { + CpuVU0->SetCacheReserve( (CpuVU0->GetCacheReserve() * 3) / 2 ); + CpuVU0->Reset(); + } + + if (CpuVU1) + { + CpuVU1->SetCacheReserve( (CpuVU1->GetCacheReserve() * 3) / 2 ); + CpuVU1->Reset(); + } + + if (psxCpu) + { + psxCpu->SetCacheReserve( (psxCpu->GetCacheReserve() * 3) / 2 ); + psxCpu->Reset(); } } + #if _MSC_VER # include "svnrev.h" #endif diff --git a/pcsx2/System.h b/pcsx2/System.h index f0e1fc1db5..52280eb138 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -134,6 +134,7 @@ extern SysCpuProviderPack& GetCpuProviders(); extern void SysLogMachineCaps(); // Detects cpu type and fills cpuInfo structs. extern void SysClearExecutionCache(); // clears recompiled execution caches! +extern void SysOutOfMemory_EmergencyResponse(uptr blocksize); extern u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed"); extern void vSyncDebugStuff( uint frame ); diff --git a/pcsx2/System/RecTypes.h b/pcsx2/System/RecTypes.h index c4367437f7..e999780058 100644 --- a/pcsx2/System/RecTypes.h +++ b/pcsx2/System/RecTypes.h @@ -21,9 +21,7 @@ // 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. +// cleared to INT 3 (0xcc) as needed. // class RecompiledCodeReserve : public BaseVirtualMemoryReserve { @@ -44,7 +42,6 @@ public: virtual void* Reserve( uint size, uptr base=0, uptr upper_bounds=0 ); virtual void OnCommittedBlock( void* block ); - virtual void OnOutOfMemory( const Exception::OutOfMemory& ex, void* blockptr, bool& handled ); virtual RecompiledCodeReserve& SetProfilerName( const wxString& shortname ); virtual RecompiledCodeReserve& SetProfilerName( const char* shortname ) diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index d0a4288d8e..ac3ebafff8 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -527,7 +527,9 @@ bool Pcsx2App::OnInit() InitCPUTicks(); - pxDoAssert = AppDoAssert; + pxDoAssert = AppDoAssert; + pxDoOutOfMemory = SysOutOfMemory_EmergencyResponse; + g_Conf = new AppConfig(); wxInitAllImageHandlers(); diff --git a/pcsx2/gui/Panels/PluginSelectorPanel.cpp b/pcsx2/gui/Panels/PluginSelectorPanel.cpp index d4772a462e..49863ea6f4 100644 --- a/pcsx2/gui/Panels/PluginSelectorPanel.cpp +++ b/pcsx2/gui/Panels/PluginSelectorPanel.cpp @@ -59,7 +59,15 @@ namespace Exception class NotEnumerablePlugin : public BadStream { public: - DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, BadStream, wxLt("File is not a PCSX2 plugin") ); + DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, BadStream ); + + wxString FormatDiagnosticMessage() const + { + FastFormatUnicode retval; + retval.Write("File is not a PCSX2 plugin"); + _formatDiagMsg(retval); + return retval; + } }; } diff --git a/pcsx2/gui/SysState.cpp b/pcsx2/gui/SysState.cpp index 8a7a894a63..5059dbdc9f 100644 --- a/pcsx2/gui/SysState.cpp +++ b/pcsx2/gui/SysState.cpp @@ -62,21 +62,6 @@ static void SaveStateFile_ReadHeader( IStreamReader& thr ) .SetUserMsg(_("Cannot load this savestate. The state is an unsupported version, likely created by a newer edition of PCSX2.")); }; -class gzError : public Exception::BadStream -{ - DEFINE_STREAM_EXCEPTION( gzError, BadStream, wxLt("Invalid or corrupted gzip archive") ) -}; - -class gzReadError : public gzError -{ - -}; - -class gzWriteError : public gzError -{ - -}; - // -------------------------------------------------------------------------------------- // gzipReader // -------------------------------------------------------------------------------------- diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index c72c18c5cb..4a3a6e8a62 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -451,10 +451,6 @@ RelativePath="..\..\NakedAsm.h" > - - diff --git a/pcsx2/windows/WinCompressNTFS.cpp b/pcsx2/windows/WinCompressNTFS.cpp index 3f9a42f848..c49cc0b9ea 100644 --- a/pcsx2/windows/WinCompressNTFS.cpp +++ b/pcsx2/windows/WinCompressNTFS.cpp @@ -46,7 +46,7 @@ void StreamException_ThrowLastError( const wxString& streamname, HANDLE result ) default: { - throw Exception::Stream( streamname ).SetDiagMsg(wxsFormat( L"General Win32 File/stream error [GetLastError: %d]", error )); + throw Exception::BadStream( streamname ).SetDiagMsg(pxsFmt( L"General Win32 File/stream error [GetLastError: %d]", error )); } } } @@ -58,7 +58,7 @@ bool StreamException_LogLastError( const wxString& streamname, const wxChar* act { StreamException_ThrowLastError( streamname, result ); } - catch( Exception::Stream& ex ) + catch( Exception::BadStream& ex ) { Console.WriteLn( Color_Yellow, L"%s: %s", action, ex.FormatDiagnosticMessage().c_str() ); return true; From 7f51e8ee662fd6453b916707d1935c17e41523eb Mon Sep 17 00:00:00 2001 From: arcum42 Date: Sat, 6 Nov 2010 05:21:06 +0000 Subject: [PATCH 13/22] newHostVM: Linux compilation fixes. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@3998 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/src/Utilities/Linux/LnxHostSys.cpp | 4 ++-- common/src/Utilities/VirtualMemory.cpp | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/common/src/Utilities/Linux/LnxHostSys.cpp b/common/src/Utilities/Linux/LnxHostSys.cpp index 5c224431f4..7cff02002b 100644 --- a/common/src/Utilities/Linux/LnxHostSys.cpp +++ b/common/src/Utilities/Linux/LnxHostSys.cpp @@ -91,7 +91,7 @@ bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& m // as PROT_NONE, then just ignore this call (memory will be committed automatically // later when the user changes permissions to something useful via calls to MemProtect). - if (mode.IsNone()) return; + if (mode.IsNone()) return false; if (_memprotect( base, size, mode )) return true; @@ -153,7 +153,7 @@ void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& { if (!_memprotect(baseaddr, size, mode)) { - throw Exception::OutOfMemory( "MemProtect" ) + throw Exception::OutOfMemory( L"MemProtect" ) .SetDiagMsg(pxsFmt( L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)", baseaddr, (uptr)baseaddr+size, mode.ToString().c_str() ) diff --git a/common/src/Utilities/VirtualMemory.cpp b/common/src/Utilities/VirtualMemory.cpp index bf0e532d5c..fa4e96a399 100644 --- a/common/src/Utilities/VirtualMemory.cpp +++ b/common/src/Utilities/VirtualMemory.cpp @@ -17,7 +17,11 @@ #include "PageFaultSource.h" #include "EventSource.inl" -#include "MemsetFast.inl" +#include "MemsetFast.inl" + +#ifndef __WXMSW__ +#include +#endif template class EventSource< IEventListener_PageFault >; From d6de2e39421757aa0528730f973cad1dac229459 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Sat, 6 Nov 2010 16:25:40 +0000 Subject: [PATCH 14/22] newHostVM: Made use of the new SpatialArrayReserve for the EE/R5900 recompiler. Reduces the recompiler's lookup tables from ~40mb to a mere 1-3mb. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@4003 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/include/Utilities/PageFaultSource.h | 18 +- common/src/Utilities/VirtualMemory.cpp | 731 +++++++++++---------- pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 1 + pcsx2/x86/BaseblockEx.h | 6 +- pcsx2/x86/ix86-32/iR5900-32.cpp | 237 ++++--- 5 files changed, 525 insertions(+), 468 deletions(-) diff --git a/common/include/Utilities/PageFaultSource.h b/common/include/Utilities/PageFaultSource.h index cf4bb313a6..32e71e98b9 100644 --- a/common/include/Utilities/PageFaultSource.h +++ b/common/include/Utilities/PageFaultSource.h @@ -148,6 +148,18 @@ public: operator u8*() { return (u8*)m_baseptr; } operator const u8*() const { return (u8*)m_baseptr; } + u8& operator[](uint idx) + { + pxAssume(idx < (m_reserved * __pagesize)); + return *((u8*)m_baseptr + idx); + } + + const u8& operator[](uint idx) const + { + pxAssume(idx < (m_reserved * __pagesize)); + return *((u8*)m_baseptr + idx); + } + protected: void OnPageFaultEvent( const PageFaultInfo& info, bool& handled ); @@ -204,7 +216,7 @@ protected: ScopedAlignedAlloc m_blockbits; public: - SpatialArrayReserve( const wxString& name, uint defCommit = 0 ); + SpatialArrayReserve( const wxString& name ); virtual void* Reserve( uint size, uptr base = 0, uptr upper_bounds = 0 ); virtual void Reset(); @@ -216,14 +228,16 @@ public: SpatialArrayReserve& SetBlockSizeInPages( uint bytes ); uint SetBlockSize( uint bytes ); - operator void*() { return m_baseptr; } operator const void*() const { return m_baseptr; } operator u8*() { return (u8*)m_baseptr; } operator const u8*() const { return (u8*)m_baseptr; } + + using __parent::operator[]; protected: + void DoCommitAndProtect( uptr page ); uint _calcBlockBitArrayLength() const; }; diff --git a/common/src/Utilities/VirtualMemory.cpp b/common/src/Utilities/VirtualMemory.cpp index fa4e96a399..63f8eae822 100644 --- a/common/src/Utilities/VirtualMemory.cpp +++ b/common/src/Utilities/VirtualMemory.cpp @@ -1,358 +1,379 @@ -/* 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 "PageFaultSource.h" -#include "EventSource.inl" +/* 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 "PageFaultSource.h" +#include "EventSource.inl" #include "MemsetFast.inl" - -#ifndef __WXMSW__ + +#ifndef __WXMSW__ #include #endif - -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_blocksize = __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 = HostSys::MmapReserve( 0, reserved_bytes ); - } - - if ((upper_bounds != 0) && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)) - { - SafeSysMunmap( m_baseptr, reserved_bytes ); - // returns null, caller should throw an exception or handle appropriately. - } - } - - if (!m_baseptr) return NULL; - - DevCon.WriteLn( Color_Blue, L"%-32s @ 0x%08X -> 0x%08X [%umb]", Name.c_str(), - m_baseptr, (uptr)m_baseptr+reserved_bytes, reserved_bytes / _1mb); - - 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::MmapResetPtr(m_baseptr, m_commited*__pagesize); - m_commited = 0; -} - -void BaseVirtualMemoryReserve::Free() -{ - HostSys::Munmap((uptr)m_baseptr, m_reserved*__pagesize); -} - -// If growing the array, or if shrinking the array to some point that's still *greater* than the -// committed memory range, then attempt a passive "on-the-fly" resize that maps/unmaps some portion -// of the reserve. -// -// If the above conditions are not met, or if the map/unmap fails, this method returns false. -// The caller will be responsible for manually resetting the reserve. -// -// Parameters: -// newsize - new size of the reserved buffer, in bytes. -bool BaseVirtualMemoryReserve::TryResize( uint newsize ) -{ - uint newPages = (newsize + __pagesize - 1) / __pagesize; - - if (newPages > m_reserved) - { - uint toReservePages = newPages - m_reserved; - uint toReserveBytes = toReservePages * __pagesize; - - DevCon.WriteLn( L"%-32s is being expanded by %u pages.", Name.c_str(), toReservePages); - - m_baseptr = (void*)HostSys::MmapReserve((uptr)GetPtrEnd(), toReserveBytes); - - if (!m_baseptr) - { - Console.Warning("%-32s could not be passively resized due to virtual memory conflict!"); - Console.Indent().Warning("(attempted to map memory @ 0x%08X -> 0x%08X", m_baseptr, (uptr)m_baseptr+toReserveBytes); - } - - 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) - { - if (m_commited > newsize) return false; - - uint toRemovePages = m_reserved - newPages; - uint toRemoveBytes = toRemovePages * __pagesize; - - DevCon.WriteLn( L"%-32s is being shrunk by %u pages.", Name.c_str(), toRemovePages); - - HostSys::MmapResetPtr(GetPtrEnd(), toRemoveBytes); - - DevCon.WriteLn( Color_Blue, L"%-32s @ 0x%08X -> 0x%08X [%umb]", Name.c_str(), - m_baseptr, (uptr)m_baseptr+toRemoveBytes, toRemoveBytes / _1mb); - } - - return true; -} - - -void BaseVirtualMemoryReserve::CommitBlocks( uptr page, uint blocks ) -{ - const uptr blocksbytes = blocks * m_blocksize * __pagesize; - void* blockptr = (u8*)m_baseptr + (page * __pagesize); - - // Depending on the operating system, this call could fail if the system is low on either - // physical ram or virtual memory. - if (!HostSys::MmapCommitPtr(blockptr, blocksbytes, m_prot_mode)) - { - throw Exception::OutOfMemory(Name) - .SetDiagMsg(pxsFmt("An additional %u blocks @ 0x%08x were requested, but could not be committed!", blocks, blockptr)); - } - - u8* init = (u8*)blockptr; - u8* endpos = init + blocksbytes; - for( ; init= m_reserved)) return; - - // Linux Note! the SIGNAL handler is very limited in what it can do, and not only can't - // we let the C++ exception try to unwind the stack, we may not be able to log it either. - // (but we might as well try -- kernel/posix rules says not to do it, but Linux kernel - // implementations seem to support it). - // Note also that logging the exception and/or issuing an assertion dialog are always - // possible if the thread handling the signal is not the main thread. - - // In windows we can let exceptions bubble out of the page fault handler. SEH will more - // or less handle them in a semi-expected way, and might even avoid a GPF long enough - // for the system to log the error or something. - - #ifndef __WXMSW__ - try { - #endif - DoCommitAndProtect( offset ); - handled = true; - - #ifndef __WXMSW__ - } - catch (Exception::BaseException& ex) - { - handled = false; - if (!wxThread::IsMain()) - { - pxFailRel( ex.FormatDiagnosticMessage() ); - } - else - { - wxTrap(); - } - } - #endif -} - - -// -------------------------------------------------------------------------------------- -// SpatialArrayReserve (implementations) -// -------------------------------------------------------------------------------------- - -uint SpatialArrayReserve::_calcBlockBitArrayLength() const -{ - return (m_numblocks + 127) / 128; -} - -void* SpatialArrayReserve::Reserve( uint size, uptr base, uptr upper_bounds ) -{ - return __parent::Reserve( size, base, upper_bounds ); -} - -// Resets/clears the spatial array, reducing the memory commit pool overhead to zero (0). -void SpatialArrayReserve::Reset() -{ - __parent::Reset(); - memzero_sse_a(m_blockbits.GetPtr(), _calcBlockBitArrayLength()); -} - -// Important! The number of blocks of the array will be altered when using this method. -// -bool SpatialArrayReserve::TryResize( uint newsize ) -{ - uint newpages = (newsize + __pagesize - 1) / __pagesize; - - // find the last allocated block -- we cannot be allowed to resize any smaller than that: - - uint i; - for (i=m_numblocks-1; i; --i) - { - uint bit = i & 7; - if (m_blockbits[i / 8] & bit) break; - } - - uint pages_in_use = i * m_blocksize; - if (newpages < pages_in_use) return false; - - if (!__parent::TryResize( newsize )) return false; - - // On success, we must re-calibrate the internal blockbits array. - - m_blockbits.Resize( (m_numblocks + 7) / 8 ); - - return true; -} - -// This method allows the programmer to specify the block size of the array as a function -// of its reserved size. This function *must* be called *after* the reserve has been made, -// and *before* the array contents have been accessed. -// -// Calls to this function prior to initializing the reserve or after the reserve has been -// accessed (resulting in committed blocks) will be ignored -- and will generate an assertion -// in debug builds. -SpatialArrayReserve& SpatialArrayReserve::SetBlockCount( uint blocks ) -{ - pxAssumeDev( !m_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; - - return *this; -} - -// Sets the block size via pages (pages are defined by the __pagesize global, which is -// typically 4096). -// -// This method must be called prior to accessing or modifying the array contents. Calls to -// a modified buffer will be ignored (and generate an assertion in dev/debug modes). -SpatialArrayReserve& SpatialArrayReserve::SetBlockSizeInPages( uint pages ) -{ - if (pxAssertDev(m_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_blockbits.Alloc( _calcBlockBitArrayLength() ); - } - return *this; -} - -// SetBlockSize assigns the block size of the spatial array, in bytes. The actual size of -// each block will be rounded up to the nearest page size. The resulting size is returned. -// -// This method must be called prior to accessing or modifying the array contents. Calls to -// a modified buffer will be ignored (and generate an assertion in dev/debug modes). -uint SpatialArrayReserve::SetBlockSize( uint bytes ) -{ - SetBlockSizeInPages((bytes + __pagesize - 1) / __pagesize); - return m_blocksize * __pagesize; -} - -void SpatialArrayReserve::OnCommittedBlock( void* block ) -{ - // Determine the block position in the blockbits array, flag it, and be done! - - uptr relative = (uptr)m_baseptr - (uptr)block; - pxAssume( (relative % (m_blocksize * __pagesize)) == 0); - relative /= m_blocksize * __pagesize; - - m_blockbits[relative/32] |= 1 << (relative & 31); - m_commited += m_blocksize; -} - - -// -------------------------------------------------------------------------------------- -// PageProtectionMode (implementations) -// -------------------------------------------------------------------------------------- -wxString PageProtectionMode::ToString() const -{ - wxString modeStr; - - if (m_read) modeStr += L"Read"; - if (m_write) modeStr += L"Write"; - if (m_exec) modeStr += L"Exec"; - - if (modeStr.IsEmpty()) return L"NoAccess"; - if (modeStr.Length() <= 5) modeStr += L"Only"; - - return modeStr; -} + +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_blocksize = __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 = HostSys::MmapReserve( 0, reserved_bytes ); + } + + if ((upper_bounds != 0) && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)) + { + SafeSysMunmap( m_baseptr, reserved_bytes ); + // returns null, caller should throw an exception or handle appropriately. + } + } + + if (!m_baseptr) return NULL; + + DevCon.WriteLn( Color_Blue, L"%-32s @ 0x%08X -> 0x%08X [%umb]", Name.c_str(), + m_baseptr, (uptr)m_baseptr+reserved_bytes, reserved_bytes / _1mb); + + 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::MmapResetPtr(m_baseptr, m_commited*__pagesize); + m_commited = 0; +} + +void BaseVirtualMemoryReserve::Free() +{ + HostSys::Munmap((uptr)m_baseptr, m_reserved*__pagesize); +} + +// If growing the array, or if shrinking the array to some point that's still *greater* than the +// committed memory range, then attempt a passive "on-the-fly" resize that maps/unmaps some portion +// of the reserve. +// +// If the above conditions are not met, or if the map/unmap fails, this method returns false. +// The caller will be responsible for manually resetting the reserve. +// +// Parameters: +// newsize - new size of the reserved buffer, in bytes. +bool BaseVirtualMemoryReserve::TryResize( uint newsize ) +{ + uint newPages = (newsize + __pagesize - 1) / __pagesize; + + if (newPages > m_reserved) + { + uint toReservePages = newPages - m_reserved; + uint toReserveBytes = toReservePages * __pagesize; + + DevCon.WriteLn( L"%-32s is being expanded by %u pages.", Name.c_str(), toReservePages); + + m_baseptr = (void*)HostSys::MmapReserve((uptr)GetPtrEnd(), toReserveBytes); + + if (!m_baseptr) + { + Console.Warning("%-32s could not be passively resized due to virtual memory conflict!"); + Console.Indent().Warning("(attempted to map memory @ 0x%08X -> 0x%08X", m_baseptr, (uptr)m_baseptr+toReserveBytes); + } + + 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) + { + if (m_commited > newsize) return false; + + uint toRemovePages = m_reserved - newPages; + uint toRemoveBytes = toRemovePages * __pagesize; + + DevCon.WriteLn( L"%-32s is being shrunk by %u pages.", Name.c_str(), toRemovePages); + + HostSys::MmapResetPtr(GetPtrEnd(), toRemoveBytes); + + DevCon.WriteLn( Color_Blue, L"%-32s @ 0x%08X -> 0x%08X [%umb]", Name.c_str(), + m_baseptr, (uptr)m_baseptr+toRemoveBytes, toRemoveBytes / _1mb); + } + + return true; +} + + +void BaseVirtualMemoryReserve::CommitBlocks( uptr page, uint blocks ) +{ + const uptr blocksbytes = blocks * m_blocksize * __pagesize; + void* blockptr = (u8*)m_baseptr + (page * __pagesize); + + // Depending on the operating system, this call could fail if the system is low on either + // physical ram or virtual memory. + if (!HostSys::MmapCommitPtr(blockptr, blocksbytes, m_prot_mode)) + { + throw Exception::OutOfMemory(Name) + .SetDiagMsg(pxsFmt("An additional %u blocks @ 0x%08x were requested, but could not be committed!", blocks, blockptr)); + } + + u8* init = (u8*)blockptr; + u8* endpos = init + blocksbytes; + for( ; init= m_reserved)) return; + + // Linux Note! the SIGNAL handler is very limited in what it can do, and not only can't + // we let the C++ exception try to unwind the stack, we may not be able to log it either. + // (but we might as well try -- kernel/posix rules says not to do it, but Linux kernel + // implementations seem to support it). + // Note also that logging the exception and/or issuing an assertion dialog are always + // possible if the thread handling the signal is not the main thread. + + // In windows we can let exceptions bubble out of the page fault handler. SEH will more + // or less handle them in a semi-expected way, and might even avoid a GPF long enough + // for the system to log the error or something. + + #ifndef __WXMSW__ + try { + #endif + DoCommitAndProtect( offset ); + handled = true; + + #ifndef __WXMSW__ + } + catch (Exception::BaseException& ex) + { + handled = false; + if (!wxThread::IsMain()) + { + pxFailRel( ex.FormatDiagnosticMessage() ); + } + else + { + wxTrap(); + } + } + #endif +} + + +// -------------------------------------------------------------------------------------- +// SpatialArrayReserve (implementations) +// -------------------------------------------------------------------------------------- + +SpatialArrayReserve::SpatialArrayReserve( const wxString& name ) : + __parent( name ) +{ + m_prot_mode = PageAccess_ReadWrite(); +} + +uint SpatialArrayReserve::_calcBlockBitArrayLength() const +{ + // divide by 8 (rounded up) to compress 8 bits into each byte. + // mask off lower bits (rounded up) to allow for 128-bit alignment and SSE operations. + return (((m_numblocks + 7) / 8) + 15) & ~15; +} + +void* SpatialArrayReserve::Reserve( uint size, uptr base, uptr upper_bounds ) +{ + void* addr = __parent::Reserve( size, base, upper_bounds ); + if (!addr) return NULL; + + if (m_blocksize) SetBlockSizeInPages( m_blocksize ); + m_blockbits.Alloc( _calcBlockBitArrayLength() ); + + return addr; +} + +// Resets/clears the spatial array, reducing the memory commit pool overhead to zero (0). +void SpatialArrayReserve::Reset() +{ + __parent::Reset(); + memzero_sse_a(m_blockbits.GetPtr(), _calcBlockBitArrayLength()); +} + +// Important! The number of blocks of the array will be altered when using this method. +// +bool SpatialArrayReserve::TryResize( uint newsize ) +{ + uint newpages = (newsize + __pagesize - 1) / __pagesize; + + // find the last allocated block -- we cannot be allowed to resize any smaller than that: + + uint i; + for (i=m_numblocks-1; i; --i) + { + uint bit = i & 7; + if (m_blockbits[i / 8] & bit) break; + } + + uint pages_in_use = i * m_blocksize; + if (newpages < pages_in_use) return false; + + if (!__parent::TryResize( newsize )) return false; + + // On success, we must re-calibrate the internal blockbits array. + + m_blockbits.Resize( (m_numblocks + 7) / 8 ); + + return true; +} + +// This method allows the programmer to specify the block size of the array as a function +// of its reserved size. This function *must* be called *after* the reserve has been made, +// and *before* the array contents have been accessed. +// +// Calls to this function prior to initializing the reserve or after the reserve has been +// accessed (resulting in committed blocks) will be ignored -- and will generate an assertion +// in debug builds. +SpatialArrayReserve& SpatialArrayReserve::SetBlockCount( uint blocks ) +{ + pxAssumeDev( !m_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; + + return *this; +} + +// Sets the block size via pages (pages are defined by the __pagesize global, which is +// typically 4096). +// +// This method must be called prior to accessing or modifying the array contents. Calls to +// a modified buffer will be ignored (and generate an assertion in dev/debug modes). +SpatialArrayReserve& SpatialArrayReserve::SetBlockSizeInPages( uint pages ) +{ + if (pxAssertDev(!m_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_blockbits.Alloc( _calcBlockBitArrayLength() ); + } + return *this; +} + +// SetBlockSize assigns the block size of the spatial array, in bytes. The actual size of +// each block will be rounded up to the nearest page size. The resulting size is returned. +// +// This method must be called prior to accessing or modifying the array contents. Calls to +// a modified buffer will be ignored (and generate an assertion in dev/debug modes). +uint SpatialArrayReserve::SetBlockSize( uint bytes ) +{ + SetBlockSizeInPages((bytes + __pagesize - 1) / __pagesize); + return m_blocksize * __pagesize; +} + +void SpatialArrayReserve::DoCommitAndProtect( uptr page ) +{ + // Spatial Arrays work on block granularity only: + // Round the page into a block, and commit the whole block that the page belongs to. + + uint block = page / m_blocksize; + CommitBlocks(block*m_blocksize, 1); +} + +void SpatialArrayReserve::OnCommittedBlock( void* block ) +{ + // Determine the block position in the blockbits array, flag it, and be done! + + uptr relative = (uptr)block - (uptr)m_baseptr; + relative /= m_blocksize * __pagesize; + + m_blockbits[relative/32] |= 1 << (relative & 31); +} + + +// -------------------------------------------------------------------------------------- +// PageProtectionMode (implementations) +// -------------------------------------------------------------------------------------- +wxString PageProtectionMode::ToString() const +{ + wxString modeStr; + + if (m_read) modeStr += L"Read"; + if (m_write) modeStr += L"Write"; + if (m_exec) modeStr += L"Exec"; + + if (modeStr.IsEmpty()) return L"NoAccess"; + if (modeStr.Length() <= 5) modeStr += L"Only"; + + return modeStr; +} diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index 4a3a6e8a62..f648745cb0 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -70,6 +70,7 @@ Name="VCLinkerTool" AdditionalDependencies="zlib.lib rpcrt4.lib" OutputFile="$(OutDir)\$(ProjectName)-dbg.exe" + RandomizedBaseAddress="1" /> = blocks[idx].startpc + blocks[idx].size * 4))) return -1; @@ -139,9 +136,10 @@ public: static void recLUT_SetPage(uptr reclut[0x10000], uptr hwlut[0x10000], BASEBLOCK *mapbase, uint pagebase, uint pageidx, uint mappage) { + // this value is in 64k pages! uint page = pagebase + pageidx; - jASSUME( page < 0x10000 ); + pxAssume( page < 0x10000 ); reclut[page] = (uptr)&mapbase[(mappage - page) << 14]; if (hwlut) hwlut[page] = 0u - (pagebase << 16); diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index 6a605c59d0..d80b6416f4 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -36,14 +36,18 @@ # include #endif + +#include "Utilities/MemsetFast.inl" + + using namespace x86Emitter; using namespace R5900; #define PC_GETBLOCK(x) PC_GETBLOCK_(x, recLUT) u32 maxrecmem = 0; -static __aligned16 uptr recLUT[0x10000]; -static __aligned16 uptr hwLUT[0x10000]; +static __aligned16 uptr recLUT[_64kb]; +static __aligned16 uptr hwLUT[_64kb]; #define HWADDR(mem) (hwLUT[mem >> 16] + (mem)) @@ -56,6 +60,24 @@ __aligned16 GPR_reg64 g_cpuConstRegs[32] = {0}; u32 g_cpuHasConstReg = 0, g_cpuFlushedConstReg = 0; bool g_cpuFlushedPC, g_cpuFlushedCode, g_recompilingDelaySlot, g_maySignalException; +// -------------------------------------------------------------------------------------- +// R5900LutReserve_RAM +// -------------------------------------------------------------------------------------- +class R5900LutReserve_RAM : public SpatialArrayReserve +{ + typedef SpatialArrayReserve __parent; + +public: + R5900LutReserve_RAM( const wxString& name ) + : __parent( name ) + { + } + +protected: + void OnCommittedBlock( void* block ); +}; + + //////////////////////////////////////////////////////////////// // Static Private Variables - R5900 Dynarec @@ -63,13 +85,16 @@ bool g_cpuFlushedPC, g_cpuFlushedCode, g_recompilingDelaySlot, g_maySignalExcept static const int RECCONSTBUF_SIZE = 16384 * 2; // 64 bit consts in 32 bit units static RecompiledCodeReserve* recMem = NULL; +static SpatialArrayReserve* recRAMCopy = NULL; +static R5900LutReserve_RAM* recLutReserve_RAM = NULL; + static uptr m_ConfiguredCacheReserve = 64; static u32* recConstBuf = NULL; // 64-bit pseudo-immediates static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here static BASEBLOCK *recROM = NULL; // and here static BASEBLOCK *recROM1 = NULL; // also here -static u32 *recRAMCopy = NULL; + static BaseBlocks recBlocks; static u8* recPtr = NULL; static u32 *recConstBufPtr = NULL; @@ -534,12 +559,17 @@ static void _DynGen_Dispatchers() // static void __fastcall dyna_block_discard(u32 start,u32 sz); -// memory allocation handle for the entire BASEBLOCK and stack allocations. -static u8* m_recBlockAlloc = NULL; +static __ri void ClearRecLUT(BASEBLOCK* base, int memsize) +{ + for (int i = 0; i < memsize/4; i++) + base[i].SetFnptr((uptr)JITCompile); +} -static const uint m_recBlockAllocSize = - (((Ps2MemSize::MainRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK)) -+ RECCONSTBUF_SIZE * sizeof(u32) + Ps2MemSize::MainRam; +void R5900LutReserve_RAM::OnCommittedBlock( void* block ) +{ + __parent::OnCommittedBlock(block); + ClearRecLUT((BASEBLOCK*)block, __pagesize * m_blocksize); +} static void recThrowHardwareDeficiency( const wxChar* extFail ) { @@ -599,83 +629,26 @@ static void recReserve() static void recAlloc() { - // Goal: Allocate BASEBLOCKs for every possible branch target in PS2 memory. - // Any 4-byte aligned address makes a valid branch target as per MIPS design (all - // instructions are always 4 bytes long). - - if( m_recBlockAlloc == NULL ) - m_recBlockAlloc = (u8*) _aligned_malloc( m_recBlockAllocSize, 4096 ); - - if( m_recBlockAlloc == NULL ) - throw Exception::OutOfMemory( L"R5900-32 BASEBLOCK tables" ); - - u8* curpos = m_recBlockAlloc; - recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::MainRam / 4) * sizeof(BASEBLOCK); - recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK); - recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK); - recConstBuf = (u32*)curpos; curpos += RECCONSTBUF_SIZE * sizeof(u32); - recRAMCopy = (u32*)curpos; - - if( s_pInstCache == NULL ) + if (!recRAMCopy) { - s_nInstCacheSize = 128; - s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize ); + recRAMCopy = new SpatialArrayReserve( L"R5900 RAM copy" ); + recRAMCopy->SetBlockSize(_16kb); + recRAMCopy->Reserve(Ps2MemSize::MainRam); + } + + if (!recRAM) + { + recLutReserve_RAM = new R5900LutReserve_RAM( L"R5900 RAM LUT" ); + recLutReserve_RAM->SetBlockSize(_16kb); + recLutReserve_RAM->Reserve(Ps2MemSize::MainRam + Ps2MemSize::Rom + Ps2MemSize::Rom1); } - if( s_pInstCache == NULL ) - throw Exception::OutOfMemory( L"R5900-32 InstCache" ); + BASEBLOCK* basepos = (BASEBLOCK*)recLutReserve_RAM->GetPtr(); + recRAM = basepos; basepos += (Ps2MemSize::MainRam / 4); + recROM = basepos; basepos += (Ps2MemSize::Rom / 4); + recROM1 = basepos; basepos += (Ps2MemSize::Rom1 / 4); - // No errors.. Proceed with initialization: - - _DynGen_Dispatchers(); - - x86FpuState = FPU_STATE; -} - -struct ManualPageTracking -{ - u16 page; - u8 counter; -}; - -static __aligned16 u16 manual_page[Ps2MemSize::MainRam >> 12]; -static __aligned16 u8 manual_counter[Ps2MemSize::MainRam >> 12]; - -static u32 eeRecIsReset = false; -static u32 eeRecNeedsReset = false; -static bool eeRecIsActive = false; -static bool eeCpuExecuting = false; - -//////////////////////////////////////////////////// -static void recResetRaw() -{ - recAlloc(); - - if( AtomicExchange( eeRecIsReset, true ) ) return; - AtomicExchange( eeRecNeedsReset, false ); - - Console.WriteLn( Color_StrongBlack, "EE/iR5900-32 Recompiler Reset" ); - - recMem->Reset(); - - maxrecmem = 0; - - memzero_ptr( m_recBlockAlloc ); // Excluding the 32mb ram copy - memzero_ptr(recConstBuf); - ClearRecLUT((BASEBLOCK*)m_recBlockAlloc, - (((Ps2MemSize::MainRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4))); - - if( s_pInstCache ) - memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize ); - - recBlocks.Reset(); - mmap_ResetBlockTracking(); - -#ifdef _MSC_VER - __asm emms; -#else - __asm__("emms"); -#endif + pxAssert(recLutReserve_RAM->GetPtrEnd() == (u8*)basepos); for (int i = 0; i < 0x10000; i++) recLUT_SetPage(recLUT, 0, 0, 0, i, 0); @@ -706,6 +679,65 @@ static void recResetRaw() recLUT_SetPage(recLUT, hwLUT, recROM1, 0xa000, i, i - 0x1e00); } + if( recConstBuf == NULL ) + recConstBuf = (u32*) _aligned_malloc( RECCONSTBUF_SIZE * sizeof(*recConstBuf), 16 ); + + if( recConstBuf == NULL ) + throw Exception::OutOfMemory( L"R5900-32 SIMD Constants Buffer" ); + + if( s_pInstCache == NULL ) + { + s_nInstCacheSize = 128; + s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize ); + } + + if( s_pInstCache == NULL ) + throw Exception::OutOfMemory( L"R5900-32 InstCache" ); + + // No errors.. Proceed with initialization: + + _DynGen_Dispatchers(); + + x86FpuState = FPU_STATE; +} + +struct ManualPageTracking +{ + u16 page; + u8 counter; +}; + +static __aligned16 u16 manual_page[Ps2MemSize::MainRam >> 12]; +static __aligned16 u8 manual_counter[Ps2MemSize::MainRam >> 12]; + +static u32 eeRecIsReset = false; +static u32 eeRecNeedsReset = false; +static bool eeCpuExecuting = false; + +//////////////////////////////////////////////////// +static void recResetRaw() +{ + recAlloc(); + + if( AtomicExchange( eeRecIsReset, true ) ) return; + AtomicExchange( eeRecNeedsReset, false ); + + Console.WriteLn( Color_StrongBlack, "EE/iR5900-32 Recompiler Reset" ); + + recMem->Reset(); + recRAMCopy->Reset(); + recLutReserve_RAM->Reset(); + + maxrecmem = 0; + + memzero_ptr(recConstBuf); + + if( s_pInstCache ) + memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize ); + + recBlocks.Reset(); + mmap_ResetBlockTracking(); + x86SetPtr(*recMem); recPtr = *recMem; @@ -718,20 +750,21 @@ static void recResetRaw() static void recShutdown() { safe_delete( recMem ); + safe_delete( recRAMCopy ); + safe_delete( recLutReserve_RAM ); + recBlocks.Reset(); - safe_aligned_free( m_recBlockAlloc ); recRAM = recROM = recROM1 = NULL; - recConstBuf = NULL; - recRAMCopy = NULL; + safe_aligned_free( recConstBuf ); safe_free( s_pInstCache ); s_nInstCacheSize = 0; } static void recResetEE() { - if (eeRecIsActive || eeCpuExecuting) + if (eeCpuExecuting) { AtomicExchange( eeRecNeedsReset, true ); return; @@ -848,18 +881,8 @@ void R5900::Dynarec::OpcodeImpl::recBREAK( void ) //branch = 2; } -// Clears the recLUT table so that all blocks are mapped to the JIT recompiler by default. -static __ri void ClearRecLUT(BASEBLOCK* base, int count) -{ - for (int i = 0; i < count; i++) - base[i].SetFnptr((uptr)JITCompile); -} - void recClear(u32 addr, u32 size) { - BASEBLOCKEX* pexblock; - BASEBLOCK* pblock; - // necessary since recompiler doesn't call femms/emms #ifdef _MSC_VER __asm emms; @@ -878,14 +901,14 @@ void recClear(u32 addr, u32 size) u32 lowerextent = (u32)-1, upperextent = 0, ceiling = (u32)-1; - pexblock = recBlocks[blockidx + 1]; + BASEBLOCKEX* pexblock = recBlocks[blockidx + 1]; if (pexblock) ceiling = pexblock->startpc; while (pexblock = recBlocks[blockidx]) { u32 blockstart = pexblock->startpc; u32 blockend = pexblock->startpc + pexblock->size * 4; - pblock = PC_GETBLOCK(blockstart); + BASEBLOCK* pblock = PC_GETBLOCK(blockstart); if (pblock == s_pCurBlock) { blockidx--; @@ -921,7 +944,7 @@ void recClear(u32 addr, u32 size) } if (upperextent > lowerextent) - ClearRecLUT(PC_GETBLOCK(lowerextent), (upperextent - lowerextent) / 4); + ClearRecLUT(PC_GETBLOCK(lowerextent), upperextent - lowerextent); } @@ -1396,14 +1419,12 @@ static void __fastcall recRecompile( const u32 startpc ) if (eeRecNeedsReset) recResetRaw(); - // 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); - xSetPtr( recPtr ); recPtr = xGetAlignedCallTarget(); + if (0x8000d618 == startpc) + DbgCon.WriteLn("Compiling block @ 0x%08x", startpc); + s_pCurBlock = PC_GETBLOCK(startpc); pxAssert(s_pCurBlock->GetFnptr() == (uptr)JITCompile @@ -1813,10 +1834,12 @@ StartRecomp: continue; if (oldBlock->startpc >= HWADDR(pc)) continue; - if (oldBlock->startpc + oldBlock->size * 4 <= HWADDR(startpc)) + if ((oldBlock->startpc + oldBlock->size * 4) <= HWADDR(startpc)) break; - if (memcmp(&recRAMCopy[oldBlock->startpc / 4], PSM(oldBlock->startpc), - oldBlock->size * 4)) { + + if (memcmp(&(*recRAMCopy)[oldBlock->startpc / 4], PSM(oldBlock->startpc), + oldBlock->size * 4)) + { recClear(startpc, (pc - startpc) / 4); s_pCurBlockEx = recBlocks.Get(HWADDR(startpc)); pxAssert(s_pCurBlockEx->startpc == HWADDR(startpc)); @@ -1824,7 +1847,7 @@ StartRecomp: } } - memcpy_fast(&recRAMCopy[HWADDR(startpc) / 4], PSM(startpc), pc - startpc); + memcpy_fast(&(*recRAMCopy)[HWADDR(startpc) / 4], PSM(startpc), pc - startpc); } s_pCurBlock->SetFnptr((uptr)recPtr); From f1024dad9129c0d588e2cf2401645555169871d0 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Sun, 7 Nov 2010 00:04:53 +0000 Subject: [PATCH 15/22] newHostVM: Fix for savestates! git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@4004 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/src/Utilities/VirtualMemory.cpp | 20 ++++++++++++++++++-- common/src/Utilities/Windows/WinHostSys.cpp | 8 ++++++-- pcsx2/x86/iR3000A.cpp | 4 +++- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/common/src/Utilities/VirtualMemory.cpp b/common/src/Utilities/VirtualMemory.cpp index 63f8eae822..3ce141004d 100644 --- a/common/src/Utilities/VirtualMemory.cpp +++ b/common/src/Utilities/VirtualMemory.cpp @@ -264,7 +264,20 @@ 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() { - __parent::Reset(); + if (m_commited) + { + u8* curptr = GetPtr(); + const uint blockBytes = m_blocksize * __pagesize; + for (uint i=0; i 0x%08X (mode=%s)", baseaddr, (uptr)baseaddr + size, mode.ToString().c_str() )); + + pxFailDev( apiError.FormatDiagnosticMessage() ); } } diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp index 757b49a4f7..795f671f28 100644 --- a/pcsx2/x86/iR3000A.cpp +++ b/pcsx2/x86/iR3000A.cpp @@ -125,7 +125,7 @@ static void recEventTest() // stackframe setup code in this function) static void __fastcall StackFrameCheckFailed( int espORebp, int regval ) { - pxFailDev( wxsFormat( L"(R3000A Recompiler Stackframe) Sanity check failed on %s\n\tCurrent=%d; Saved=%d", + pxFailDev( pxsFmt( L"(R3000A Recompiler Stackframe) Sanity check failed on %s\n\tCurrent=%d; Saved=%d", (espORebp==0) ? L"ESP" : L"EBP", regval, (espORebp==0) ? s_store_esp : s_store_ebp ) ); @@ -827,6 +827,7 @@ void recResetIOP() for (int i = 0; i < 0x10000; i++) recLUT_SetPage(psxRecLUT, 0, 0, 0, i, 0); + // IOP knows 64k pages, hence for the 0x10000's // The bottom 2 bits of PC are always zero, so we <<14 to "compress" @@ -834,6 +835,7 @@ void recResetIOP() // We're only mapping 20 pages here in 4 places. // 0x80 comes from : (Ps2MemSize::IopRam / 0x10000) * 4 + for (int i=0; i<0x80; i++) { recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0x0000, i, i & 0x1f); From be1a5904645c68b439fbd149bba0945dc5229f8d Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Mon, 15 Nov 2010 14:05:02 +0000 Subject: [PATCH 16/22] newHostVM: (WIP, may not run!) -- Applied host virtual memory mapping to the EE/IOP/VU main and on-chip memory banks. Added a new OO-based system allocator object for handling said virtual memory resources. Plus many code cleanups, and some added mess that needs to be cleaned up. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@4020 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/include/Utilities/Dependencies.h | 1 + common/include/Utilities/PageFaultSource.h | 129 ++++++++++++---- common/src/Utilities/Linux/LnxHostSys.cpp | 53 +++++++ common/src/Utilities/VirtualMemory.cpp | 159 ++++++++++++++------ common/src/Utilities/Windows/WinHostSys.cpp | 19 ++- pcsx2/IopMem.cpp | 44 ++++-- pcsx2/IopMem.h | 1 + pcsx2/Linux/LnxHostSys.cpp | 58 ------- pcsx2/Linux/LnxKeyCodes.cpp | 2 + pcsx2/Memory.cpp | 69 +++++---- pcsx2/Memory.h | 4 +- pcsx2/MemoryTypes.h | 25 +-- pcsx2/R5900.cpp | 8 +- pcsx2/System.cpp | 111 ++++++-------- pcsx2/System.h | 51 ++++--- pcsx2/System/RecTypes.h | 6 +- pcsx2/System/SysCoreThread.cpp | 15 +- pcsx2/System/SysThreads.h | 1 + pcsx2/VUmicro.h | 20 +-- pcsx2/VUmicroMem.cpp | 42 +++--- pcsx2/gui/App.h | 7 +- pcsx2/gui/AppCoreThread.cpp | 12 +- pcsx2/gui/AppCoreThread.h | 1 + pcsx2/gui/AppEventListeners.h | 10 +- pcsx2/gui/AppInit.cpp | 12 +- pcsx2/gui/AppMain.cpp | 13 +- pcsx2/vtlb.cpp | 107 +++++++------ pcsx2/vtlb.h | 105 +++++++++++-- pcsx2/windows/WinSysExec.cpp | 14 -- pcsx2/x86/ix86-32/iR5900-32.cpp | 6 +- 30 files changed, 691 insertions(+), 414 deletions(-) delete mode 100644 pcsx2/Linux/LnxHostSys.cpp 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); } From 239c9f83d8d94a6f1fb5a2c25d98c4773ffca1da Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Tue, 16 Nov 2010 00:22:18 +0000 Subject: [PATCH 17/22] newHostVM: (Restored booting) - * Added some bounds checking to debug builds for VTLB mappings. * Fixed a VU mapping bug that caused boot crashing * Fixed some startup, shutdown, and reset resource management. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@4021 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/include/Utilities/PageFaultSource.h | 6 +- pcsx2/CMakeLists.txt | 1 - pcsx2/IopMem.cpp | 4 +- pcsx2/Linux/pcsx2.cbp | 1 - pcsx2/Memory.cpp | 2 +- pcsx2/System.cpp | 26 ++++--- pcsx2/System.h | 16 ++--- pcsx2/System/SysCoreThread.cpp | 2 +- pcsx2/VUmicroMem.cpp | 8 +-- pcsx2/vtlb.cpp | 79 ++++++++++++---------- pcsx2/vtlb.h | 16 ++--- pcsx2/x86/microVU_Misc.inl | 2 +- 12 files changed, 88 insertions(+), 75 deletions(-) diff --git a/common/include/Utilities/PageFaultSource.h b/common/include/Utilities/PageFaultSource.h index ce16f63aa6..07ea665d06 100644 --- a/common/include/Utilities/PageFaultSource.h +++ b/common/include/Utilities/PageFaultSource.h @@ -57,7 +57,6 @@ public: pxFailRel( "Don't call me, damnit. Use DispatchException instead." ); } -protected: virtual void OnPageFaultEvent( const PageFaultInfo& evtinfo, bool& handled ) {} }; @@ -93,7 +92,7 @@ public: protected: virtual void OnPageFaultEvent( const PageFaultInfo& info, bool& handled ) { - OnPageFaultEvent( info, handled ); + Owner->OnPageFaultEvent( info, handled ); } }; @@ -230,9 +229,10 @@ public: using _parent::operator[]; -protected: void OnPageFaultEvent( const PageFaultInfo& info, bool& handled ); +protected: + // This function is called from OnPageFaultEvent after the address has been translated // and confirmed to apply to this reserved area in question. OnPageFaultEvent contains // a try/catch exception handler, which ensures "reasonable" error response behavior if diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index fac53faafc..82957bf97c 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -383,7 +383,6 @@ set(pcsx2IPUHeaders # Linux sources set(pcsx2LinuxSources - Linux/LnxHostSys.cpp Linux/LnxKeyCodes.cpp) # Linux headers diff --git a/pcsx2/IopMem.cpp b/pcsx2/IopMem.cpp index 00b619378a..be31cf2b4b 100644 --- a/pcsx2/IopMem.cpp +++ b/pcsx2/IopMem.cpp @@ -99,9 +99,9 @@ void iopMemoryReserve::Reset() //for (i=0; i<0x0008; i++) psxMemWLUT[i + 0xbfc0] = (uptr)&psR[i << 16]; } -void iopMemoryReserve::Shutdown() +void iopMemoryReserve::Decommit() { - _parent::Shutdown(); + _parent::Decommit(); safe_aligned_free(psxMemWLUT); psxMemRLUT = NULL; diff --git a/pcsx2/Linux/pcsx2.cbp b/pcsx2/Linux/pcsx2.cbp index 0de2bb31c6..d3855a71c4 100644 --- a/pcsx2/Linux/pcsx2.cbp +++ b/pcsx2/Linux/pcsx2.cbp @@ -317,7 +317,6 @@ - diff --git a/pcsx2/Memory.cpp b/pcsx2/Memory.cpp index 415ca979f7..0b0965873c 100644 --- a/pcsx2/Memory.cpp +++ b/pcsx2/Memory.cpp @@ -579,7 +579,7 @@ void memClearPageAddr(u32 vaddr) class mmap_PageFaultHandler : public EventListener_PageFault { -protected: +public: void OnPageFaultEvent( const PageFaultInfo& info, bool& handled ); }; diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index b922787d20..400fb27738 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -339,7 +339,6 @@ SysMainMemory::SysMainMemory() SysMainMemory::~SysMainMemory() throw() { - ShutdownAll(); ReleaseAll(); } @@ -356,6 +355,7 @@ void SysMainMemory::ReserveAll() void SysMainMemory::CommitAll() { + vtlb_Core_Alloc(); if (m_ee.IsCommitted() && m_iop.IsCommitted() && m_vu.IsCommitted()) return; DevCon.WriteLn( "PS2vm: Allocating host memory for all virtual systems..." ); @@ -377,22 +377,30 @@ void SysMainMemory::ResetAll() m_vu.Reset(); } -void SysMainMemory::ShutdownAll() +void SysMainMemory::DecommitAll() { - Console.WriteLn( "PS2vm: Shutting down host memory for all virtual systems..." ); + if (!m_ee.IsCommitted() && !m_iop.IsCommitted() && !m_vu.IsCommitted()) return; - m_ee.Shutdown(); - m_iop.Shutdown(); - m_vu.Shutdown(); + Console.WriteLn( "PS2vm: Decommitting host memory for all virtual systems..." ); + + m_ee.Decommit(); + m_iop.Decommit(); + m_vu.Decommit(); + + vtlb_Core_Free(); } void SysMainMemory::ReleaseAll() { + DecommitAll(); + Console.WriteLn( "PS2vm: Releasing host memory maps for all virtual systems..." ); - m_ee.Shutdown(); - m_iop.Shutdown(); - m_vu.Shutdown(); + vtlb_Core_Free(); // Just to be sure... (calling order could result in it getting missed during Decommit). + + m_ee.Decommit(); + m_iop.Decommit(); + m_vu.Decommit(); safe_delete(Source_PageFault); } diff --git a/pcsx2/System.h b/pcsx2/System.h index 00a92f88da..dd34f0f117 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -47,25 +47,25 @@ namespace HostMemoryMap static const uptr sVU1rec = _256mb - (_8mb*2); // PS2 main memory, SPR, and ROMs - static const uptr EEmem = 0x30000000; + static const uptr EEmem = 0x20000000; // IOP main memory and ROMs - static const uptr IOPmem = 0x34000000; + static const uptr IOPmem = 0x24000000; // VU0 and VU1 memory. - static const uptr VUmem = 0x38000000; + static const uptr VUmem = 0x28000000; // EE recompiler code cache area (64mb) - static const uptr EErec = 0x40000000; + static const uptr EErec = 0x30000000; // IOP recompiler code cache area (16 or 32mb) - static const uptr IOPrec = 0x44000000; + static const uptr IOPrec = 0x34000000; // microVU1 recompiler code cache area (32 or 64mb) - static const uptr mVU0rec = 0x48000000; + static const uptr mVU0rec = 0x38000000; // microVU0 recompiler code cache area (64mb) - static const uptr mVU1rec = 0x50000000; + static const uptr mVU1rec = 0x40000000; } // -------------------------------------------------------------------------------------- @@ -86,7 +86,7 @@ public: virtual void ReserveAll(); virtual void CommitAll(); virtual void ResetAll(); - virtual void ShutdownAll(); + virtual void DecommitAll(); virtual void ReleaseAll(); }; diff --git a/pcsx2/System/SysCoreThread.cpp b/pcsx2/System/SysCoreThread.cpp index 4c28750d44..d52b89866c 100644 --- a/pcsx2/System/SysCoreThread.cpp +++ b/pcsx2/System/SysCoreThread.cpp @@ -124,7 +124,7 @@ void SysCoreThread::ResetQuick() void SysCoreThread::Reset() { ResetQuick(); - GetVmMemory().ShutdownAll(); + GetVmMemory().DecommitAll(); SysClearExecutionCache(); } diff --git a/pcsx2/VUmicroMem.cpp b/pcsx2/VUmicroMem.cpp index 5eea6ec73c..70c2f9643a 100644 --- a/pcsx2/VUmicroMem.cpp +++ b/pcsx2/VUmicroMem.cpp @@ -33,10 +33,10 @@ void vuMemoryReserve::Reserve() //_parent::Reserve(EmuConfig.HostMemMap.VUmem); u8* curpos = m_reserve.GetPtr(); - VU0.Micro = curpos; curpos += 0x1000; - VU0.Mem = curpos; curpos += 0x4000; - VU1.Micro = curpos; curpos += 0x4000; - VU1.Mem = curpos; + VU0.Micro = curpos; curpos += VU0_PROGSIZE; + VU0.Mem = curpos; curpos += VU0_MEMSIZE; + VU1.Micro = curpos; curpos += VU1_PROGSIZE; + VU1.Mem = curpos; curpos += VU1_MEMSIZE; } void vuMemoryReserve::Release() diff --git a/pcsx2/vtlb.cpp b/pcsx2/vtlb.cpp index fb4fd2f37a..a0df4ba944 100644 --- a/pcsx2/vtlb.cpp +++ b/pcsx2/vtlb.cpp @@ -148,9 +148,9 @@ void __fastcall vtlb_memWrite(u32 addr, DataType data) switch( DataSize ) { - case 8: return ((vtlbMemW8FP*)vtlbdata.RWFT[0][1][hand])(paddr, (u8)data); - case 16: return ((vtlbMemW16FP*)vtlbdata.RWFT[1][1][hand])(paddr, (u16)data); - case 32: return ((vtlbMemW32FP*)vtlbdata.RWFT[2][1][hand])(paddr, (u32)data); + case 8: return ((vtlbMemW8FP*)vtlbdata.RWFT[0][1][hand])(paddr, (u8)data); + case 16: return ((vtlbMemW16FP*)vtlbdata.RWFT[1][1][hand])(paddr, (u16)data); + case 32: return ((vtlbMemW32FP*)vtlbdata.RWFT[2][1][hand])(paddr, (u32)data); jNO_DEFAULT; } @@ -378,24 +378,25 @@ __ri vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMem // function. // // The memory region start and size parameters must be pagesize aligned. -void vtlb_MapHandler(vtlbHandler handler,u32 start,u32 size) +void vtlb_MapHandler(vtlbHandler handler, u32 start, u32 size) { verify(0==(start&VTLB_PAGE_MASK)); verify(0==(size&VTLB_PAGE_MASK) && size>0); - s32 value=handler|0x80000000; - while(size>0) + s32 value = handler | 0x80000000; + u32 end = start + (size - VTLB_PAGE_SIZE); + pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) ); + + while (start <= end) { - vtlbdata.pmap[start>>VTLB_PAGE_BITS]=value; - - start+=VTLB_PAGE_SIZE; - size-=VTLB_PAGE_SIZE; + vtlbdata.pmap[start>>VTLB_PAGE_BITS] = value; + start += VTLB_PAGE_SIZE; } } -void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize) +void vtlb_MapBlock(void* base, u32 start, u32 size, u32 blocksize) { - s32 baseint=(s32)base; + s32 baseint = (s32)base; verify(0==(start&VTLB_PAGE_MASK)); verify(0==(size&VTLB_PAGE_MASK) && size>0); @@ -404,19 +405,21 @@ void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize) verify(0==(blocksize&VTLB_PAGE_MASK) && blocksize>0); verify(0==(size%blocksize)); - while(size>0) + u32 end = start + (size - VTLB_PAGE_SIZE); + pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) ); + + while (start <= end) { - u32 blocksz=blocksize; - s32 ptr=baseint; + u32 loopsz = blocksize; + s32 ptr = baseint; - while(blocksz>0) + while (loopsz > 0) { - vtlbdata.pmap[start>>VTLB_PAGE_BITS]=ptr; + vtlbdata.pmap[start>>VTLB_PAGE_BITS] = ptr; - start+=VTLB_PAGE_SIZE; - ptr+=VTLB_PAGE_SIZE; - blocksz-=VTLB_PAGE_SIZE; - size-=VTLB_PAGE_SIZE; + start += VTLB_PAGE_SIZE; + ptr += VTLB_PAGE_SIZE; + loopsz -= VTLB_PAGE_SIZE; } } } @@ -427,13 +430,15 @@ void vtlb_Mirror(u32 new_region,u32 start,u32 size) verify(0==(start&VTLB_PAGE_MASK)); verify(0==(size&VTLB_PAGE_MASK) && size>0); - while(size>0) - { - vtlbdata.pmap[start>>VTLB_PAGE_BITS]=vtlbdata.pmap[new_region>>VTLB_PAGE_BITS]; + u32 end = start + (size-VTLB_PAGE_SIZE); + pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) ); - start+=VTLB_PAGE_SIZE; - new_region+=VTLB_PAGE_SIZE; - size-=VTLB_PAGE_SIZE; + while(start <= end) + { + vtlbdata.pmap[start>>VTLB_PAGE_BITS] = vtlbdata.pmap[new_region>>VTLB_PAGE_BITS]; + + start += VTLB_PAGE_SIZE; + new_region += VTLB_PAGE_SIZE; } } @@ -470,6 +475,7 @@ void vtlb_VMap(u32 vaddr,u32 paddr,u32 sz) if (pme<0) pme|=paddr;// top bit is set anyway ... } + vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=pme-vaddr; vaddr+=VTLB_PAGE_SIZE; paddr+=VTLB_PAGE_SIZE; @@ -568,11 +574,14 @@ void vtlb_Term() // default is used. void vtlb_Core_Alloc() { - vtlbdata.vmap = (s32*)_aligned_malloc( VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap), 16 ); if (!vtlbdata.vmap) - throw Exception::OutOfMemory( L"VTLB Virtual Address Translation LUT" ) - .SetDiagMsg(pxsFmt("(%u megs)", VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap) / _1mb) - ); + { + vtlbdata.vmap = (s32*)_aligned_malloc( VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap), 16 ); + if (!vtlbdata.vmap) + throw Exception::OutOfMemory( L"VTLB Virtual Address Translation LUT" ) + .SetDiagMsg(pxsFmt("(%u megs)", VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap) / _1mb) + ); + } } void vtlb_Core_Free() @@ -596,7 +605,7 @@ void VtlbMemoryReserve::SetBaseAddr( uptr newaddr ) void VtlbMemoryReserve::Reserve( sptr hostptr ) { - m_reserve.Reserve(); + m_reserve.ReserveAt( hostptr ); if (!m_reserve.IsOk()) throw Exception::OutOfMemory( m_reserve.GetName() ); } @@ -610,13 +619,11 @@ void VtlbMemoryReserve::Commit() void VtlbMemoryReserve::Reset() { - if (!m_reserve.Commit()) - throw Exception::OutOfMemory( m_reserve.GetName() ); - + Commit(); memzero_sse_a(m_reserve.GetPtr(), m_reserve.GetCommittedBytes()); } -void VtlbMemoryReserve::Shutdown() +void VtlbMemoryReserve::Decommit() { m_reserve.Reset(); } diff --git a/pcsx2/vtlb.h b/pcsx2/vtlb.h index 934988d60b..d840643c18 100644 --- a/pcsx2/vtlb.h +++ b/pcsx2/vtlb.h @@ -107,7 +107,7 @@ public: virtual void Commit(); virtual void Reset(); - virtual void Shutdown(); + virtual void Decommit(); virtual void SetBaseAddr( uptr newaddr ); bool IsCommitted() const; @@ -149,7 +149,7 @@ public: void Reserve(); void Release(); void Reset(); - void Shutdown(); + void Decommit(); }; // -------------------------------------------------------------------------------------- @@ -178,8 +178,8 @@ namespace vtlb_private static const uint VTLB_PAGE_MASK = 4095; static const uint VTLB_PAGE_SIZE = 4096; - static const uint VTLB_PMAP_ITEMS = _256mb / VTLB_PAGE_SIZE; - static const uint VTLB_PMAP_SZ = _256mb; + static const uint VTLB_PMAP_SZ = _1mb * 512; + static const uint VTLB_PMAP_ITEMS = VTLB_PMAP_SZ / VTLB_PAGE_SIZE; static const uint VTLB_VMAP_ITEMS = _4gb / VTLB_PAGE_SIZE; struct MapData @@ -193,10 +193,10 @@ 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 + MapData() + { + vmap = NULL; + } }; extern __aligned(64) MapData vtlbdata; diff --git a/pcsx2/x86/microVU_Misc.inl b/pcsx2/x86/microVU_Misc.inl index 285de1d901..1906e47725 100644 --- a/pcsx2/x86/microVU_Misc.inl +++ b/pcsx2/x86/microVU_Misc.inl @@ -251,7 +251,7 @@ __fi void mVUaddrFix(mV, const x32& gprReg) else { if (IsDevBuild && !isCOP2) mVUbackupRegs(mVU, true); xTEST(gprReg, 0x400); - xForwardJNZ8 jmpA; // if addr & 0x4000, reads VU1's VF regs and VI regs + xForwardJNZ8 jmpA; // if addr & 0x4000, reads VU1's VF regs and VI regs xAND(gprReg, 0xff); // if !(addr & 0x4000), wrap around xForwardJump8 jmpB; jmpA.SetTarget(); From 9a0a89aa134fa63f88d1f0e715f7ec818c70b753 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Tue, 16 Nov 2010 04:53:52 +0000 Subject: [PATCH 18/22] newHostVM: Cleanups, improved error messages. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@4022 96395faa-99c1-11dd-bbfe-3dabce05a288 --- pcsx2/IopMem.cpp | 6 ++ pcsx2/Memory.cpp | 41 +++++++--- pcsx2/vtlb.cpp | 137 +++++++++++++++++--------------- pcsx2/vtlb.h | 11 ++- pcsx2/x86/ix86-32/iR5900-32.cpp | 5 +- 5 files changed, 120 insertions(+), 80 deletions(-) diff --git a/pcsx2/IopMem.cpp b/pcsx2/IopMem.cpp index be31cf2b4b..e623b35c95 100644 --- a/pcsx2/IopMem.cpp +++ b/pcsx2/IopMem.cpp @@ -36,6 +36,11 @@ void iopMemoryReserve::Reserve() { _parent::Reserve(HostMemoryMap::IOPmem); //_parent::Reserve(EmuConfig.HostMap.IOP); +} + +void iopMemoryReserve::Commit() +{ + _parent::Commit(); iopMem = (IopVM_MemoryAllocMess*)m_reserve.GetPtr(); } @@ -105,6 +110,7 @@ void iopMemoryReserve::Decommit() safe_aligned_free(psxMemWLUT); psxMemRLUT = NULL; + iopMem = NULL; } void iopMemoryReserve::Release() diff --git a/pcsx2/Memory.cpp b/pcsx2/Memory.cpp index 0b0965873c..547839bff5 100644 --- a/pcsx2/Memory.cpp +++ b/pcsx2/Memory.cpp @@ -154,14 +154,14 @@ void memMapPhy() vtlb_MapBlock(iopMem->Main,0x1c000000,0x00800000); // Generic Handlers; These fallback to mem* stuff... - vtlb_MapHandler(tlb_fallback_7,0x14000000,0x10000); - vtlb_MapHandler(tlb_fallback_4,0x18000000,0x10000); - vtlb_MapHandler(tlb_fallback_5,0x1a000000,0x10000); - vtlb_MapHandler(tlb_fallback_6,0x12000000,0x10000); - vtlb_MapHandler(tlb_fallback_8,0x1f000000,0x10000); - vtlb_MapHandler(tlb_fallback_3,0x1f400000,0x10000); - vtlb_MapHandler(tlb_fallback_2,0x1f800000,0x10000); - vtlb_MapHandler(tlb_fallback_8,0x1f900000,0x10000); + vtlb_MapHandler(tlb_fallback_7,0x14000000, _64kb); + vtlb_MapHandler(tlb_fallback_4,0x18000000, _64kb); + vtlb_MapHandler(tlb_fallback_5,0x1a000000, _64kb); + vtlb_MapHandler(tlb_fallback_6,0x12000000, _64kb); + vtlb_MapHandler(tlb_fallback_8,0x1f000000, _64kb); + vtlb_MapHandler(tlb_fallback_3,0x1f400000, _64kb); + vtlb_MapHandler(tlb_fallback_2,0x1f800000, _64kb); + vtlb_MapHandler(tlb_fallback_8,0x1f900000, _64kb); // Hardware Register Handlers : specialized/optimized per-page handling of HW register accesses // (note that hw_by_page handles are assigned in memReset prior to calling this function) @@ -187,9 +187,9 @@ void memMapKernelMem() //lower 512 mb: direct map //vtlb_VMap(0x00000000,0x00000000,0x20000000); //0x8* mirror - vtlb_VMap(0x80000000,0x00000000,0x20000000); + vtlb_VMap(0x80000000, 0x00000000, _1mb*512); //0xa* mirror - vtlb_VMap(0xA0000000,0x00000000,0x20000000); + vtlb_VMap(0xA0000000, 0x00000000, _1mb*512); } //what do do with these ? @@ -630,6 +630,11 @@ void eeMemoryReserve::Reserve() { _parent::Reserve(HostMemoryMap::EEmem); //_parent::Reserve(EmuConfig.HostMap.IOP); +} + +void eeMemoryReserve::Commit() +{ + _parent::Commit(); eeMem = (EEVM_MemoryAllocMess*)m_reserve.GetPtr(); } @@ -762,6 +767,12 @@ void eeMemoryReserve::Reset() LoadBIOS(); } +void eeMemoryReserve::Decommit() +{ + _parent::Decommit(); + eeMem = NULL; +} + void eeMemoryReserve::Release() { safe_delete(mmap_faultHandler); @@ -827,6 +838,8 @@ static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::MainRam // int mmap_GetRamPageInfo( u32 paddr ) { + pxAssume( eeMem ); + paddr &= ~0xfff; uptr ptr = (uptr)PSM( paddr ); @@ -842,6 +855,8 @@ int mmap_GetRamPageInfo( u32 paddr ) // paddr - physically mapped PS2 address void mmap_MarkCountedRamPage( u32 paddr ) { + pxAssume( eeMem ); + paddr &= ~0xfff; uptr ptr = (uptr)PSM( paddr ); @@ -869,6 +884,8 @@ void mmap_MarkCountedRamPage( u32 paddr ) // from code residing in this page will use manual protection. static __fi void mmap_ClearCpuBlock( uint offset ) { + pxAssume( eeMem ); + int rampage = offset >> 12; // Assertion: This function should never be run on a block that's already under @@ -883,6 +900,8 @@ static __fi void mmap_ClearCpuBlock( uint offset ) void mmap_PageFaultHandler::OnPageFaultEvent( const PageFaultInfo& info, bool& handled ) { + pxAssume( eeMem ); + // get bad virtual address uptr offset = info.addr - (uptr)eeMem->Main; if( offset >= Ps2MemSize::MainRam ) return; @@ -899,5 +918,5 @@ void mmap_ResetBlockTracking() { //DbgCon.WriteLn( "vtlb/mmap: Block Tracking reset..." ); memzero( m_PageProtectInfo ); - HostSys::MemProtect( eeMem->Main, Ps2MemSize::MainRam, PageAccess_ReadWrite() ); + if (eeMem) HostSys::MemProtect( eeMem->Main, Ps2MemSize::MainRam, PageAccess_ReadWrite() ); } diff --git a/pcsx2/vtlb.cpp b/pcsx2/vtlb.cpp index a0df4ba944..869db2b3ea 100644 --- a/pcsx2/vtlb.cpp +++ b/pcsx2/vtlb.cpp @@ -256,65 +256,55 @@ _tmpl(void) vtlbUnmappedPWriteLg(u32 addr,const OperandType* data) { vtlb_BusErr static mem8_t __fastcall vtlbDefaultPhyRead8(u32 addr) { - Console.Error("vtlbDefaultPhyRead8: 0x%08X", addr); - pxFailDev("(VTLB) Attempted read from an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted read8 from unmapped physical address @ 0x%08X.", addr)); return 0; } static mem16_t __fastcall vtlbDefaultPhyRead16(u32 addr) { - Console.Error("vtlbDefaultPhyRead16: 0x%08X", addr); - pxFailDev("(VTLB) Attempted read from an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted read16 from unmapped physical address @ 0x%08X.", addr)); return 0; } static mem32_t __fastcall vtlbDefaultPhyRead32(u32 addr) { - Console.Error("vtlbDefaultPhyRead32: 0x%08X", addr); - pxFailDev("(VTLB) Attempted read from an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted read32 from unmapped physical address @ 0x%08X.", addr)); return 0; } static void __fastcall vtlbDefaultPhyRead64(u32 addr, mem64_t* dest) { - Console.Error("vtlbDefaultPhyRead64: 0x%08X", addr); - pxFailDev("(VTLB) Attempted read from an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted read64 from unmapped physical address @ 0x%08X.", addr)); } static void __fastcall vtlbDefaultPhyRead128(u32 addr, mem128_t* dest) { - Console.Error("vtlbDefaultPhyRead128: 0x%08X", addr); - pxFailDev("(VTLB) Attempted read from an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted read128 from unmapped physical address @ 0x%08X.", addr)); } static void __fastcall vtlbDefaultPhyWrite8(u32 addr, mem8_t data) { - Console.Error("vtlbDefaultPhyWrite8: 0x%08X",addr); - pxFailDev("(VTLB) Attempted write to an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted write8 to unmapped physical address @ 0x%08X.", addr)); } static void __fastcall vtlbDefaultPhyWrite16(u32 addr, mem16_t data) { - Console.Error("vtlbDefaultPhyWrite16: 0x%08X",addr); - pxFailDev("(VTLB) Attempted write to an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted write16 to unmapped physical address @ 0x%08X.", addr)); } static void __fastcall vtlbDefaultPhyWrite32(u32 addr, mem32_t data) { - Console.Error("vtlbDefaultPhyWrite32: 0x%08X",addr); - pxFailDev("(VTLB) Attempted write to an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted write32 to unmapped physical address @ 0x%08X.", addr)); } static void __fastcall vtlbDefaultPhyWrite64(u32 addr,const mem64_t* data) { - Console.Error("vtlbDefaultPhyWrite64: 0x%08X",addr); - pxFailDev("(VTLB) Attempted write to an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted write64 to unmapped physical address @ 0x%08X.", addr)); } static void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data) { - Console.Error("vtlbDefaultPhyWrite128: 0x%08X",addr); - pxFailDev("(VTLB) Attempted write to an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted write128 to unmapped physical address @ 0x%08X.", addr)); } #undef _tmpl @@ -334,6 +324,8 @@ __ri void vtlb_ReassignHandler( vtlbHandler rv, vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128, vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128 ) { + pxAssume(rv < VTLB_HANDLER_ITEMS); + vtlbdata.RWFT[0][0][rv] = (void*)((r8!=0) ? r8 : vtlbDefaultPhyRead8); vtlbdata.RWFT[1][0][rv] = (void*)((r16!=0) ? r16 : vtlbDefaultPhyRead16); vtlbdata.RWFT[2][0][rv] = (void*)((r32!=0) ? r32 : vtlbDefaultPhyRead32); @@ -349,7 +341,7 @@ __ri void vtlb_ReassignHandler( vtlbHandler rv, vtlbHandler vtlb_NewHandler() { - pxAssertDev( vtlbHandlerCount < 127, "VTLB allowed handler count exceeded!" ); + pxAssertDev( vtlbHandlerCount < VTLB_HANDLER_ITEMS, "VTLB handler count overflow!" ); return vtlbHandlerCount++; } @@ -363,7 +355,7 @@ vtlbHandler vtlb_NewHandler() // Returns a handle for the newly created handler See vtlb_MapHandler for use of the return value. // __ri vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128, - vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128) + vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128) { vtlbHandler rv = vtlb_NewHandler(); vtlb_ReassignHandler( rv, r8, r16, r32, r64, r128, w8, w16, w32, w64, w128 ); @@ -396,15 +388,14 @@ void vtlb_MapHandler(vtlbHandler handler, u32 start, u32 size) void vtlb_MapBlock(void* base, u32 start, u32 size, u32 blocksize) { - s32 baseint = (s32)base; - verify(0==(start&VTLB_PAGE_MASK)); verify(0==(size&VTLB_PAGE_MASK) && size>0); - if (blocksize==0) - blocksize=size; + if (!blocksize) + blocksize = size; verify(0==(blocksize&VTLB_PAGE_MASK) && blocksize>0); verify(0==(size%blocksize)); + s32 baseint = (s32)base; u32 end = start + (size - VTLB_PAGE_SIZE); pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) ); @@ -452,67 +443,70 @@ __fi void* vtlb_GetPhyPtr(u32 paddr) //virtual mappings //TODO: Add invalid paddr checks -void vtlb_VMap(u32 vaddr,u32 paddr,u32 sz) +void vtlb_VMap(u32 vaddr,u32 paddr,u32 size) { verify(0==(vaddr&VTLB_PAGE_MASK)); verify(0==(paddr&VTLB_PAGE_MASK)); - verify(0==(sz&VTLB_PAGE_MASK) && sz>0); + verify(0==(size&VTLB_PAGE_MASK) && size>0); - while(sz>0) + while (size > 0) { s32 pme; - if (paddr>=VTLB_PMAP_SZ) + if (paddr >= VTLB_PMAP_SZ) { - pme=UnmappedPhyHandler0; - if (paddr&0x80000000) - pme=UnmappedPhyHandler1; - pme|=0x80000000; - pme|=paddr;// top bit is set anyway ... + pme = UnmappedPhyHandler0; + if (paddr & 0x80000000) + pme = UnmappedPhyHandler1; + pme |= 0x80000000; + pme |= paddr;// top bit is set anyway ... } else { - pme=vtlbdata.pmap[paddr>>VTLB_PAGE_BITS]; + pme = vtlbdata.pmap[paddr>>VTLB_PAGE_BITS]; if (pme<0) - pme|=paddr;// top bit is set anyway ... + pme |= paddr;// top bit is set anyway ... } - vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=pme-vaddr; - vaddr+=VTLB_PAGE_SIZE; - paddr+=VTLB_PAGE_SIZE; - sz-=VTLB_PAGE_SIZE; + vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS] = pme-vaddr; + vaddr += VTLB_PAGE_SIZE; + paddr += VTLB_PAGE_SIZE; + size -= VTLB_PAGE_SIZE; } } -void vtlb_VMapBuffer(u32 vaddr,void* buffer,u32 sz) +void vtlb_VMapBuffer(u32 vaddr,void* buffer,u32 size) { verify(0==(vaddr&VTLB_PAGE_MASK)); - verify(0==(sz&VTLB_PAGE_MASK) && sz>0); - u32 bu8=(u32)buffer; - while(sz>0) + verify(0==(size&VTLB_PAGE_MASK) && size>0); + + u32 bu8 = (u32)buffer; + while (size > 0) { - vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=bu8-vaddr; - vaddr+=VTLB_PAGE_SIZE; - bu8+=VTLB_PAGE_SIZE; - sz-=VTLB_PAGE_SIZE; + vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS] = bu8-vaddr; + vaddr += VTLB_PAGE_SIZE; + bu8 += VTLB_PAGE_SIZE; + size -= VTLB_PAGE_SIZE; } } -void vtlb_VMapUnmap(u32 vaddr,u32 sz) +void vtlb_VMapUnmap(u32 vaddr,u32 size) { verify(0==(vaddr&VTLB_PAGE_MASK)); - verify(0==(sz&VTLB_PAGE_MASK) && sz>0); + verify(0==(size&VTLB_PAGE_MASK) && size>0); - while(sz>0) + while (size > 0) { - u32 handl=UnmappedVirtHandler0; - if (vaddr&0x80000000) + u32 handl = UnmappedVirtHandler0; + if (vaddr & 0x80000000) { - handl=UnmappedVirtHandler1; + handl = UnmappedVirtHandler1; } - handl|=vaddr; // top bit is set anyway ... - handl|=0x80000000; - vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=handl-vaddr; - vaddr+=VTLB_PAGE_SIZE; - sz-=VTLB_PAGE_SIZE; + + handl |= vaddr; // top bit is set anyway ... + handl |= 0x80000000; + + vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS] = handl-vaddr; + vaddr += VTLB_PAGE_SIZE; + size -= VTLB_PAGE_SIZE; } } @@ -589,6 +583,14 @@ void vtlb_Core_Free() safe_aligned_free( vtlbdata.vmap ); } +static wxString GetHostVmErrorMsg() +{ + return pxE(".Error:HostVmReserve", + L"Your system is too low on virtual resources for PCSX2 to run. This can be " + L"caused by having a small or disabled swapfile, or by other programs that are " + L"hogging resources." + ); +} // -------------------------------------------------------------------------------------- // VtlbMemoryReserve (implementations) // -------------------------------------------------------------------------------------- @@ -605,16 +607,23 @@ void VtlbMemoryReserve::SetBaseAddr( uptr newaddr ) void VtlbMemoryReserve::Reserve( sptr hostptr ) { - m_reserve.ReserveAt( hostptr ); - if (!m_reserve.IsOk()) - throw Exception::OutOfMemory( m_reserve.GetName() ); + if (!m_reserve.ReserveAt( hostptr )) + { + throw Exception::OutOfMemory( m_reserve.GetName() ) + .SetDiagMsg(L"Vtlb memory could not be reserved.") + .SetUserMsg(GetHostVmErrorMsg()); + } } void VtlbMemoryReserve::Commit() { if (IsCommitted()) return; if (!m_reserve.Commit()) - throw Exception::OutOfMemory( m_reserve.GetName() ); + { + throw Exception::OutOfMemory( m_reserve.GetName() ) + .SetDiagMsg(L"Vtlb memory could not be committed.") + .SetUserMsg(GetHostVmErrorMsg()); + } } void VtlbMemoryReserve::Reset() diff --git a/pcsx2/vtlb.h b/pcsx2/vtlb.h index d840643c18..891b3c5323 100644 --- a/pcsx2/vtlb.h +++ b/pcsx2/vtlb.h @@ -128,8 +128,10 @@ public: } void Reserve(); - void Release(); + void Commit(); + void Decommit(); void Reset(); + void Release(); }; // -------------------------------------------------------------------------------------- @@ -147,9 +149,10 @@ public: } void Reserve(); + void Commit(); + void Decommit(); void Release(); void Reset(); - void Decommit(); }; // -------------------------------------------------------------------------------------- @@ -182,12 +185,14 @@ namespace vtlb_private static const uint VTLB_PMAP_ITEMS = VTLB_PMAP_SZ / VTLB_PAGE_SIZE; static const uint VTLB_VMAP_ITEMS = _4gb / VTLB_PAGE_SIZE; + static const uint VTLB_HANDLER_ITEMS = 128; + struct MapData { // first indexer -- 8/16/32/64/128 bit tables [values 0-4] // second indexer -- read/write [0 or 1] // third indexer -- 128 possible handlers! - void* RWFT[5][2][128]; + void* RWFT[5][2][VTLB_HANDLER_ITEMS]; s32 pmap[VTLB_PMAP_ITEMS]; //512KB diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index ea7c0aee53..874b452765 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -583,8 +583,9 @@ static void recThrowHardwareDeficiency( const wxChar* extFail ) wxString GetMsg_RecVmFailed() { return pxE( ".Error:Recompiler:VirtualMemoryAlloc", - L"This recompiler was unable to reserve contiguous memory required " - L"for internal caches. This problem may be fixable by reducing the default " + L"This recompiler was unable to reserve contiguous memory required for internal caches. " + L"This error can be caused by low virtual memory resources, such as a small or disabled swapfile, " + L"or by another program that is hogging a lot of memory. You can also try reducing the default " L"cache sizes for all PCSX2 recompilers, found under Host Settings." ); } From 2ca8278c65a099a4e0b0ffbfbbd26fa3f9a38dc4 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Tue, 16 Nov 2010 05:32:31 +0000 Subject: [PATCH 19/22] newHostVM: Some Linux compilation fixes, warning removals. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@4023 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/src/Utilities/Linux/LnxHostSys.cpp | 4 +- pcsx2/CDVD/IsoFileFormats.cpp | 1 - pcsx2/Memory.cpp | 1 - pcsx2/PluginManager.cpp | 2 +- pcsx2/gui/AppAssert.cpp | 160 +++++++++++----------- pcsx2/vtlb.cpp | 2 +- 6 files changed, 84 insertions(+), 86 deletions(-) diff --git a/common/src/Utilities/Linux/LnxHostSys.cpp b/common/src/Utilities/Linux/LnxHostSys.cpp index cdcecb3161..dd94cbe5c0 100644 --- a/common/src/Utilities/Linux/LnxHostSys.cpp +++ b/common/src/Utilities/Linux/LnxHostSys.cpp @@ -17,6 +17,8 @@ #include "../PrecompiledHeader.h" #include "PageFaultSource.h" +#include + #include #include #include @@ -169,7 +171,7 @@ void HostSys::MmapResetPtr(void* base, size_t size) pxAssertRel ((uptr)result != (uptr)base, pxsFmt( "Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped. " - "This is likely caused by multi-thread memory contention.", base, base+size + "This is likely caused by multi-thread memory contention.", base, (uptr)base+size )); } diff --git a/pcsx2/CDVD/IsoFileFormats.cpp b/pcsx2/CDVD/IsoFileFormats.cpp index 540cf2f55a..a389123b27 100644 --- a/pcsx2/CDVD/IsoFileFormats.cpp +++ b/pcsx2/CDVD/IsoFileFormats.cpp @@ -78,7 +78,6 @@ bool isoFile::tryIsoType(u32 _size, s32 _offset, s32 _blockofs) bool isoFile::Detect( bool readType ) { char buf[32]; - int len = m_filename.Length(); m_type = ISOTYPE_ILLEGAL; diff --git a/pcsx2/Memory.cpp b/pcsx2/Memory.cpp index 547839bff5..beee3cdc40 100644 --- a/pcsx2/Memory.cpp +++ b/pcsx2/Memory.cpp @@ -92,7 +92,6 @@ static vtlbHandler null_handler, tlb_fallback_0, - tlb_fallback_1, tlb_fallback_2, tlb_fallback_3, tlb_fallback_4, diff --git a/pcsx2/PluginManager.cpp b/pcsx2/PluginManager.cpp index da172756a8..847cbada0d 100644 --- a/pcsx2/PluginManager.cpp +++ b/pcsx2/PluginManager.cpp @@ -1278,7 +1278,7 @@ void SysCorePlugins::Init( PluginsEnum_t pid ) if( !m_info[pid] || m_info[pid]->IsInitialized ) return; Console.Indent().WriteLn( "Init %s", tbl_PluginInfo[pid].shortname ); - if( NULL != m_info[pid]->CommonBindings.Init() ) + if( 0 != m_info[pid]->CommonBindings.Init() ) throw Exception::PluginInitError( pid ); m_info[pid]->IsInitialized = true; diff --git a/pcsx2/gui/AppAssert.cpp b/pcsx2/gui/AppAssert.cpp index f1f176b75d..c6b754b92e 100644 --- a/pcsx2/gui/AppAssert.cpp +++ b/pcsx2/gui/AppAssert.cpp @@ -19,89 +19,87 @@ #include +class StackDump : public wxStackWalker +{ +protected: + wxString m_stackTrace; + wxString m_srcFuncName; + bool m_ignoreDone; + int m_skipped; + +public: + StackDump( const FnChar_t* src_function_name ) + { + if( src_function_name != NULL ) + m_srcFuncName = fromUTF8(src_function_name); + + m_ignoreDone = false; + m_skipped = 0; + } + + const wxString& GetStackTrace() const { return m_stackTrace; } + +protected: + virtual void OnStackFrame(const wxStackFrame& frame) + { + wxString name( frame.GetName() ); + if( name.IsEmpty() ) + { + name = wxsFormat( L"%p ", frame.GetAddress() ); + } + /*else if( m_srcFuncName.IsEmpty() || m_srcFuncName == name ) + { + // FIXME: This logic isn't reliable yet. + // It's possible for our debug information to not match the function names returned by + // __pxFUNCTION__ (might happen in linux a lot, and could happen in win32 due to + // inlining on Dev aserts). The better approach is a system the queues up all the + // stacktrace info in individual wxStrings, and does a two-pass check -- first pass + // for the function name and, if not found, a second pass that just skips the first + // few stack entries. + + // It's important we only walk the stack once because Linux (argh, always linux!) has + // a really god aweful slow stack walker. + + // I'm not doing it right now because I've worked on this mess enough for one week. --air + + m_ignoreDone = true; + } + + if( !m_ignoreDone ) + { + m_skipped++; + return; + }*/ + + //wxString briefName; + wxString essenName; + + if( frame.HasSourceLocation() ) + { + wxFileName wxfn(frame.GetFileName()); + //briefName.Printf( L"(%s:%d)", wxfn.GetFullName().c_str(), frame.GetLine() ); + + wxfn.SetVolume( wxEmptyString ); + //int count = wxfn.GetDirCount(); + for( int i=0; i<2; ++i ) + wxfn.RemoveDir(0); + + essenName.Printf( L"%s:%d", wxfn.GetFullPath().c_str(), frame.GetLine() ); + } + + m_stackTrace += pxsFmt( L"[%02d] %-44s %s\n", + frame.GetLevel()-m_skipped, + name.c_str(), + essenName.c_str() + ); + } +}; + static wxString pxGetStackTrace( const FnChar_t* calledFrom ) { - wxString stackTrace; - - class StackDump : public wxStackWalker - { - protected: - wxString m_stackTrace; - wxString m_srcFuncName; - bool m_ignoreDone; - int m_skipped; - - public: - StackDump( const FnChar_t* src_function_name ) - { - if( src_function_name != NULL ) - m_srcFuncName = fromUTF8(src_function_name); - - m_ignoreDone = false; - m_skipped = 0; - } - - const wxString& GetStackTrace() const { return m_stackTrace; } - - protected: - virtual void OnStackFrame(const wxStackFrame& frame) - { - wxString name( frame.GetName() ); - if( name.IsEmpty() ) - { - name = wxsFormat( L"%p ", frame.GetAddress() ); - } - /*else if( m_srcFuncName.IsEmpty() || m_srcFuncName == name ) - { - // FIXME: This logic isn't reliable yet. - // It's possible for our debug information to not match the function names returned by - // __pxFUNCTION__ (might happen in linux a lot, and could happen in win32 due to - // inlining on Dev aserts). The better approach is a system the queues up all the - // stacktrace info in individual wxStrings, and does a two-pass check -- first pass - // for the function name and, if not found, a second pass that just skips the first - // few stack entries. - - // It's important we only walk the stack once because Linux (argh, always linux!) has - // a really god aweful slow stack walker. - - // I'm not doing it right now because I've worked on this mess enough for one week. --air - - m_ignoreDone = true; - } - - if( !m_ignoreDone ) - { - m_skipped++; - return; - }*/ - - //wxString briefName; - wxString essenName; - - if( frame.HasSourceLocation() ) - { - wxFileName wxfn(frame.GetFileName()); - //briefName.Printf( L"(%s:%d)", wxfn.GetFullName().c_str(), frame.GetLine() ); - - wxfn.SetVolume( wxEmptyString ); - int count = wxfn.GetDirCount(); - for( int i=0; i<2; ++i ) - wxfn.RemoveDir(0); - - essenName.Printf( L"%s:%d", wxfn.GetFullPath().c_str(), frame.GetLine() ); - } - - m_stackTrace += wxString::Format( L"[%02d] %-44s %s\n", - frame.GetLevel()-m_skipped, - name.c_str(), - essenName.c_str() - ); - } - }; - - StackDump dump( calledFrom ); - dump.Walk( 3 ); - return dump.GetStackTrace(); + StackDump dump( calledFrom ); + dump.Walk( 3 ); + return dump.GetStackTrace(); } #ifdef __WXDEBUG__ diff --git a/pcsx2/vtlb.cpp b/pcsx2/vtlb.cpp index 869db2b3ea..a7d9c35b85 100644 --- a/pcsx2/vtlb.cpp +++ b/pcsx2/vtlb.cpp @@ -35,7 +35,7 @@ #include "COP0.h" #include "R5900Exceptions.h" -#include "Utilities\MemsetFast.inl" +#include "Utilities/MemsetFast.inl" using namespace R5900; using namespace vtlb_private; From 63b254c8bd5d68f720f1246a2e015eb3db4ffac5 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Tue, 16 Nov 2010 15:58:42 +0000 Subject: [PATCH 20/22] newHostVM: * Applied the new RecompiledCodeReserve to the VIF recompilers (saves another 4-8mb of memory, depending on game). * Fixed a bug in pxsFmt / FastFormatUnicode (string formatting). * Final round of error handling cleanups. (branch is basically ready for re-integration -- needs some testin for obvious/show stopping bugs, thanks!) git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@4025 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/include/Utilities/PageFaultSource.h | 10 +-- common/src/Utilities/FastFormatString.cpp | 4 +- common/src/Utilities/VirtualMemory.cpp | 35 ++++++--- pcsx2/CMakeLists.txt | 1 - pcsx2/Linux/pcsx2.cbp | 1 - pcsx2/System.cpp | 55 ++++++++++---- pcsx2/System.h | 9 ++- pcsx2/System/RecTypes.h | 4 +- pcsx2/gui/AppAssert.cpp | 37 ++++------ pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 4 - pcsx2/x86/iR3000A.cpp | 9 +-- pcsx2/x86/ix86-32/iR5900-32.cpp | 19 +---- pcsx2/x86/microVU.cpp | 3 +- pcsx2/x86/newVif.h | 33 +++++---- pcsx2/x86/newVif_BlockBuffer.h | 86 ---------------------- pcsx2/x86/newVif_Dynarec.cpp | 44 +++++------ pcsx2/x86/newVif_Unpack.cpp | 17 +++++ 17 files changed, 161 insertions(+), 210 deletions(-) delete mode 100644 pcsx2/x86/newVif_BlockBuffer.h diff --git a/common/include/Utilities/PageFaultSource.h b/common/include/Utilities/PageFaultSource.h index 07ea665d06..41fd4c0924 100644 --- a/common/include/Utilities/PageFaultSource.h +++ b/common/include/Utilities/PageFaultSource.h @@ -127,10 +127,9 @@ class VirtualMemoryReserve { DeclareNoncopyableObject( VirtualMemoryReserve ); -public: - wxString Name; - protected: + wxString m_name; + // Default size of the reserve, in bytes. Can be specified when the object is contructed. // Is used as the reserve size when Reserve() is called, unless an override is specified // in the Reserve parameters. @@ -149,7 +148,7 @@ protected: uptr m_pages_commited; public: - VirtualMemoryReserve( const wxString& name, size_t size = 0 ); + VirtualMemoryReserve( const wxString& name=wxEmptyString, size_t size = 0 ); virtual ~VirtualMemoryReserve() throw() { Release(); @@ -167,7 +166,7 @@ public: virtual bool Commit(); bool IsOk() const { return m_baseptr != NULL; } - wxString GetName() const { return Name; } + wxString GetName() const { return m_name; } uptr GetReserveSizeInBytes() const { return m_pages_reserved * __pagesize; } uptr GetReserveSizeInPages() const { return m_pages_reserved; } @@ -179,6 +178,7 @@ public: u8* GetPtrEnd() { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); } const u8* GetPtrEnd() const { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); } + VirtualMemoryReserve& SetName( const wxString& newname ); VirtualMemoryReserve& SetBaseAddr( uptr newaddr ); VirtualMemoryReserve& SetPageAccessOnCommit( const PageProtectionMode& mode ); diff --git a/common/src/Utilities/FastFormatString.cpp b/common/src/Utilities/FastFormatString.cpp index 175a8ae27c..b08e14bdbd 100644 --- a/common/src/Utilities/FastFormatString.cpp +++ b/common/src/Utilities/FastFormatString.cpp @@ -174,7 +174,7 @@ static __ri void format_that_ascii_mess( CharBufferType& buffer, uint writepos, len += writepos; if (len < size) break; - buffer.Alloc( len + 128 ); + buffer.Resize( len + 128 ); }; // performing an assertion or log of a truncated string is unsafe, so let's not; even @@ -205,7 +205,7 @@ static __ri uint format_that_unicode_mess( CharBufferType& buffer, uint writepos len += writepos; if (len < size) return len; - buffer.Alloc( (len + 128) * sizeof(wxChar) ); + buffer.Resize( (len + 128) * sizeof(wxChar) ); }; // performing an assertion or log of a truncated string is unsafe, so let's not; even diff --git a/common/src/Utilities/VirtualMemory.cpp b/common/src/Utilities/VirtualMemory.cpp index 1812ade3a7..69369ec3e9 100644 --- a/common/src/Utilities/VirtualMemory.cpp +++ b/common/src/Utilities/VirtualMemory.cpp @@ -71,7 +71,7 @@ void SrcType_PageFault::_DispatchRaw( ListenerIterator iter, const ListenerItera // VirtualMemoryReserve (implementations) // -------------------------------------------------------------------------------------- VirtualMemoryReserve::VirtualMemoryReserve( const wxString& name, size_t size ) - : Name( name ) + : m_name( name ) { m_defsize = size; @@ -81,6 +81,12 @@ VirtualMemoryReserve::VirtualMemoryReserve( const wxString& name, size_t size ) m_prot_mode = PageAccess_None(); } +VirtualMemoryReserve& VirtualMemoryReserve::SetName( const wxString& newname ) +{ + m_name = newname; + return *this; +} + VirtualMemoryReserve& VirtualMemoryReserve::SetBaseAddr( uptr newaddr ) { if (!pxAssertDev(!m_pages_reserved, "Invalid object state: you must release the virtual memory reserve prior to changing its base address!")) return *this; @@ -124,7 +130,7 @@ void* VirtualMemoryReserve::Reserve( size_t size, uptr base, uptr 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 ); + m_name.c_str(), base, base + size ); SafeSysMunmap(m_baseptr, reserved_bytes); @@ -143,9 +149,16 @@ void* VirtualMemoryReserve::Reserve( size_t size, uptr base, uptr upper_bounds ) } 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); + + FastFormatUnicode mbkb; + uint mbytes = reserved_bytes / _1mb; + if (mbytes) + mbkb.Write( "[%umb]", mbytes ); + else + mbkb.Write( "[%ukb]", reserved_bytes / 1024 ); + + DevCon.WriteLn( Color_Gray, L"%-32s @ 0x%08p -> 0x%08p %s", m_name.c_str(), + m_baseptr, (uptr)m_baseptr+reserved_bytes, mbkb.c_str()); return m_baseptr; } @@ -193,17 +206,17 @@ bool VirtualMemoryReserve::TryResize( uint newsize ) uint toReservePages = newPages - m_pages_reserved; uint toReserveBytes = toReservePages * __pagesize; - DevCon.WriteLn( L"%-32s is being expanded by %u pages.", Name.c_str(), toReservePages); + DevCon.WriteLn( L"%-32s is being expanded by %u pages.", m_name.c_str(), toReservePages); m_baseptr = (void*)HostSys::MmapReserve((uptr)GetPtrEnd(), toReserveBytes); if (!m_baseptr) { Console.Warning("%-32s could not be passively resized due to virtual memory conflict!"); - Console.Indent().Warning("(attempted to map memory @ 0x%08X -> 0x%08X", m_baseptr, (uptr)m_baseptr+toReserveBytes); + Console.Indent().Warning("(attempted to map memory @ 0x%08p -> 0x%08p", m_baseptr, (uptr)m_baseptr+toReserveBytes); } - DevCon.WriteLn( Color_Blue, L"%-32s @ 0x%08X -> 0x%08X [%umb]", Name.c_str(), + DevCon.WriteLn( Color_Gray, L"%-32s @ 0x%08p -> 0x%08p [%umb]", m_name.c_str(), m_baseptr, (uptr)m_baseptr+toReserveBytes, toReserveBytes / _1mb); } else if (newPages < m_pages_reserved) @@ -213,11 +226,11 @@ bool VirtualMemoryReserve::TryResize( uint newsize ) uint toRemovePages = m_pages_reserved - newPages; uint toRemoveBytes = toRemovePages * __pagesize; - DevCon.WriteLn( L"%-32s is being shrunk by %u pages.", Name.c_str(), toRemovePages); + DevCon.WriteLn( L"%-32s is being shrunk by %u pages.", m_name.c_str(), toRemovePages); HostSys::MmapResetPtr(GetPtrEnd(), toRemoveBytes); - DevCon.WriteLn( Color_Blue, L"%-32s @ 0x%08X -> 0x%08X [%umb]", Name.c_str(), + DevCon.WriteLn( Color_Gray, L"%-32s @ 0x%08p -> 0x%08p [%umb]", m_name.c_str(), m_baseptr, (uptr)m_baseptr+toRemoveBytes, toRemoveBytes / _1mb); } @@ -244,7 +257,7 @@ void BaseVmReserveListener::CommitBlocks( uptr page, uint blocks ) // physical ram or virtual memory. if (!HostSys::MmapCommitPtr(blockptr, blocksbytes, m_prot_mode)) { - throw Exception::OutOfMemory(Name) + throw Exception::OutOfMemory(m_name) .SetDiagMsg(pxsFmt("An additional %u blocks @ 0x%08x were requested, but could not be committed!", blocks, blockptr)); } diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index 82957bf97c..cdbbc3342a 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -541,7 +541,6 @@ set(pcsx2x86Headers x86/microVU_Tables.inl x86/microVU_Upper.inl x86/newVif.h - x86/newVif_BlockBuffer.h x86/newVif_HashBucket.h x86/newVif_UnpackSSE.h x86/sVU_Compare.h diff --git a/pcsx2/Linux/pcsx2.cbp b/pcsx2/Linux/pcsx2.cbp index d3855a71c4..8722a0c032 100644 --- a/pcsx2/Linux/pcsx2.cbp +++ b/pcsx2/Linux/pcsx2.cbp @@ -646,7 +646,6 @@ - diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index 400fb27738..eb3dd07a3a 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -17,6 +17,7 @@ #include "Common.h" #include "IopCommon.h" #include "VUmicro.h" +#include "newVif.h" #include "SamplProf.h" @@ -30,9 +31,6 @@ #include "Utilities/MemsetFast.inl" -extern void closeNewVif(int idx); -extern void resetNewVif(int idx); - // -------------------------------------------------------------------------------------- // RecompiledCodeReserve (implementations) // -------------------------------------------------------------------------------------- @@ -108,6 +106,23 @@ void RecompiledCodeReserve::OnCommittedBlock( void* block ) } } +// This error message is shared by R5900, R3000, and microVU recompilers. It is not used by the +// SuperVU recompiler, since it has its own customized message. +void RecompiledCodeReserve::ThrowIfNotOk() const +{ + if (IsOk()) return; + + throw Exception::OutOfMemory(m_name) + .SetDiagMsg(pxsFmt( L"Recompiled code cache could not be mapped." )) + .SetUserMsg( pxE( ".Error:Recompiler:VirtualMemoryAlloc", + L"This recompiler was unable to reserve contiguous memory required for internal caches. " + L"This error can be caused by low virtual memory resources, such as a small or disabled swapfile, " + L"or by another program that is hogging a lot of memory. You can also try reducing the default " + L"cache sizes for all PCSX2 recompilers, found under Host Settings." + )); +} + + void SysOutOfMemory_EmergencyResponse(uptr blocksize) { // An out of memory error occurred. All we can try to do in response is reset the various @@ -346,11 +361,15 @@ void SysMainMemory::ReserveAll() { pxInstallSignalHandler(); - DevCon.WriteLn( "PS2vm: Mapping host memory for all virtual systems..." ); + DevCon.WriteLn( Color_StrongBlue, "Mapping host memory for virtual systems..." ); + ConsoleIndentScope indent(1); m_ee.Reserve(); m_iop.Reserve(); m_vu.Reserve(); + + reserveNewVif(0); + reserveNewVif(1); } void SysMainMemory::CommitAll() @@ -358,7 +377,8 @@ void SysMainMemory::CommitAll() vtlb_Core_Alloc(); if (m_ee.IsCommitted() && m_iop.IsCommitted() && m_vu.IsCommitted()) return; - DevCon.WriteLn( "PS2vm: Allocating host memory for all virtual systems..." ); + DevCon.WriteLn( Color_StrongBlue, "Allocating host memory for virtual systems..." ); + ConsoleIndentScope indent(1); m_ee.Commit(); m_iop.Commit(); @@ -370,23 +390,30 @@ void SysMainMemory::ResetAll() { CommitAll(); - DevCon.WriteLn( "PS2vm: Resetting host memory for all virtual systems..." ); + DevCon.WriteLn( Color_StrongBlue, "Resetting host memory for virtual systems..." ); + ConsoleIndentScope indent(1); m_ee.Reset(); m_iop.Reset(); m_vu.Reset(); + + // Note: newVif is reset as part of other VIF structures. } void SysMainMemory::DecommitAll() { if (!m_ee.IsCommitted() && !m_iop.IsCommitted() && !m_vu.IsCommitted()) return; - Console.WriteLn( "PS2vm: Decommitting host memory for all virtual systems..." ); + Console.WriteLn( Color_Blue, "Decommitting host memory for virtual systems..." ); + ConsoleIndentScope indent(1); m_ee.Decommit(); m_iop.Decommit(); m_vu.Decommit(); + closeNewVif(0); + closeNewVif(1); + vtlb_Core_Free(); } @@ -394,10 +421,14 @@ void SysMainMemory::ReleaseAll() { DecommitAll(); - Console.WriteLn( "PS2vm: Releasing host memory maps for all virtual systems..." ); + Console.WriteLn( Color_Blue, "Releasing host memory maps for virtual systems..." ); + ConsoleIndentScope indent(1); vtlb_Core_Free(); // Just to be sure... (calling order could result in it getting missed during Decommit). + releaseNewVif(0); + releaseNewVif(1); + m_ee.Decommit(); m_iop.Decommit(); m_vu.Decommit(); @@ -411,7 +442,8 @@ void SysMainMemory::ReleaseAll() // -------------------------------------------------------------------------------------- SysCpuProviderPack::SysCpuProviderPack() { - Console.WriteLn( "Reserving memory for recompilers..." ); + Console.WriteLn( Color_StrongBlue, "Reserving memory for recompilers..." ); + ConsoleIndentScope indent(1); CpuProviders = new CpuInitializerSet(); @@ -453,9 +485,6 @@ void SysCpuProviderPack::CleanupMess() throw() { try { - closeNewVif(0); - closeNewVif(1); - psxRec.Shutdown(); recCpu.Shutdown(); } @@ -574,5 +603,5 @@ wxString SysGetDiscID() // region and revision). } - return wxsFormat( L"%8.8x", ElfCRC ); + return pxsFmt( L"%08x", ElfCRC ); } diff --git a/pcsx2/System.h b/pcsx2/System.h index dd34f0f117..43159f08d3 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -61,11 +61,18 @@ namespace HostMemoryMap // IOP recompiler code cache area (16 or 32mb) static const uptr IOPrec = 0x34000000; + // newVif0 recompiler code cache area (16mb) + static const uptr VIF0rec = 0x36000000; + + // newVif1 recompiler code cache area (32mb) + static const uptr VIF1rec = 0x38000000; + // microVU1 recompiler code cache area (32 or 64mb) - static const uptr mVU0rec = 0x38000000; + static const uptr mVU0rec = 0x3C000000; // microVU0 recompiler code cache area (64mb) static const uptr mVU1rec = 0x40000000; + } // -------------------------------------------------------------------------------------- diff --git a/pcsx2/System/RecTypes.h b/pcsx2/System/RecTypes.h index 1fec845da1..2c26e3702c 100644 --- a/pcsx2/System/RecTypes.h +++ b/pcsx2/System/RecTypes.h @@ -37,7 +37,7 @@ protected: bool m_profiler_registered; public: - RecompiledCodeReserve( const wxString& name, uint defCommit = 0 ); + RecompiledCodeReserve( const wxString& name=wxEmptyString, uint defCommit = 0 ); virtual ~RecompiledCodeReserve() throw(); virtual void* Reserve( size_t size, uptr base=0, uptr upper_bounds=0 ); @@ -48,6 +48,8 @@ public: { return SetProfilerName( fromUTF8(shortname) ); } + + void ThrowIfNotOk() const; operator void*() { return m_baseptr; } operator const void*() const { return m_baseptr; } diff --git a/pcsx2/gui/AppAssert.cpp b/pcsx2/gui/AppAssert.cpp index c6b754b92e..d729c1a5b0 100644 --- a/pcsx2/gui/AppAssert.cpp +++ b/pcsx2/gui/AppAssert.cpp @@ -22,10 +22,10 @@ class StackDump : public wxStackWalker { protected: - wxString m_stackTrace; - wxString m_srcFuncName; - bool m_ignoreDone; - int m_skipped; + FastFormatUnicode m_stackTrace; + wxString m_srcFuncName; + bool m_ignoreDone; + int m_skipped; public: StackDump( const FnChar_t* src_function_name ) @@ -37,17 +37,12 @@ public: m_skipped = 0; } - const wxString& GetStackTrace() const { return m_stackTrace; } + const wxChar* GetStackTrace() const { return m_stackTrace.c_str(); } protected: virtual void OnStackFrame(const wxStackFrame& frame) { - wxString name( frame.GetName() ); - if( name.IsEmpty() ) - { - name = wxsFormat( L"%p ", frame.GetAddress() ); - } - /*else if( m_srcFuncName.IsEmpty() || m_srcFuncName == name ) + /*if( m_srcFuncName.IsEmpty() || m_srcFuncName == name ) { // FIXME: This logic isn't reliable yet. // It's possible for our debug information to not match the function names returned by @@ -71,27 +66,25 @@ protected: return; }*/ - //wxString briefName; - wxString essenName; + m_stackTrace.Write(pxsFmt( L"[%02d]", frame.GetLevel()-m_skipped)); + + if (!frame.GetName().IsEmpty()) + m_stackTrace.Write(pxsFmt( L" %-44s", frame.GetName().c_str() )); + else + m_stackTrace.Write(pxsFmt( L" 0x%-42p", frame.GetAddress() )); if( frame.HasSourceLocation() ) { wxFileName wxfn(frame.GetFileName()); - //briefName.Printf( L"(%s:%d)", wxfn.GetFullName().c_str(), frame.GetLine() ); wxfn.SetVolume( wxEmptyString ); - //int count = wxfn.GetDirCount(); for( int i=0; i<2; ++i ) wxfn.RemoveDir(0); - essenName.Printf( L"%s:%d", wxfn.GetFullPath().c_str(), frame.GetLine() ); + m_stackTrace.Write( L" %s:%d", wxfn.GetFullPath().c_str(), frame.GetLine() ); } - - m_stackTrace += pxsFmt( L"[%02d] %-44s %s\n", - frame.GetLevel()-m_skipped, - name.c_str(), - essenName.c_str() - ); + + m_stackTrace.Write(L"\n"); } }; diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index f648745cb0..129822dfc8 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -839,10 +839,6 @@ RelativePath="..\..\x86\newVif.h" > - - diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp index 795f671f28..941125e3d8 100644 --- a/pcsx2/x86/iR3000A.cpp +++ b/pcsx2/x86/iR3000A.cpp @@ -757,8 +757,6 @@ static const uint m_recBlockAllocSize = static void recReserveCache() { - extern wxString GetMsg_RecVmFailed(); - if (!recMem) recMem = new RecompiledCodeReserve(L"R3000A Recompiler Cache", _1mb * 2); recMem->SetProfilerName("IOPrec"); @@ -771,12 +769,7 @@ static void recReserveCache() m_ConfiguredCacheReserve /= 2; } - if (!recMem->IsOk()) - { - throw Exception::VirtualMemoryMapConflict(recMem->GetName()) - .SetDiagMsg(pxsFmt( L"Recompiled code cache could not be mapped." )) - .SetUserMsg(GetMsg_RecVmFailed()); - } + recMem->ThrowIfNotOk(); } static void recReserve() diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index 874b452765..2be0fafd9c 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -578,18 +578,6 @@ static void recThrowHardwareDeficiency( const wxChar* extFail ) .SetUserMsg(pxsFmt(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )); } -// This error message is shared by R5900, R3000, and microVU recompilers. It is not used by the -// SuperVU recompiler, since it has its own customized message. -wxString GetMsg_RecVmFailed() -{ - return pxE( ".Error:Recompiler:VirtualMemoryAlloc", - L"This recompiler was unable to reserve contiguous memory required for internal caches. " - L"This error can be caused by low virtual memory resources, such as a small or disabled swapfile, " - L"or by another program that is hogging a lot of memory. You can also try reducing the default " - L"cache sizes for all PCSX2 recompilers, found under Host Settings." - ); -} - static void recReserveCache() { if (!recMem) recMem = new RecompiledCodeReserve(L"R5900-32 Recompiler Cache", _1mb * 4); @@ -604,12 +592,7 @@ static void recReserveCache() m_ConfiguredCacheReserve /= 2; } - if (!recMem->IsOk()) - { - throw Exception::VirtualMemoryMapConflict(recMem->GetName()) - .SetDiagMsg(pxsFmt( L"Recompiled code cache could not be mapped." )) - .SetUserMsg(GetMsg_RecVmFailed()); - } + recMem->ThrowIfNotOk(); } static void recReserve() diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp index b01d1cb904..a1bbaf3872 100644 --- a/pcsx2/x86/microVU.cpp +++ b/pcsx2/x86/microVU.cpp @@ -94,8 +94,7 @@ void microVU::reserveCache() (u8*)cache_reserve->Reserve( cacheSize * _1mb, HostMemoryMap::mVU1rec ) : (u8*)cache_reserve->Reserve( cacheSize * _1mb, HostMemoryMap::mVU0rec ); - if(!cache_reserve->IsOk()) - throw Exception::VirtualMemoryMapConflict().SetDiagMsg(pxsFmt( L"Micro VU%u Recompiler Cache", index )); + cache_reserve->ThrowIfNotOk(); } // Only run this once per VU! ;) diff --git a/pcsx2/x86/newVif.h b/pcsx2/x86/newVif.h index 7f63bb6b91..d61456b395 100644 --- a/pcsx2/x86/newVif.h +++ b/pcsx2/x86/newVif.h @@ -19,6 +19,8 @@ #include "VU.h" #include "x86emitter/x86emitter.h" +#include "RecTypes.h" + using namespace x86Emitter; #define aMax(x, y) std::max(x,y) @@ -28,13 +30,14 @@ using namespace x86Emitter; typedef u32 (__fastcall *nVifCall)(void*, const void*); typedef void (__fastcall *nVifrecCall)(uptr dest, uptr src); -#include "newVif_BlockBuffer.h" #include "newVif_HashBucket.h" extern void mVUmergeRegs(const xRegisterSSE& dest, const xRegisterSSE& src, int xyzw, bool modXYZW = 0); extern void _nVifUnpack (int idx, const u8* data, uint mode, bool isFill); +extern void dVifReserve (int idx); extern void dVifReset (int idx); extern void dVifClose (int idx); +extern void dVifRelease (int idx); extern void VifUnpackSSE_Init(); _vifT extern void dVifUnpack (const u8* data, bool isFill); @@ -76,23 +79,25 @@ struct nVifStruct { u32 bSize; // Size of 'buffer' u32 bPtr; - u32 idx; // VIF0 or VIF1 - u8* recPtr; // Cur Pos to recompile to - u8* recEnd; // 'Safe' End of Rec Cache - BlockBuffer* vifCache; // Block Buffer + uint recReserveSizeMB; // reserve size, in megabytes. + RecompiledCodeReserve* recReserve; + u8* recWritePtr; // current write pos into the reserve + HashBucket<_tParams>* vifBlocks; // Vif Blocks int numBlocks; // # of Blocks Recompiled - - nVifStruct() - { - vifCache = NULL; - vifBlocks = NULL; - numBlocks = 0; - recPtr = NULL; - recEnd = NULL; - } + + // VIF0 or VIF1 - provided for debugging helpfulness only, and is generally unused. + // (templates are used for most or all VIF indexing) + u32 idx; + + nVifStruct(); }; +extern void reserveNewVif(int idx); +extern void closeNewVif(int idx); +extern void resetNewVif(int idx); +extern void releaseNewVif(int idx); + extern __aligned16 nVifStruct nVif[2]; extern __aligned16 nVifCall nVifUpk[(2*2*16)*4]; // ([USN][Masking][Unpack Type]) [curCycle] extern __aligned16 u32 nVifMask[3][4][4]; // [MaskNumber][CycleNumber][Vector] diff --git a/pcsx2/x86/newVif_BlockBuffer.h b/pcsx2/x86/newVif_BlockBuffer.h deleted file mode 100644 index 532c613819..0000000000 --- a/pcsx2/x86/newVif_BlockBuffer.h +++ /dev/null @@ -1,86 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -// Allocates a Chunk of memory using SysMmapEx... -// This memory can be used to write recompiled code to. -// Its got basic resizing/growing ability too, but probably -// won't be too useful since growing the block buffer will -// invalidate any pointers pointing to the old block buffer. -// (so remember to invalidate those block pointers :D) -// It also deallocates itself on 'delete', so you can -// just use 'new' and 'delete' for initialization and -// deletion/cleanup respectfully... -class BlockBuffer { -protected: - u32 mSize; // Cur Size (in bytes) - u32 mSizeT; // Total Size (in bytes) - u32 mGrowBy; // amount to grow by when buffer fills (in bytes) - u8* mData; // Data Ptr (allocated via SysMmap) - - void alloc(int size) { - mData = SysMmapEx(0, size, 0, "nVif_BlockBuffer"); - if (!mData) throw Exception::OutOfMemory(L"nVif recompiled code buffer (nVif_BlockBuffer)"); - clear(); - } - void dealloc(u8* &dPtr, int size) { - SafeSysMunmap( dPtr, size ); - } - -public: - virtual ~BlockBuffer() throw() { - dealloc(mData, mSizeT); - } - - BlockBuffer(u32 tSize, u32 growby=_1mb*2) { - mSizeT = tSize; - mGrowBy = growby; - mSize = 0; - alloc(mSizeT); - } - - void append(void *addr, u32 size) { - if ((mSize + size) > mSizeT) grow(mSizeT + mGrowBy); - memcpy_fast(&mData[mSize], addr, size); - mSize += size; - } - - // Increases the allocation size. Warning: Unlike 'realloc' this function will - // CLEAR all contents of the buffer. This is because copying contents of recompiled - // caches is mostly useless since it invalidates any pointers into the block. - // (code relocation techniques are possible, but are difficult, potentially slow, - // and easily bug prone. Not recommended at this time). --air - void grow(u32 newSize) { - pxAssume( newSize > mSizeT ); - u8* temp = mData; - alloc(newSize); - dealloc(temp, mSizeT); - clear(); - mSizeT = newSize; - } - - // clears the entire buffer to recompiler fill (0xcc), and sets mSize to 0. - // (indicating none of the buffer is allocated). - void clear() { - if( mSize == 0 ) return; // no clears needed if nothing's been written/modified - mSize = 0; - memset(mData, 0xcc, mSizeT); - } - - u32 getCurSize() { return mSize; } - u32 getAllocSize() { return mSizeT; } - u8* getBlock() { return mData; } -}; diff --git a/pcsx2/x86/newVif_Dynarec.cpp b/pcsx2/x86/newVif_Dynarec.cpp index 8325341da5..d5656b2292 100644 --- a/pcsx2/x86/newVif_Dynarec.cpp +++ b/pcsx2/x86/newVif_Dynarec.cpp @@ -22,34 +22,37 @@ static __aligned16 nVifBlock _vBlock = {0}; -void dVifReset(int idx) { - // If the VIF cache is greater than 12mb, then it's due for a complete reset back - // down to a reasonable starting point of 4mb. - if( nVif[idx].vifCache && (nVif[idx].vifCache->getAllocSize() > _1mb*12) ) - safe_delete(nVif[idx].vifCache); +void dVifReserve(int idx) +{ + if (!nVif[idx].recReserve) + nVif[idx].recReserve = new RecompiledCodeReserve(pxsFmt(L"VIF%u Unpack Recompiler Cache", idx)); - if( !nVif[idx].vifCache ) - nVif[idx].vifCache = new BlockBuffer(_1mb*4); - else - nVif[idx].vifCache->clear(); + nVif[idx].recReserve->Reserve( nVif[idx].recReserveSizeMB * _1mb, idx ? HostMemoryMap::VIF1rec : HostMemoryMap::VIF0rec ); +} + +void dVifReset(int idx) { if( !nVif[idx].vifBlocks ) nVif[idx].vifBlocks = new HashBucket<_tParams>(); else nVif[idx].vifBlocks->clear(); - nVif[idx].numBlocks = 0; - - nVif[idx].recPtr = nVif[idx].vifCache->getBlock(); - nVif[idx].recEnd = &nVif[idx].recPtr[nVif[idx].vifCache->getAllocSize()-(_1mb/4)]; // .25mb Safe Zone + nVif[idx].recReserve->Reset(); + nVif[idx].numBlocks = 0; + nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr(); } void dVifClose(int idx) { nVif[idx].numBlocks = 0; - safe_delete(nVif[idx].vifCache); + nVif[idx].recReserve->Reset(); + safe_delete(nVif[idx].vifBlocks); } +void dVifRelease(int idx) { + safe_delete(nVif[idx].recReserve); +} + VifUnpackSSE_Dynarec::VifUnpackSSE_Dynarec(const nVifStruct& vif_, const nVifBlock& vifBlock_) : v(vif_) , vB(vifBlock_) @@ -223,11 +226,10 @@ _vifT static __fi u8* dVifsetVUptr(uint cl, uint wl, bool isFill) { // [TODO] : Finish implementing support for VIF's growable recBlocks buffer. Currently // it clears the buffer only. static __fi void dVifRecLimit(int idx) { - if (nVif[idx].recPtr > nVif[idx].recEnd) { - DevCon.WriteLn("nVif Rec - Out of Rec Cache! [%x > %x]", nVif[idx].recPtr, nVif[idx].recEnd); - nVif[idx].vifBlocks->clear(); - nVif[idx].recPtr = nVif[idx].vifCache->getBlock(); - nVif[idx].recEnd = &nVif[idx].recPtr[nVif[idx].vifCache->getAllocSize()-(_1mb/4)]; // .25mb Safe Zone + if (nVif[idx].recWritePtr > (nVif[idx].recReserve->GetPtrEnd() - _256kb)) { + DevCon.WriteLn("nVif Recompiler Cache Reset! [0x%08x > 0x%08x]", nVif[idx].recWritePtr, nVif[idx].recReserve->GetPtrEnd()); + nVif[idx].recReserve->Reset(); + nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr(); } } @@ -277,11 +279,11 @@ _vifT __fi void dVifUnpack(const u8* data, bool isFill) { if (dVifExecuteUnpack(data, isFill)) return; - xSetPtr(v.recPtr); + xSetPtr(v.recWritePtr); _vBlock.startPtr = (uptr)xGetAlignedCallTarget(); v.vifBlocks->add(_vBlock); VifUnpackSSE_Dynarec( v, _vBlock ).CompileRoutine(); - nVif[idx].recPtr = xGetPtr(); + nVif[idx].recWritePtr = xGetPtr(); // [TODO] : Ideally we should test recompile buffer limits prior to each instruction, // which would be safer and more memory efficient than using an 0.25 meg recEnd marker. diff --git a/pcsx2/x86/newVif_Unpack.cpp b/pcsx2/x86/newVif_Unpack.cpp index 0c692292c9..02808d152f 100644 --- a/pcsx2/x86/newVif_Unpack.cpp +++ b/pcsx2/x86/newVif_Unpack.cpp @@ -70,6 +70,19 @@ static const __aligned16 Fnptr_VifUnpackLoop UnpackLoopTable[2][2][2] = { }; // ---------------------------------------------------------------------------- +nVifStruct::nVifStruct() +{ + vifBlocks = NULL; + numBlocks = 0; + + recReserveSizeMB = 8; +} + +void reserveNewVif(int idx) +{ + if (newVifDynaRec) dVifReserve(idx); +} + void resetNewVif(int idx) { // Safety Reset : Reassign all VIF structure info, just in case the VU1 pointers have @@ -86,6 +99,10 @@ void closeNewVif(int idx) { if (newVifDynaRec) dVifClose(idx); } +void releaseNewVif(int idx) { + if (newVifDynaRec) dVifRelease(idx); +} + static __fi u8* getVUptr(uint idx, int offset) { return (u8*)(vuRegs[idx].Mem + ( offset & (idx ? 0x3ff0 : 0xff0) )); } From 0692ab1bc5f0948b40118a55b72cf79b53da235f Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Wed, 17 Nov 2010 03:18:36 +0000 Subject: [PATCH 21/22] newHostVM: Linux fixes. * Removed some missing / obsolete files from codeblocks projects. * Fixed a segfault on exit * Implemented a platform-consistent pointer value string formatter (%p has no defined standard) git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@4026 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/src/Utilities/Linux/LnxHostSys.cpp | 7 +- common/src/Utilities/VirtualMemory.cpp | 75 +++++++++++++------ pcsx2/Linux/pcsx2.cbp | 11 +-- pcsx2/gui/ConsoleLogger.cpp | 26 ++++--- pcsx2/gui/CpuUsageProvider.cpp | 2 +- pcsx2/gui/Dialogs/ConfirmationDialogs.cpp | 4 +- pcsx2/gui/Panels/LogOptionsPanels.cpp | 12 +-- pcsx2/x86/newVif.h | 2 +- plugins/onepad/Linux/OnePad.cbp | 2 +- .../opengl/Linux/zzogl-pg/zzogl-pg.cbp | 4 +- 10 files changed, 85 insertions(+), 60 deletions(-) diff --git a/common/src/Utilities/Linux/LnxHostSys.cpp b/common/src/Utilities/Linux/LnxHostSys.cpp index dd94cbe5c0..a92c2475fc 100644 --- a/common/src/Utilities/Linux/LnxHostSys.cpp +++ b/common/src/Utilities/Linux/LnxHostSys.cpp @@ -42,7 +42,7 @@ static void SysPageFaultSignalFilter( int signal, siginfo_t *siginfo, void * ) // 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. @@ -106,7 +106,7 @@ static bool _memprotect( void* baseaddr, size_t size, const PageProtectionMode& const int result = mprotect( baseaddr, size, lnxmode ); if (result == 0) return true; - + switch(errno) { case EINVAL: @@ -114,7 +114,7 @@ static bool _memprotect( void* baseaddr, size_t size, const PageProtectionMode& baseaddr, (uptr)baseaddr+size, mode.ToString().c_str()) ); break; - + case EACCES: pxFailDev(pxsFmt(L"mprotect returned EACCES @ 0x%08X -> 0x%08X (mode=%s)", baseaddr, (uptr)baseaddr+size, mode.ToString().c_str()) @@ -201,6 +201,7 @@ void* HostSys::Mmap(uptr base, size_t size) void HostSys::Munmap(uptr base, size_t size) { + if (!base) return; munmap((void*)base, size); } diff --git a/common/src/Utilities/VirtualMemory.cpp b/common/src/Utilities/VirtualMemory.cpp index 69369ec3e9..f9f0b3cfd8 100644 --- a/common/src/Utilities/VirtualMemory.cpp +++ b/common/src/Utilities/VirtualMemory.cpp @@ -14,15 +14,16 @@ */ #include "PrecompiledHeader.h" - #include "PageFaultSource.h" -#include "EventSource.inl" -#include "MemsetFast.inl" #ifndef __WXMSW__ #include #endif +#include "EventSource.inl" +#include "MemsetFast.inl" +#include "TlsVariable.inl" + template class EventSource< IEventListener_PageFault >; SrcType_PageFault* Source_PageFault = NULL; @@ -90,7 +91,7 @@ VirtualMemoryReserve& VirtualMemoryReserve::SetName( const wxString& newname ) 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; } @@ -101,6 +102,34 @@ VirtualMemoryReserve& VirtualMemoryReserve::SetPageAccessOnCommit( const PagePro return *this; } +template< uint T > +struct pxMiniCharBuffer +{ + wxChar chars[T]; + pxMiniCharBuffer() {} +}; + +// Rational for this function: %p behavior is undefined, and not well-implemented in most cases. +// MSVC doesn't prefix 0x, and Linux doesn't pad with zeros. (furthermore, 64-bit formatting is unknown +// and has even more room for variation and confusion). As is typical, we need portability, and so this +// isn't really acceptable. So here's a portable version! +const wxChar* pxPtrToString( void* ptr ) +{ + static Threading::TlsVariable< pxMiniCharBuffer < 32 > > buffer; + +#ifdef __x86_64__ + wxSnprintf( buffer->chars, 31, wxT("0x%08X.%08X"), ptr ); +#else + wxSnprintf( buffer->chars, 31, wxT("0x%08X"), ptr ); +#endif + + return buffer->chars; +} + +const wxChar* pxPtrToString( uptr ptr ) +{ + pxPtrToString( (void*)ptr ); +} // Notes: // * This method should be called if the object is already in an released (unreserved) state. @@ -129,8 +158,8 @@ void* VirtualMemoryReserve::Reserve( size_t size, uptr base, uptr 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...", - m_name.c_str(), base, base + size ); + DevCon.Warning( L"%s: host memory @ %s -> %s is unavailable; attempting to map elsewhere...", + m_name.c_str(), pxPtrToString(base), pxPtrToString(base + size) ); SafeSysMunmap(m_baseptr, reserved_bytes); @@ -141,7 +170,7 @@ void* VirtualMemoryReserve::Reserve( size_t size, uptr base, uptr upper_bounds ) m_baseptr = HostSys::MmapReserve( 0, reserved_bytes ); } } - + if ((upper_bounds != 0) && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)) { SafeSysMunmap(m_baseptr, reserved_bytes); @@ -157,8 +186,8 @@ void* VirtualMemoryReserve::Reserve( size_t size, uptr base, uptr upper_bounds ) else mbkb.Write( "[%ukb]", reserved_bytes / 1024 ); - DevCon.WriteLn( Color_Gray, L"%-32s @ 0x%08p -> 0x%08p %s", m_name.c_str(), - m_baseptr, (uptr)m_baseptr+reserved_bytes, mbkb.c_str()); + DevCon.WriteLn( Color_Gray, L"%-32s @ %s -> %s %s", m_name.c_str(), + pxPtrToString(m_baseptr), pxPtrToString((uptr)m_baseptr+reserved_bytes), mbkb.c_str()); return m_baseptr; } @@ -213,16 +242,16 @@ bool VirtualMemoryReserve::TryResize( uint newsize ) if (!m_baseptr) { Console.Warning("%-32s could not be passively resized due to virtual memory conflict!"); - Console.Indent().Warning("(attempted to map memory @ 0x%08p -> 0x%08p", m_baseptr, (uptr)m_baseptr+toReserveBytes); + Console.Indent().Warning("(attempted to map memory @ %08p -> %08p)", m_baseptr, (uptr)m_baseptr+toReserveBytes); } - DevCon.WriteLn( Color_Gray, L"%-32s @ 0x%08p -> 0x%08p [%umb]", m_name.c_str(), + DevCon.WriteLn( Color_Gray, L"%-32s @ %08p -> %08p [%umb]", m_name.c_str(), m_baseptr, (uptr)m_baseptr+toReserveBytes, toReserveBytes / _1mb); } else if (newPages < m_pages_reserved) { if (m_pages_commited > newsize) return false; - + uint toRemovePages = m_pages_reserved - newPages; uint toRemoveBytes = toRemovePages * __pagesize; @@ -230,10 +259,10 @@ bool VirtualMemoryReserve::TryResize( uint newsize ) HostSys::MmapResetPtr(GetPtrEnd(), toRemoveBytes); - DevCon.WriteLn( Color_Gray, L"%-32s @ 0x%08p -> 0x%08p [%umb]", m_name.c_str(), + DevCon.WriteLn( Color_Gray, L"%-32s @ %08p -> %08p [%umb]", m_name.c_str(), m_baseptr, (uptr)m_baseptr+toRemoveBytes, toRemoveBytes / _1mb); } - + return true; } @@ -274,7 +303,7 @@ void BaseVmReserveListener::OnPageFaultEvent(const PageFaultInfo& info, bool& ha sptr offset = (info.addr - (uptr)m_baseptr) / __pagesize; if ((offset < 0) || ((uptr)offset >= m_pages_reserved)) return; - // Linux Note! the SIGNAL handler is very limited in what it can do, and not only can't + // Linux Note! the SIGNAL handler is very limited in what it can do, and not only can't // we let the C++ exception try to unwind the stack, we may not be able to log it either. // (but we might as well try -- kernel/posix rules says not to do it, but Linux kernel // implementations seem to support it). @@ -358,7 +387,7 @@ void SpatialArrayReserve::Reset() } // Important! The number of blocks of the array will be altered when using this method. -// +// bool SpatialArrayReserve::TryResize( uint newsize ) { uint newpages = (newsize + __pagesize - 1) / __pagesize; @@ -376,11 +405,11 @@ bool SpatialArrayReserve::TryResize( uint newsize ) if (newpages < pages_in_use) return false; if (!_parent::TryResize( newsize )) return false; - + // On success, we must re-calibrate the internal blockbits array. - + m_blockbits.Resize( (m_numblocks + 7) / 8 ); - + return true; } @@ -399,7 +428,7 @@ SpatialArrayReserve& SpatialArrayReserve::SetBlockCount( uint blocks ) m_numblocks = blocks; m_blocksize = (m_pages_reserved + m_numblocks-1) / m_numblocks; - + return *this; } @@ -434,7 +463,7 @@ void SpatialArrayReserve::DoCommitAndProtect( uptr page ) { // Spatial Arrays work on block granularity only: // Round the page into a block, and commit the whole block that the page belongs to. - + uint block = page / m_blocksize; CommitBlocks(block*m_blocksize, 1); } @@ -442,12 +471,12 @@ void SpatialArrayReserve::DoCommitAndProtect( uptr page ) void SpatialArrayReserve::OnCommittedBlock( void* block ) { // Determine the block position in the blockbits array, flag it, and be done! - + uptr relative = (uptr)block - (uptr)m_baseptr; relative /= m_blocksize * __pagesize; //DbgCon.WriteLn("Check me out @ 0x%08x", block); - + pxAssert( (m_blockbits[relative/8] & (1 << (relative & 7))) == 0 ); m_blockbits[relative/8] |= 1 << (relative & 7); } diff --git a/pcsx2/Linux/pcsx2.cbp b/pcsx2/Linux/pcsx2.cbp index 8722a0c032..76feb52187 100644 --- a/pcsx2/Linux/pcsx2.cbp +++ b/pcsx2/Linux/pcsx2.cbp @@ -268,9 +268,7 @@ - - @@ -316,7 +314,6 @@ - @@ -362,14 +359,13 @@ - + - @@ -420,7 +416,6 @@ - @@ -448,7 +443,6 @@ - @@ -465,7 +459,6 @@ - @@ -571,10 +564,8 @@ - - diff --git a/pcsx2/gui/ConsoleLogger.cpp b/pcsx2/gui/ConsoleLogger.cpp index 2f6457b64f..58a6133aeb 100644 --- a/pcsx2/gui/ConsoleLogger.cpp +++ b/pcsx2/gui/ConsoleLogger.cpp @@ -193,7 +193,7 @@ void ConsoleLogFrame::ColorArray::Create( int fontsize ) new (&m_table[Color_StrongCyan]) wxTextAttr( wxNullColour, wxNullColour, fixedB ); new (&m_table[Color_StrongYellow]) wxTextAttr( wxNullColour, wxNullColour, fixedB ); new (&m_table[Color_StrongWhite]) wxTextAttr( wxNullColour, wxNullColour, fixedB ); - + SetColorScheme_Light(); } @@ -281,10 +281,10 @@ enum MenuIDs_t MenuId_FontSize_Normal, MenuId_FontSize_Large, MenuId_FontSize_Huge, - + MenuId_ColorScheme_Light = 0x20, MenuId_ColorScheme_Dark, - + MenuId_LogSource_EnableAll = 0x30, MenuId_LogSource_DisableAll, MenuId_LogSource_Devel, @@ -322,7 +322,7 @@ public: } }; -static ConsoleLogSource* const ConLogSources[] = +static ConsoleLogSource* const ConLogSources[] = { (ConsoleLogSource*)&SysConsole.eeConsole, (ConsoleLogSource*)&SysConsole.iopConsole, @@ -334,7 +334,7 @@ static ConsoleLogSource* const ConLogSources[] = (ConsoleLogSource*)&pxConLog_Thread, }; -static const bool ConLogDefaults[] = +static const bool ConLogDefaults[] = { true, true, @@ -437,7 +437,7 @@ ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, A menuSources.Append( MenuId_LogSource_Devel, _("Dev/Verbose"), _("Shows PCSX2 developer logs"), wxITEM_CHECK ); menuSources.AppendSeparator(); - + uint srcnt = ArraySize(ConLogSources); for (uint i=0; i 0x100000 || m_QueueColorSection.GetLength() > 256 ) { ++m_WaitingThreadsForFlush; @@ -629,7 +629,7 @@ bool ConsoleLogFrame::Write( ConsoleColors color, const wxString& text ) if( m_WaitingThreadsForFlush != 0 ) --m_WaitingThreadsForFlush; } } - + return false; } @@ -790,7 +790,7 @@ void ConsoleLogFrame::OnToggleSource( wxCommandEvent& evt ) if (!pxAssertDev( ArraySize(ConLogSources) > srcid, "Invalid source log index (out of bounds)" )) return; if (!pxAssertDev( ConLogSources[srcid] != NULL, "Invalid source log index (NULL pointer [separator])" )) return; - + if( wxMenuItem* item = GetMenuBar()->FindItem(evt.GetId()) ) { pxAssertDev( item->IsCheckable(), "Uncheckable log source menu item? Seems fishy!" ); @@ -926,7 +926,7 @@ void ConsoleLogFrame::DoFlushQueue() // cap at 512k for now... // fixme - 512k runs well on win32 but appears to be very sluggish on linux (but that could // be a result of my using Xming + CoLinux). Might need platform dependent defaults here. --air - + static const int BufferSize = 0x80000; if( (insertPoint + m_CurQueuePos) > BufferSize ) { @@ -1040,6 +1040,8 @@ const IConsoleWriter ConsoleWriter_File = ConsoleToFile_DoWrite, ConsoleToFile_Newline, ConsoleToFile_SetTitle, + + 0 }; Mutex& Pcsx2App::GetProgramLogLock() @@ -1111,6 +1113,8 @@ static const IConsoleWriter ConsoleWriter_Window = ConsoleToWindow_DoWrite, ConsoleToWindow_Newline, ConsoleToWindow_SetTitle, + + 0 }; static const IConsoleWriter ConsoleWriter_WindowAndFile = @@ -1122,6 +1126,8 @@ static const IConsoleWriter ConsoleWriter_WindowAndFile = ConsoleToWindow_DoWrite, ConsoleToWindow_Newline, ConsoleToWindow_SetTitle, + + 0 }; void Pcsx2App::EnableAllLogging() diff --git a/pcsx2/gui/CpuUsageProvider.cpp b/pcsx2/gui/CpuUsageProvider.cpp index a9dc1febf2..8c638283d5 100644 --- a/pcsx2/gui/CpuUsageProvider.cpp +++ b/pcsx2/gui/CpuUsageProvider.cpp @@ -56,7 +56,7 @@ DefaultCpuUsageProvider::DefaultCpuUsageProvider() void DefaultCpuUsageProvider::Reset() { - for( int i=0; iApply(); m_IsDirty = false; - + for( uint i = 0; i - @@ -68,6 +67,7 @@ + diff --git a/plugins/zzogl-pg/opengl/Linux/zzogl-pg/zzogl-pg.cbp b/plugins/zzogl-pg/opengl/Linux/zzogl-pg/zzogl-pg.cbp index c9cef870be..36597b8a36 100644 --- a/plugins/zzogl-pg/opengl/Linux/zzogl-pg/zzogl-pg.cbp +++ b/plugins/zzogl-pg/opengl/Linux/zzogl-pg/zzogl-pg.cbp @@ -132,9 +132,6 @@ - - - @@ -177,6 +174,7 @@ + From b10a6d5271ff23cfea47d98bdbae36bc4f73b75c Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Wed, 17 Nov 2010 04:58:35 +0000 Subject: [PATCH 22/22] newHostVM: MSVC compilation fix. git-svn-id: http://pcsx2.googlecode.com/svn/branches/newHostVM@4028 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/include/Utilities/StringHelpers.h | 3 +++ common/src/Utilities/StringHelpers.cpp | 33 ++++++++++++++++++++++++ common/src/Utilities/VirtualMemory.cpp | 30 --------------------- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/common/include/Utilities/StringHelpers.h b/common/include/Utilities/StringHelpers.h index 1c40692991..c4b3927a53 100644 --- a/common/include/Utilities/StringHelpers.h +++ b/common/include/Utilities/StringHelpers.h @@ -82,6 +82,9 @@ extern bool TryParse( wxPoint& dest, const wxString& src, const wxPoint& defval= extern bool TryParse( wxSize& dest, const wxString& src, const wxSize& defval=wxDefaultSize, const wxString& separators=L","); extern bool TryParse( wxRect& dest, const wxString& src, const wxRect& defval=wxDefaultRect, const wxString& separators=L","); +const wxChar* pxPtrToString( void* ptr ); +const wxChar* pxPtrToString( uptr ptr ); + // -------------------------------------------------------------------------------------- // ParsedAssignmentString // -------------------------------------------------------------------------------------- diff --git a/common/src/Utilities/StringHelpers.cpp b/common/src/Utilities/StringHelpers.cpp index 1b4785fa8a..a8d8c25a3e 100644 --- a/common/src/Utilities/StringHelpers.cpp +++ b/common/src/Utilities/StringHelpers.cpp @@ -16,6 +16,8 @@ #include "PrecompiledHeader.h" #include // for wxPoint/wxRect stuff +#include "TlsVariable.inl" + __fi wxString fromUTF8( const char* src ) { // IMPORTANT: We cannot use wxString::FromUTF8 because it *stupidly* relies on a C++ global instance of @@ -118,6 +120,37 @@ wxString JoinString( const wxChar** src, const wxString& separator ) return dest; } + +template< uint T > +struct pxMiniCharBuffer +{ + wxChar chars[T]; + pxMiniCharBuffer() {} +}; + +// Rational for this function: %p behavior is undefined, and not well-implemented in most cases. +// MSVC doesn't prefix 0x, and Linux doesn't pad with zeros. (furthermore, 64-bit formatting is unknown +// and has even more room for variation and confusion). As is typical, we need portability, and so this +// isn't really acceptable. So here's a portable version! +const wxChar* pxPtrToString( void* ptr ) +{ + static Threading::TlsVariable< pxMiniCharBuffer < 32 > > buffer; + +#ifdef __x86_64__ + wxSnprintf( buffer->chars, 31, wxT("0x%08X.%08X"), ptr ); +#else + wxSnprintf( buffer->chars, 31, wxT("0x%08X"), ptr ); +#endif + + return buffer->chars; +} + +const wxChar* pxPtrToString( uptr ptr ) +{ + return pxPtrToString( (void*)ptr ); +} + + // Attempts to parse and return a value for the given template type, and throws a ParseError // exception if the parse fails. The template type can be anything that is supported/ // implemented via one of the TryParse() method overloads. diff --git a/common/src/Utilities/VirtualMemory.cpp b/common/src/Utilities/VirtualMemory.cpp index f9f0b3cfd8..bb6ec7e838 100644 --- a/common/src/Utilities/VirtualMemory.cpp +++ b/common/src/Utilities/VirtualMemory.cpp @@ -22,7 +22,6 @@ #include "EventSource.inl" #include "MemsetFast.inl" -#include "TlsVariable.inl" template class EventSource< IEventListener_PageFault >; @@ -102,35 +101,6 @@ VirtualMemoryReserve& VirtualMemoryReserve::SetPageAccessOnCommit( const PagePro return *this; } -template< uint T > -struct pxMiniCharBuffer -{ - wxChar chars[T]; - pxMiniCharBuffer() {} -}; - -// Rational for this function: %p behavior is undefined, and not well-implemented in most cases. -// MSVC doesn't prefix 0x, and Linux doesn't pad with zeros. (furthermore, 64-bit formatting is unknown -// and has even more room for variation and confusion). As is typical, we need portability, and so this -// isn't really acceptable. So here's a portable version! -const wxChar* pxPtrToString( void* ptr ) -{ - static Threading::TlsVariable< pxMiniCharBuffer < 32 > > buffer; - -#ifdef __x86_64__ - wxSnprintf( buffer->chars, 31, wxT("0x%08X.%08X"), ptr ); -#else - wxSnprintf( buffer->chars, 31, wxT("0x%08X"), ptr ); -#endif - - return buffer->chars; -} - -const wxChar* pxPtrToString( uptr ptr ) -{ - pxPtrToString( (void*)ptr ); -} - // 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.