mirror of https://github.com/PCSX2/pcsx2.git
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
This commit is contained in:
parent
2cba5081b3
commit
672bdb5a60
|
@ -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 );
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
28
pcsx2/Misc.h
28
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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -2741,6 +2741,10 @@
|
|||
<Filter
|
||||
Name="System"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\AlignedMalloc.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Console.cpp"
|
||||
>
|
||||
|
|
Loading…
Reference in New Issue