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:
Jake.Stine 2009-01-30 21:06:09 +00:00 committed by Gregory Hainaut
parent 2cba5081b3
commit 672bdb5a60
10 changed files with 183 additions and 138 deletions

72
pcsx2/AlignedMalloc.cpp Normal file
View File

@ -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 );
}

View File

@ -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;

View File

@ -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;

View File

@ -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();
}

View File

@ -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();

View File

@ -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.

View File

@ -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
}

View File

@ -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

View File

@ -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,

View File

@ -2741,6 +2741,10 @@
<Filter
Name="System"
>
<File
RelativePath="..\..\AlignedMalloc.cpp"
>
</File>
<File
RelativePath="..\..\Console.cpp"
>