From 672bdb5a60837dba10933144c4061bec9d018ce4 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Fri, 30 Jan 2009 21:06:09 +0000 Subject: [PATCH] Implemented Aligned Realloc for Linux, fixed VUmicroMemInit so that it's Linux friendly, and added a new function vtlb_malloc(), which allocates memory blocks below 0x80000000 (which keeps vtlb happy). It's used by PS2, IOP, and VU memory allocators. git-svn-id: http://pcsx2-playground.googlecode.com/svn/trunk@661 a6443dda-0b58-4228-96e9-037be469359c --- pcsx2/AlignedMalloc.cpp | 72 ++++++++++++++++++++++ pcsx2/Hw.cpp | 4 +- pcsx2/IopMem.cpp | 58 +++++------------ pcsx2/Memory.cpp | 39 +----------- pcsx2/Misc.h | 28 --------- pcsx2/SafeArray.h | 10 +++ pcsx2/VUmicroMem.cpp | 60 +++++++++--------- pcsx2/vtlb.cpp | 43 +++++++++++++ pcsx2/vtlb.h | 3 + pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 4 ++ 10 files changed, 183 insertions(+), 138 deletions(-) create mode 100644 pcsx2/AlignedMalloc.cpp diff --git a/pcsx2/AlignedMalloc.cpp b/pcsx2/AlignedMalloc.cpp new file mode 100644 index 0000000000..bc8c37dd3a --- /dev/null +++ b/pcsx2/AlignedMalloc.cpp @@ -0,0 +1,72 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// This module contains implementations of _aligned_malloc for platforms that don't have +// it built into their CRT/libc. + +#include "PrecompiledHeader.h" +#include "System.h" + + +struct AlignedMallocHeader +{ + u32 size; // size of the allocated buffer (minus alignment and header) + void* baseptr; // offset of the original allocated pointer +}; + +static const uint headsize = sizeof(AlignedMallocHeader); + +void* __fastcall pcsx2_aligned_malloc(size_t size, size_t align) +{ + jASSUME( align < 0x10000 ); + + u8* p = (u8*)malloc(size+align+headsize); + + // start alignment calculations from past the header. + uptr pasthead = (uptr)(p+headsize); + uptr aligned = (pasthead + align-1) & ~(align-1); + + AlignedMallocHeader* header = (AlignedMallocHeader*)(aligned-headsize); + jASSUME( (uptr)header >= (uptr)p ); + + header->baseptr = p; + header->size = size; + + return (void*)aligned; +} + +void* __fastcall pcsx2_aligned_realloc(void* handle, size_t size, size_t align) +{ + if( handle == NULL ) return NULL; + jASSUME( align < 0x10000 ); + + AlignedMallocHeader* header = (AlignedMallocHeader*)((uptr)handle - headsize); + + void* newbuf = pcsx2_aligned_malloc( size, align ); + memcpy_fast( newbuf, handle, std::min( size, header->size ) ); + + free( header->baseptr ); + return newbuf; +} + +__forceinline void pcsx2_aligned_free(void* pmem) +{ + if( pmem == NULL ) return; + AlignedMallocHeader* header = (AlignedMallocHeader*)((uptr)pmem - headsize); + free( header->baseptr ); +} diff --git a/pcsx2/Hw.cpp b/pcsx2/Hw.cpp index 2181b5db8f..9f30f32177 100644 --- a/pcsx2/Hw.cpp +++ b/pcsx2/Hw.cpp @@ -327,7 +327,7 @@ mem32_t __fastcall hwRead32_page_other(u32 mem) case D2_SADR: regName = "DMA2_SADDR"; break; } - HW_LOG( "Hardware Read32 at 0x%x (%s), value=0x%x\n", regName, mem, psHu32(mem) ); + HW_LOG( "Hardware Read32 at 0x%x (%s), value=0x%x\n", mem, regName, psHu32(mem) ); } break; @@ -1511,7 +1511,7 @@ mem32_t __fastcall hwRead32(u32 mem) case D2_SADR: regName = "DMA2_SADDR"; break; } - HW_LOG( "Hardware Read32 at 0x%x (%s), value=0x%x\n", regName, mem, psHu32(mem) ); + HW_LOG( "Hardware Read32 at 0x%x (%s), value=0x%x\n", mem, regName, psHu32(mem) ); } break; diff --git a/pcsx2/IopMem.cpp b/pcsx2/IopMem.cpp index a0dbf16e9a..1511b269f9 100644 --- a/pcsx2/IopMem.cpp +++ b/pcsx2/IopMem.cpp @@ -340,49 +340,25 @@ void* _PSXM(u32 mem) } #endif -u8 *psxM; -u8 *psxP; -u8 *psxH; -u8 *psxS; +u8 *psxM = NULL; +u8 *psxP = NULL; +u8 *psxH = NULL; +u8 *psxS = NULL; -uptr *psxMemWLUT; -const uptr *psxMemRLUT; +uptr *psxMemWLUT = NULL; +const uptr *psxMemRLUT = NULL; static u8* m_psxAllMem = NULL; -static const uint m_psxMemSize = Ps2MemSize::IopRam + Ps2MemSize::IopHardware + 0x00010000 + 0x00010000 ; +static const uint m_psxMemSize = + Ps2MemSize::IopRam + + Ps2MemSize::IopHardware + + 0x00010000 + // psxP + 0x00010000 ; // psxS void psxMemAlloc() { - psxMemWLUT = (uptr*)_aligned_malloc(0x10000 * sizeof(uptr) * 2,16); - psxMemRLUT = psxMemWLUT + 0x10000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16); - -#ifdef __LINUX__ - if( m_psxAllMem == NULL ) - m_psxAllMem = (u8*)SysMmap( 0x28000000, m_psxMemSize ); - - if( m_psxAllMem == NULL || (uptr)m_psxAllMem > 0xe0000000 ) - { - // memory allocation *must* have the top bit clear, so let's try again - // with NULL (let the OS pick something for us). - - if( m_psxAllMem != NULL ) - SysMunmap( m_psxAllMem, m_psxMemSize ); - - m_psxAllMem = (u8*)SysMmap( NULL, m_psxMemSize ); - if( (uptr)m_psxAllMem > 0xe0000000 ) - { - if( m_psxAllMem != NULL ) - SysMunmap( m_psxAllMem, m_psxMemSize ); - - m_psxAllMem = NULL; // let the os-independent code below handle the error - } - } - -#else - if( m_psxAllMem == NULL ) - m_psxAllMem = (u8*)_aligned_malloc( m_psxMemSize, 4096 ); -#endif + m_psxAllMem = vtlb_malloc( m_psxMemSize, 4096, 0x21000000 ); if( m_psxAllMem == NULL) throw Exception::OutOfMemory( "psxMemAlloc > failed allocating memory for the IOP processor." ); @@ -393,6 +369,8 @@ void psxMemAlloc() psxH = curpos; curpos += Ps2MemSize::IopHardware; psxS = curpos; //curpos += 0x00010000; + psxMemWLUT = (uptr*)_aligned_malloc(0x10000 * sizeof(uptr) * 2, 16); + psxMemRLUT = psxMemWLUT + 0x10000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16); } // Note! Resetting the IOP's memory state is dependent on having *all* psx memory allocated, @@ -460,11 +438,9 @@ void psxMemReset() void psxMemShutdown() { -#ifdef __LINUX__ - SafeSysMunmap( m_psxAllMem, m_psxMemSize ); -#else - safe_aligned_free( m_psxAllMem ); -#endif + vtlb_free( m_psxAllMem, m_psxMemSize ); + m_psxAllMem = NULL; + //safe_aligned_free( m_psxAllMem ); psxM = psxP = psxH = psxS = NULL; diff --git a/pcsx2/Memory.cpp b/pcsx2/Memory.cpp index d4cd06dfe7..0e8a98971e 100644 --- a/pcsx2/Memory.cpp +++ b/pcsx2/Memory.cpp @@ -624,35 +624,8 @@ static u8* m_psAllMem = NULL; void memAlloc() { -#ifdef __LINUX__ - // For Linux we need to use the system virtual memory mapper so that we - // can coerce an allocation below the 2GB line. - - // just try an arbitrary address first... - // maybe there's a better one to pick? if( m_psAllMem == NULL ) - m_psAllMem = (u8*)SysMmap( 0x24000000, m_allMemSize ); - - if( m_psAllMem == NULL || (uptr)m_psAllMem > 0xe0000000 ) - { - // memory allocation *must* have the top bit clear, so let's try again - // with NULL (let the OS pick something for us). - - if( m_psAllMem != NULL ) - SysMunmap( m_psAllMem, m_allMemSize ); - - m_psAllMem = (u8*)SysMmap( NULL, m_allMemSize ); - if( (uptr)m_psAllMem > 0xe0000000 ) - { - SysMunmap( m_psAllMem, m_allMemSize ); - m_psAllMem = NULL; // let the os-independent code below handle the error - } - } - -#else - if( m_psAllMem == NULL ) - m_psAllMem = (u8*)_aligned_malloc(m_allMemSize, 4096 ); -#endif + m_psAllMem = vtlb_malloc( m_allMemSize, 4096, 0x2400000 ); if( m_psAllMem == NULL) throw Exception::OutOfMemory( "memAlloc > failed to allocate PS2's base ram/rom/scratchpad." ); @@ -669,14 +642,8 @@ void memAlloc() void memShutdown() { -#ifdef __LINUX__ - SafeSysMunmap( m_psAllMem, m_allMemSize ); -#else - // Make sure and unprotect memory first, since CrtDebug will try to write to it. - DWORD old; - VirtualProtect( m_psAllMem, m_allMemSize, PAGE_READWRITE, &old ); - safe_aligned_free(m_psAllMem); -#endif + vtlb_free( m_psAllMem, m_allMemSize ); + m_psAllMem = NULL; psM = psR = psR1 = psR2 = psER = psS = psH = NULL; vtlb_Term(); } diff --git a/pcsx2/Misc.h b/pcsx2/Misc.h index 05333354e7..4104a43655 100644 --- a/pcsx2/Misc.h +++ b/pcsx2/Misc.h @@ -211,34 +211,6 @@ extern u8 g_globalXMMSaved; void injectIRX(const char *filename); -// aligned_malloc: Implement/declare linux equivalents here! -#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) - -static __forceinline void* pcsx2_aligned_malloc(size_t size, size_t align) -{ - assert( align < 0x10000 ); - char* p = (char*)malloc(size+align); - int off = 2+align - ((int)(uptr)(p+2) % align); - - p += off; - *(u16*)(p-2) = off; - - return p; -} - -static __forceinline void pcsx2_aligned_free(void* pmem) -{ - if( pmem != NULL ) { - char* p = (char*)pmem; - free(p - (int)*(u16*)(p-2)); - } -} - -#define _aligned_malloc pcsx2_aligned_malloc -#define _aligned_free pcsx2_aligned_free - -#endif - extern void InitCPUTicks(); extern u64 GetTickFrequency(); extern u64 GetCPUTicks(); diff --git a/pcsx2/SafeArray.h b/pcsx2/SafeArray.h index 1346350bf2..60e8ee98c2 100644 --- a/pcsx2/SafeArray.h +++ b/pcsx2/SafeArray.h @@ -21,6 +21,16 @@ #include "MemcpyFast.h" +extern void* __fastcall pcsx2_aligned_malloc(size_t size, size_t align); +extern void* __fastcall pcsx2_aligned_realloc(void* handle, size_t size, size_t align); +extern void pcsx2_aligned_free(void* pmem); + +// aligned_malloc: Implement/declare linux equivalents here! +#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) +# define _aligned_malloc pcsx2_aligned_malloc +# define _aligned_free pcsx2_aligned_free +#endif + ////////////////////////////////////////////////////////////// // Safe deallocation macros -- always check pointer validity (non-null) // and set pointer to null on deallocation. diff --git a/pcsx2/VUmicroMem.cpp b/pcsx2/VUmicroMem.cpp index cb2af6a1cc..b3b9c12f4b 100644 --- a/pcsx2/VUmicroMem.cpp +++ b/pcsx2/VUmicroMem.cpp @@ -70,6 +70,21 @@ void vuMicroCpuReset() SuperVUReset(-1); } +static u8* m_vuAllMem = NULL; +static const uint m_vuMemSize = + 0x4000+0x800 + // VU0 memory and VU1 registers + 0x1000 + // VU0micro memory + 0x4000 + // VU1 memory + 0x4000 + // VU1micro memory + 0x4000; // HACKFIX (see below) + +// HACKFIX! (air) +// The VIFdma1 has a nasty habit of transferring data into the 4k page of memory above +// the VU1. (oops!!) This happens to be recLUT most of the time, which causes rapid death +// of our emulator. So we allocate some extra space here to keep VIF1 a little happier. + +// fixme - When the VIF is fixed, remove the third +0x4000 above. :) + void vuMicroMemAlloc() { #ifdef PCSX2_VIRTUAL_MEM @@ -120,36 +135,20 @@ void vuMicroMemAlloc() // -- VTLB Memory Allocation -- - if( VU0.Mem == NULL ) - { - VU0.Mem = (u8*)_aligned_malloc(0x4000+sizeof(VURegs), 16); // for VU1 + if( m_vuAllMem == NULL ) + m_vuAllMem = vtlb_malloc( m_vuMemSize, 16, 0x28000000 ); - if( VU0.Mem == NULL ) - throw Exception::OutOfMemory( "vu0init > Failed to allocate VUmicro memory." ); + if( m_vuAllMem == NULL ) + throw Exception::OutOfMemory( "vuMicroMemInit > Failed to allocate VUmicro memory." ); - // Initialize VU1 memory using VU0's allocations: - // Important! VU1 is actually a macro to g_pVU1 (yes, awkward!) so we need to assign it first. + jASSUME( sizeof( VURegs ) <= 0x800 ); - g_pVU1 = (VURegs*)(VU0.Mem + 0x4000); - - // HACKFIX! (Air) - // The VIFdma1 has a nasty habit of transferring data into the 4k page of memory above - // the VU1. (oops!!) This happens to be recLUT most of the time, which causes rapid death - // of our emulator. So we allocate some extra space here to keep VIF1 a little happier. - - // fixme - When the VIF is fixed, change the *3 below back to an *2. - - VU1.Mem = (u8*)_aligned_malloc(0x4000*3, 16); - if (VU1.Mem == NULL ) - throw Exception::OutOfMemory( "vu1Init > Failed to allocate memory for the VU1micro." ); - VU1.Micro = VU1.Mem + 0x4000; //(u8*)_aligned_malloc(16*1024, 16); - } - - if( VU0.Micro == NULL ) - VU0.Micro = (u8*)_aligned_malloc(4*1024, 16); - - if( VU0.Micro == NULL ) - throw Exception::OutOfMemory( "vu0init > Failed to allocate VUmicro memory." ); + u8* curpos = m_vuAllMem; + VU0.Mem = curpos; curpos += 0x4000; + g_pVU1 = (VURegs*)curpos; curpos += 0x800; + VU0.Micro = curpos; curpos += 0x1000; + VU1.Mem = curpos; curpos += 0x4000; + VU1.Micro = curpos; //curpos += 0x4000; #endif } @@ -173,10 +172,9 @@ void vuMicroMemShutdown() // -- VTLB Memory Allocation -- - safe_aligned_free( VU1.Mem ); - safe_aligned_free( VU0.Mem ); - safe_aligned_free( VU0.Micro ); - + vtlb_free( m_vuAllMem, m_vuMemSize ); + m_vuAllMem = NULL; + g_pVU1 = NULL; #endif } diff --git a/pcsx2/vtlb.cpp b/pcsx2/vtlb.cpp index a7c7941acc..cdfae647f2 100644 --- a/pcsx2/vtlb.cpp +++ b/pcsx2/vtlb.cpp @@ -563,4 +563,47 @@ void vtlb_Term() //nothing to do for now } +// 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, uptr tryBaseAddress ) +{ +#ifdef __LINUX__ + void* retval = + ( tryBaseAddress != NULL ) ? SysMmap( tryBaseAddress, size ) : NULL; + + if( retval == NULL || (uptr)retval > 0x80000000 ) + { + // memory allocation *must* have the top bit clear, so let's try again + // with NULL (let the OS pick something for us). + + SafeSysMunmap( retval, size ); + + retval = (u8*)SysMmap( NULL, size ); + if( (uptr)retval > 0x80000000 ) + SafeSysMunmap( retval, size ); + } + return (u8*)retval; +#else + // Win32 just needs this, since malloc always maps below 2GB. + return (u8*)_aligned_malloc(size, align); +#endif +} + +void vtlb_free( void* pmem, uint size ) +{ + if( pmem == NULL ) return; + +#ifdef __LINUX__ + SafeSysMunmap( pmem, size ); +#else +// Make sure and unprotect memory first, since CrtDebug will try to write to it. + DWORD old; + VirtualProtect( pmem, size, PAGE_READWRITE, &old ); + safe_aligned_free( pmem ); +#endif +} + #endif // PCSX2_VIRTUAL_MEM diff --git a/pcsx2/vtlb.h b/pcsx2/vtlb.h index 4c031de32a..fff55c3de1 100644 --- a/pcsx2/vtlb.h +++ b/pcsx2/vtlb.h @@ -30,6 +30,9 @@ typedef u32 vtlbHandler; extern void vtlb_Init(); extern void vtlb_Reset(); extern void vtlb_Term(); +extern u8* vtlb_malloc( uint size, uint align, uptr tryBaseAddress ); +extern void vtlb_free( void* pmem, uint size ); + //physical stuff vtlbHandler vtlb_RegisterHandler( vltbMemR8FP* r8,vltbMemR16FP* r16,vltbMemR32FP* r32,vltbMemR64FP* r64,vltbMemR128FP* r128, diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index d016737627..f7cc0a4946 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -2741,6 +2741,10 @@ + +