mirror of https://github.com/PCSX2/pcsx2.git
System: Simplify memory allocation
This commit is contained in:
parent
377746f155
commit
606cbb3883
|
@ -187,11 +187,6 @@ private:
|
|||
#endif
|
||||
};
|
||||
|
||||
|
||||
// Safe version of Munmap -- NULLs the pointer variable immediately after free'ing it.
|
||||
#define SafeSysMunmap(ptr, size) \
|
||||
((void)(HostSys::Munmap(ptr, size), (ptr) = 0))
|
||||
|
||||
extern u64 GetTickFrequency();
|
||||
extern u64 GetCPUTicks();
|
||||
extern u64 GetPhysicalMemory();
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include "pcsx2/GameList.h"
|
||||
#include "pcsx2/Patch.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
GamePatchDetailsWidget::GamePatchDetailsWidget(std::string name, const std::string& author,
|
||||
|
|
|
@ -140,7 +140,6 @@ set(pcsx2Sources
|
|||
Vif_Codes.cpp
|
||||
Vif_Transfer.cpp
|
||||
Vif_Unpack.cpp
|
||||
VirtualMemory.cpp
|
||||
VMManager.cpp
|
||||
vtlb.cpp
|
||||
VU0.cpp
|
||||
|
@ -217,7 +216,6 @@ set(pcsx2Headers
|
|||
Vif_Dma.h
|
||||
Vif.h
|
||||
Vif_Unpack.h
|
||||
VirtualMemory.h
|
||||
VMManager.h
|
||||
vtlb.h
|
||||
VUflags.h
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
// Useful enums for some of the fields.
|
||||
|
|
|
@ -17,39 +17,33 @@
|
|||
#include "GS/Renderers/Common/GSFunctionMap.h"
|
||||
#include "System.h"
|
||||
|
||||
static GSCodeReserve s_instance;
|
||||
|
||||
GSCodeReserve::GSCodeReserve()
|
||||
: RecompiledCodeReserve("GS Software Renderer")
|
||||
namespace GSCodeReserve
|
||||
{
|
||||
static u8* s_memory_base;
|
||||
static u8* s_memory_end;
|
||||
static u8* s_memory_ptr;
|
||||
}
|
||||
|
||||
GSCodeReserve::~GSCodeReserve() = default;
|
||||
|
||||
GSCodeReserve& GSCodeReserve::GetInstance()
|
||||
void GSCodeReserve::ResetMemory()
|
||||
{
|
||||
return s_instance;
|
||||
s_memory_base = SysMemory::GetSWRec();
|
||||
s_memory_end = SysMemory::GetSWRecEnd();
|
||||
s_memory_ptr = s_memory_base;
|
||||
}
|
||||
|
||||
void GSCodeReserve::Assign(VirtualMemoryManagerPtr allocator)
|
||||
size_t GSCodeReserve::GetMemoryUsed()
|
||||
{
|
||||
RecompiledCodeReserve::Assign(std::move(allocator), HostMemoryMap::SWrecOffset, HostMemoryMap::SWrecSize);
|
||||
return s_memory_ptr - s_memory_base;
|
||||
}
|
||||
|
||||
void GSCodeReserve::Reset()
|
||||
u8* GSCodeReserve::ReserveMemory(size_t size)
|
||||
{
|
||||
RecompiledCodeReserve::Reset();
|
||||
m_memory_used = 0;
|
||||
pxAssert((s_memory_ptr + size) <= s_memory_end);
|
||||
return s_memory_ptr;
|
||||
}
|
||||
|
||||
u8* GSCodeReserve::Reserve(size_t size)
|
||||
void GSCodeReserve::CommitMemory(size_t size)
|
||||
{
|
||||
pxAssert((m_memory_used + size) <= m_size);
|
||||
return m_baseptr + m_memory_used;
|
||||
}
|
||||
|
||||
void GSCodeReserve::Commit(size_t size)
|
||||
{
|
||||
pxAssert((m_memory_used + size) <= m_size);
|
||||
m_memory_used += size;
|
||||
pxAssert((s_memory_ptr + size) <= s_memory_end);
|
||||
s_memory_ptr += size;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "GS/GSExtra.h"
|
||||
#include "GS/Renderers/SW/GSScanlineEnvironment.h"
|
||||
#include "VirtualMemory.h"
|
||||
#include "System.h"
|
||||
#include "common/emitter/tools.h"
|
||||
|
||||
template <class KEY, class VALUE>
|
||||
|
@ -147,25 +147,15 @@ public:
|
|||
// --------------------------------------------------------------------------------------
|
||||
// Stores code buffers for the GS software JIT.
|
||||
//
|
||||
class GSCodeReserve : public RecompiledCodeReserve
|
||||
namespace GSCodeReserve
|
||||
{
|
||||
public:
|
||||
GSCodeReserve();
|
||||
~GSCodeReserve();
|
||||
void ResetMemory();
|
||||
|
||||
static GSCodeReserve& GetInstance();
|
||||
size_t GetMemoryUsed();
|
||||
|
||||
size_t GetMemoryUsed() const { return m_memory_used; }
|
||||
|
||||
void Assign(VirtualMemoryManagerPtr allocator);
|
||||
void Reset();
|
||||
|
||||
u8* Reserve(size_t size);
|
||||
void Commit(size_t size);
|
||||
|
||||
private:
|
||||
size_t m_memory_used = 0;
|
||||
};
|
||||
u8* ReserveMemory(size_t size);
|
||||
void CommitMemory(size_t size);
|
||||
}
|
||||
|
||||
template <class CG, class KEY, class VALUE>
|
||||
class GSCodeGeneratorFunctionMap : public GSFunctionMap<KEY, VALUE>
|
||||
|
@ -200,7 +190,7 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
u8* code_ptr = GSCodeReserve::GetInstance().Reserve(MAX_SIZE);
|
||||
u8* code_ptr = GSCodeReserve::ReserveMemory(MAX_SIZE);
|
||||
CG cg(key, code_ptr, MAX_SIZE);
|
||||
ASSERT(cg.getSize() < MAX_SIZE);
|
||||
|
||||
|
@ -210,7 +200,7 @@ public:
|
|||
sel.Print();
|
||||
#endif
|
||||
|
||||
GSCodeReserve::GetInstance().Commit(cg.getSize());
|
||||
GSCodeReserve::CommitMemory(cg.getSize());
|
||||
|
||||
ret = (VALUE)cg.getCode();
|
||||
|
||||
|
|
|
@ -38,12 +38,12 @@ GSDrawScanline::GSDrawScanline()
|
|||
: m_sp_map("GSSetupPrim")
|
||||
, m_ds_map("GSDrawScanline")
|
||||
{
|
||||
GSCodeReserve::GetInstance().Reset();
|
||||
GSCodeReserve::ResetMemory();
|
||||
}
|
||||
|
||||
GSDrawScanline::~GSDrawScanline()
|
||||
{
|
||||
if (const size_t used = GSCodeReserve::GetInstance().GetMemoryUsed(); used > 0)
|
||||
if (const size_t used = GSCodeReserve::GetMemoryUsed(); used > 0)
|
||||
DevCon.WriteLn("SW JIT generated %zu bytes of code", used);
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,7 @@ void GSDrawScanline::ResetCodeCache()
|
|||
Console.Warning("GS Software JIT cache overflow, resetting.");
|
||||
m_sp_map.Clear();
|
||||
m_ds_map.Clear();
|
||||
GSCodeReserve::GetInstance().Reset();
|
||||
GSCodeReserve::ResetMemory();
|
||||
}
|
||||
|
||||
bool GSDrawScanline::SetupDraw(GSRasterizerData& data)
|
||||
|
|
28
pcsx2/Hw.cpp
28
pcsx2/Hw.cpp
|
@ -20,7 +20,6 @@
|
|||
#include "Hardware.h"
|
||||
#include "SPU2/spu2.h"
|
||||
#include "USB/USB.h"
|
||||
#include "x86/newVif.h"
|
||||
|
||||
#include "common/WrappedMemCopy.h"
|
||||
|
||||
|
@ -31,35 +30,8 @@ using namespace R5900;
|
|||
const int rdram_devices = 2; // put 8 for TOOL and 2 for PS2 and PSX
|
||||
int rdram_sdevid = 0;
|
||||
|
||||
static bool hwInitialized = false;
|
||||
|
||||
void hwInit()
|
||||
{
|
||||
// [TODO] / FIXME: PCSX2 no longer works on an Init system. It assumes that the
|
||||
// static global vars for the process will be initialized when the process is created, and
|
||||
// then issues *resets only* from then on. (reset code for various S2 components should do
|
||||
// NULL checks and allocate memory and such if the pointers are NULL only).
|
||||
|
||||
if( hwInitialized ) return;
|
||||
|
||||
VifUnpackSSE_Init();
|
||||
|
||||
hwInitialized = true;
|
||||
}
|
||||
|
||||
void hwShutdown()
|
||||
{
|
||||
if (!hwInitialized) return;
|
||||
|
||||
VifUnpackSSE_Destroy();
|
||||
|
||||
hwInitialized = false;
|
||||
}
|
||||
|
||||
void hwReset()
|
||||
{
|
||||
hwInit();
|
||||
|
||||
std::memset(eeHw, 0, sizeof(eeHw));
|
||||
|
||||
psHu32(SBUS_F260) = 0x1D000060;
|
||||
|
|
|
@ -364,7 +364,6 @@ enum GSRegisterAddresses
|
|||
};
|
||||
|
||||
extern void hwReset();
|
||||
extern void hwShutdown();
|
||||
|
||||
extern const int rdram_devices;
|
||||
extern int rdram_sdevid;
|
||||
|
|
|
@ -30,35 +30,20 @@ IopVM_MemoryAllocMess* iopMem = NULL;
|
|||
|
||||
alignas(__pagesize) u8 iopHw[Ps2MemSize::IopHardware];
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// iopMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
iopMemoryReserve::iopMemoryReserve()
|
||||
: _parent("IOP Main Memory (2mb)")
|
||||
{
|
||||
}
|
||||
|
||||
iopMemoryReserve::~iopMemoryReserve()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
void iopMemoryReserve::Assign(VirtualMemoryManagerPtr allocator)
|
||||
void iopMemAlloc()
|
||||
{
|
||||
// TODO: Move to memmap
|
||||
psxMemWLUT = (uptr*)_aligned_malloc(0x2000 * sizeof(uptr) * 2, 16);
|
||||
if (!psxMemWLUT)
|
||||
pxFailRel("Failed to allocate IOP memory lookup table");
|
||||
|
||||
psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
|
||||
|
||||
VtlbMemoryReserve::Assign(std::move(allocator), HostMemoryMap::IOPmemOffset, sizeof(*iopMem));
|
||||
iopMem = reinterpret_cast<IopVM_MemoryAllocMess*>(GetPtr());
|
||||
iopMem = reinterpret_cast<IopVM_MemoryAllocMess*>(SysMemory::GetCodePtr(HostMemoryMap::IOPmemOffset));
|
||||
}
|
||||
|
||||
void iopMemoryReserve::Release()
|
||||
void iopMemRelease()
|
||||
{
|
||||
_parent::Release();
|
||||
|
||||
safe_aligned_free(psxMemWLUT);
|
||||
psxMemRLUT = nullptr;
|
||||
iopMem = nullptr;
|
||||
|
@ -66,10 +51,8 @@ void iopMemoryReserve::Release()
|
|||
|
||||
// Note! Resetting the IOP's memory state is dependent on having *all* psx memory allocated,
|
||||
// which is performed by MemInit and PsxMemInit()
|
||||
void iopMemoryReserve::Reset()
|
||||
void iopMemReset()
|
||||
{
|
||||
_parent::Reset();
|
||||
|
||||
pxAssert( iopMem );
|
||||
|
||||
DbgCon.WriteLn("IOP resetting main memory...");
|
||||
|
|
|
@ -71,10 +71,9 @@ 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();
|
||||
extern void iopMemAlloc();
|
||||
extern void iopMemReset();
|
||||
extern void iopMemRelease();
|
||||
|
||||
extern u8 iopMemRead8 (u32 mem);
|
||||
extern u16 iopMemRead16(u32 mem);
|
||||
|
|
|
@ -701,28 +701,13 @@ void memBindConditionalHandlers()
|
|||
// --------------------------------------------------------------------------------------
|
||||
// eeMemoryReserve (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
eeMemoryReserve::eeMemoryReserve()
|
||||
: _parent("EE Main Memory")
|
||||
void memAllocate()
|
||||
{
|
||||
eeMem = reinterpret_cast<EEVM_MemoryAllocMess*>(SysMemory::GetEEMem());
|
||||
}
|
||||
|
||||
eeMemoryReserve::~eeMemoryReserve()
|
||||
void memReset()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
void eeMemoryReserve::Assign(VirtualMemoryManagerPtr allocator)
|
||||
{
|
||||
_parent::Assign(std::move(allocator), HostMemoryMap::EEmemOffset, sizeof(*eeMem));
|
||||
eeMem = reinterpret_cast<EEVM_MemoryAllocMess*>(GetPtr());
|
||||
}
|
||||
|
||||
|
||||
// Resets memory mappings, unmaps TLBs, reloads bios roms, etc.
|
||||
void eeMemoryReserve::Reset()
|
||||
{
|
||||
_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
|
||||
|
@ -842,8 +827,7 @@ void eeMemoryReserve::Reset()
|
|||
CopyBIOSToMemory();
|
||||
}
|
||||
|
||||
void eeMemoryReserve::Release()
|
||||
void memRelease()
|
||||
{
|
||||
eeMem = nullptr;
|
||||
_parent::Release();
|
||||
}
|
||||
|
|
|
@ -97,6 +97,9 @@ static __fi void ZeroQWC( u128& dest )
|
|||
#define psSu64(mem) (*(u64 *)&eeMem->Scratch[(mem) & 0x3fff])
|
||||
#define psSu128(mem) (*(u128*)&eeMem->Scratch[(mem) & 0x3fff])
|
||||
|
||||
extern void memAllocate();
|
||||
extern void memReset();
|
||||
extern void memRelease();
|
||||
|
||||
extern void memSetKernelMode();
|
||||
//extern void memSetSupervisorMode();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 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-
|
||||
|
@ -18,18 +18,19 @@
|
|||
|
||||
namespace Ps2MemSize
|
||||
{
|
||||
static const uint MainRam = _32mb; // 32 MB main memory!
|
||||
static const uint Rom = _1mb * 4; // 4 MB main rom
|
||||
static const uint Rom1 = _1mb * 4; // DVD player
|
||||
static const uint Rom2 = 0x00080000; // Chinese rom extension
|
||||
static const uint Hardware = _64kb;
|
||||
static const uint Scratch = _16kb;
|
||||
static constexpr u32 MainRam = _32mb; // 32 MB main memory.
|
||||
static constexpr u32 ExtraRam = _1mb * 96; // 32+96 MB devkit memory.
|
||||
static constexpr u32 Rom = _1mb * 4; // 4 MB main rom
|
||||
static constexpr u32 Rom1 = _1mb * 4; // DVD player
|
||||
static constexpr u32 Rom2 = 0x00080000; // Chinese rom extension
|
||||
static constexpr u32 Hardware = _64kb;
|
||||
static constexpr u32 Scratch = _16kb;
|
||||
|
||||
static const uint IopRam = _1mb * 2; // 2MB main ram on the IOP.
|
||||
static const uint IopHardware = _64kb;
|
||||
static constexpr u32 IopRam = _1mb * 2; // 2MB main ram on the IOP.
|
||||
static constexpr u32 IopHardware = _64kb;
|
||||
|
||||
static const uint GSregs = 0x00002000; // 8k for the GS registers and stuff.
|
||||
}
|
||||
static constexpr u32 GSregs = 0x00002000; // 8k for the GS registers and stuff.
|
||||
} // namespace Ps2MemSize
|
||||
|
||||
typedef u8 mem8_t;
|
||||
typedef u16 mem16_t;
|
||||
|
@ -39,11 +40,12 @@ typedef u128 mem128_t;
|
|||
|
||||
struct EEVM_MemoryAllocMess
|
||||
{
|
||||
u8 Main[Ps2MemSize::MainRam]; // Main memory (hard-wired to 32MB)
|
||||
u8 Scratch[Ps2MemSize::Scratch]; // Scratchpad!
|
||||
u8 ROM[Ps2MemSize::Rom]; // Boot rom (4MB)
|
||||
u8 ROM1[Ps2MemSize::Rom1]; // DVD player (4MB)
|
||||
u8 ROM2[Ps2MemSize::Rom2]; // Chinese extensions
|
||||
u8 Main[Ps2MemSize::MainRam]; // Main memory (hard-wired to 32MB)
|
||||
u8 ExtraMemory[Ps2MemSize::ExtraRam]; // Extra memory (32MB up to 128MB => 96MB).
|
||||
u8 Scratch[Ps2MemSize::Scratch]; // Scratchpad!
|
||||
u8 ROM[Ps2MemSize::Rom]; // Boot rom (4MB)
|
||||
u8 ROM1[Ps2MemSize::Rom1]; // DVD player (4MB)
|
||||
u8 ROM2[Ps2MemSize::Rom2]; // Chinese extensions
|
||||
|
||||
// Two 1 megabyte (max DMA) buffers for reading and writing to high memory (>32MB).
|
||||
// Such accesses are not documented as causing bus errors but as the memory does
|
||||
|
@ -56,9 +58,9 @@ struct EEVM_MemoryAllocMess
|
|||
|
||||
struct IopVM_MemoryAllocMess
|
||||
{
|
||||
u8 Main[Ps2MemSize::IopRam]; // Main memory (hard-wired to 2MB)
|
||||
u8 P[_64kb]; // I really have no idea what this is... --air
|
||||
u8 Sif[0x100]; // a few special SIF/SBUS registers (likely not needed)
|
||||
u8 Main[Ps2MemSize::IopRam]; // Main memory (hard-wired to 2MB)
|
||||
u8 P[_64kb]; // I really have no idea what this is... --air
|
||||
u8 Sif[0x100]; // a few special SIF/SBUS registers (likely not needed)
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#define _PC_ // disables MIPS opcode macros.
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/ByteSwap.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
|
|
|
@ -207,7 +207,6 @@ extern R3000Acpu psxRec;
|
|||
extern void psxReset();
|
||||
extern void psxException(u32 code, u32 step);
|
||||
extern void iopEventTest();
|
||||
extern void psxMemReset();
|
||||
|
||||
int psxIsBreakpointNeeded(u32 addr);
|
||||
int psxIsMemcheckNeeded(u32 pc);
|
||||
|
|
|
@ -67,12 +67,8 @@ const int kMaxArgs = 16;
|
|||
uptr g_argPtrs[kMaxArgs];
|
||||
#define DEBUG_LAUNCHARG 0 // show lots of helpful console messages as the launch arguments are passed to the game
|
||||
|
||||
extern SysMainMemory& GetVmMemory();
|
||||
|
||||
void cpuReset()
|
||||
{
|
||||
GetVmMemory().Reset();
|
||||
|
||||
std::memset(&cpuRegs, 0, sizeof(cpuRegs));
|
||||
std::memset(&fpuRegs, 0, sizeof(fpuRegs));
|
||||
std::memset(&tlb, 0, sizeof(tlb));
|
||||
|
@ -91,8 +87,6 @@ void cpuReset()
|
|||
psxReset();
|
||||
pgifInit();
|
||||
|
||||
hwReset();
|
||||
|
||||
extern void Deci2Reset(); // lazy, no good header for it yet.
|
||||
Deci2Reset();
|
||||
|
||||
|
|
|
@ -248,48 +248,19 @@ struct R5900cpu
|
|||
// 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:
|
||||
// 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 (*Reserve)();
|
||||
|
||||
// Deallocates ram allocated by Allocate, Reserve, and/or by runtime code execution.
|
||||
//
|
||||
// Thread Affinity:
|
||||
// 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.
|
||||
//
|
||||
void (*Shutdown)();
|
||||
|
||||
// Initializes / Resets code execution states. Typically implementation is only
|
||||
// needed for recompilers, as interpreters have no internal execution states and
|
||||
// rely on the CPU/VM states almost entirely.
|
||||
//
|
||||
// Thread Affinity:
|
||||
// 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
|
||||
//
|
||||
void (*Reset)();
|
||||
|
||||
// Steps a single instruction. Meant to be used by debuggers. Is currently unused
|
||||
// and unimplemented. Future note: recompiler "step" should *always* fall back
|
||||
// on interpreters.
|
||||
//
|
||||
// Exception Throws: [TODO] (possible execution-related throws to be added)
|
||||
//
|
||||
void (*Step)();
|
||||
|
||||
// Executes code until a break is signaled. Execution can be paused or suspended
|
||||
|
@ -297,11 +268,6 @@ struct R5900cpu
|
|||
// Execution Breakages are handled the same way, where-by a signal causes the Execute
|
||||
// call to return at the nearest state check (typically handled internally using
|
||||
// either C++ exceptions or setjmp/longjmp).
|
||||
//
|
||||
// Exception Throws:
|
||||
// Throws BaseR5900Exception and all derivatives.
|
||||
// Throws FileNotFound or other Streaming errors (typically related to BIOS MEC/NVM)
|
||||
//
|
||||
void (*Execute)();
|
||||
|
||||
// Immediately exits execution of recompiled code if we are in a state to do so, or
|
||||
|
@ -319,13 +285,6 @@ struct R5900cpu
|
|||
// 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 remapped blocks via memory loads/stores, for example).
|
||||
//
|
||||
// Thread Affinity Rule:
|
||||
// Can be called from any thread (namely for being called from debugging threads)
|
||||
//
|
||||
// Exception Throws: [TODO] Emulator defined? (probably shouldn't throw, probably
|
||||
// doesn't matter if we're stripping it out soon. ;)
|
||||
//
|
||||
void (*Clear)(u32 Addr, u32 Size);
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "SIO/Memcard/MemoryCardFolder.h"
|
||||
#include "SIO/Sio.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "SIO/Memcard/MemoryCardFile.h"
|
||||
#include "SIO/Memcard/MemoryCardFolder.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Path.h"
|
||||
|
||||
#include "System.h"
|
||||
|
|
232
pcsx2/System.cpp
232
pcsx2/System.cpp
|
@ -20,6 +20,8 @@
|
|||
#include "CDVD/CDVD.h"
|
||||
#include "Elfheader.h"
|
||||
#include "GSDumpReplayer.h"
|
||||
#include "Host.h"
|
||||
#include "IopMem.h"
|
||||
#include "MTVU.h"
|
||||
#include "R3000A.h"
|
||||
#include "VUmicro.h"
|
||||
|
@ -44,6 +46,20 @@ SSE_MXCSR g_sseMXCSR = {DEFAULT_sseMXCSR};
|
|||
SSE_MXCSR g_sseVU0MXCSR = {DEFAULT_sseVUMXCSR};
|
||||
SSE_MXCSR g_sseVU1MXCSR = {DEFAULT_sseVUMXCSR};
|
||||
|
||||
namespace SysMemory
|
||||
{
|
||||
static u8* TryAllocateVirtualMemory(const char* name, void* file_handle, uptr base, size_t size);
|
||||
static u8* AllocateVirtualMemory(const char* name, void* file_handle, size_t size, size_t offset_from_base);
|
||||
|
||||
static bool AllocateMemoryMap();
|
||||
static void DumpMemoryMap();
|
||||
static void ReleaseMemoryMap();
|
||||
|
||||
static u8* s_data_memory;
|
||||
static void* s_data_memory_file_handle;
|
||||
static u8* s_code_memory;
|
||||
} // namespace SysMemory
|
||||
|
||||
// SetCPUState -- for assignment of SSE roundmodes and clampmodes.
|
||||
//
|
||||
void SetCPUState(SSE_MXCSR sseMXCSR, SSE_MXCSR sseVU0MXCSR, SSE_MXCSR sseVU1MXCSR)
|
||||
|
@ -140,20 +156,55 @@ namespace HostMemoryMap
|
|||
// For debuggers
|
||||
extern "C" {
|
||||
#ifdef _WIN32
|
||||
_declspec(dllexport) uptr EEmem, IOPmem, VUmem, EErec, IOPrec, VIF0rec, VIF1rec, mVU0rec, mVU1rec, SWjit, bumpAllocator;
|
||||
_declspec(dllexport) uptr EEmem, IOPmem, VUmem;
|
||||
#else
|
||||
__attribute__((visibility("default"), used)) uptr EEmem, IOPmem, VUmem, EErec, IOPrec, VIF0rec, VIF1rec, mVU0rec, mVU1rec, SWjit, bumpAllocator;
|
||||
__attribute__((visibility("default"), used)) uptr EEmem, IOPmem, VUmem;
|
||||
#endif
|
||||
}
|
||||
} // namespace HostMemoryMap
|
||||
|
||||
/// Attempts to find a spot near static variables for the main memory
|
||||
static VirtualMemoryManagerPtr makeMemoryManager(const char* name, const char* file_mapping_name, size_t size, size_t offset_from_base)
|
||||
u8* SysMemory::TryAllocateVirtualMemory(const char* name, void* file_handle, uptr base, size_t size)
|
||||
{
|
||||
u8* baseptr;
|
||||
|
||||
if (file_handle)
|
||||
baseptr = static_cast<u8*>(HostSys::MapSharedMemory(file_handle, 0, (void*)base, size, PageAccess_ReadWrite()));
|
||||
else
|
||||
baseptr = static_cast<u8*>(HostSys::Mmap((void*)base, size, PageAccess_Any()));
|
||||
|
||||
if (!baseptr)
|
||||
return nullptr;
|
||||
|
||||
if ((uptr)baseptr != base)
|
||||
{
|
||||
if (file_handle)
|
||||
{
|
||||
if (baseptr)
|
||||
HostSys::UnmapSharedMemory(baseptr, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (baseptr)
|
||||
HostSys::Munmap(baseptr, size);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DevCon.WriteLn(Color_Gray, "%-32s @ 0x%016" PRIXPTR " -> 0x%016" PRIXPTR " %s", name,
|
||||
baseptr, (uptr)baseptr + size, fmt::format("[{}mb]", size / _1mb).c_str());
|
||||
|
||||
return baseptr;
|
||||
}
|
||||
|
||||
u8* SysMemory::AllocateVirtualMemory(const char* name, void* file_handle, size_t size, size_t offset_from_base)
|
||||
{
|
||||
pxAssertRel(Common::IsAlignedPow2(size, __pagesize), "Virtual memory size is page aligned");
|
||||
|
||||
// Everything looks nicer when the start of all the sections is a nice round looking number.
|
||||
// Also reduces the variation in the address due to small changes in code.
|
||||
// Breaks ASLR but so does anything else that tries to make addresses constant for our debugging pleasure
|
||||
uptr codeBase = (uptr)(void*)makeMemoryManager / (1 << 28) * (1 << 28);
|
||||
uptr codeBase = (uptr)(void*)AllocateVirtualMemory / (1 << 28) * (1 << 28);
|
||||
|
||||
// The allocation is ~640mb in size, slighly under 3*2^28.
|
||||
// We'll hope that the code generated for the PCSX2 executable stays under 512mb (which is likely)
|
||||
|
@ -167,122 +218,177 @@ static VirtualMemoryManagerPtr makeMemoryManager(const char* name, const char* f
|
|||
// VTLB will throw a fit if we try to put EE main memory here
|
||||
continue;
|
||||
}
|
||||
auto mgr = std::make_shared<VirtualMemoryManager>(name, file_mapping_name, base, size, /*upper_bounds=*/0, /*strict=*/true);
|
||||
if (mgr->IsOk())
|
||||
{
|
||||
return mgr;
|
||||
}
|
||||
|
||||
if (u8* ret = TryAllocateVirtualMemory(name, file_handle, base, size))
|
||||
return ret;
|
||||
|
||||
DevCon.Warning("%s: host memory @ 0x%016" PRIXPTR " -> 0x%016" PRIXPTR " is unavailable; attempting to map elsewhere...", name,
|
||||
base, base + size);
|
||||
}
|
||||
|
||||
// If the above failed and it's x86-64, recompiled code is going to break!
|
||||
// If it's i386 anything can reach anything so it doesn't matter
|
||||
if (sizeof(void*) == 8)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SysMemory::AllocateMemoryMap()
|
||||
{
|
||||
s_data_memory_file_handle = HostSys::CreateSharedMemory(HostSys::GetFileMappingName("pcsx2").c_str(), HostMemoryMap::MainSize);
|
||||
if (!s_data_memory_file_handle)
|
||||
{
|
||||
pxAssertRel(0, "Failed to find a good place for the memory allocation, recompilers may fail");
|
||||
Host::ReportErrorAsync("Error", "Failed to create shared memory file.");
|
||||
ReleaseMemoryMap();
|
||||
return false;
|
||||
}
|
||||
return std::make_shared<VirtualMemoryManager>(name, file_mapping_name, 0, size);
|
||||
|
||||
if ((s_data_memory = AllocateVirtualMemory("Data Memory", s_data_memory_file_handle, HostMemoryMap::MainSize, 0)) == nullptr)
|
||||
{
|
||||
Host::ReportErrorAsync("Error", "Failed to map data memory at an acceptable location.");
|
||||
ReleaseMemoryMap();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((s_code_memory = AllocateVirtualMemory("Code Memory", nullptr, HostMemoryMap::CodeSize, HostMemoryMap::MainSize)) == nullptr)
|
||||
{
|
||||
Host::ReportErrorAsync("Error", "Failed to allocate code memory at an acceptable location.");
|
||||
ReleaseMemoryMap();
|
||||
return false;
|
||||
}
|
||||
|
||||
HostMemoryMap::EEmem = (uptr)(s_data_memory + HostMemoryMap::EEmemOffset);
|
||||
HostMemoryMap::IOPmem = (uptr)(s_data_memory + HostMemoryMap::IOPmemOffset);
|
||||
HostMemoryMap::VUmem = (uptr)(s_data_memory + HostMemoryMap::VUmemSize);
|
||||
|
||||
DumpMemoryMap();
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysReserveVM (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
SysMainMemory::SysMainMemory()
|
||||
: m_mainMemory(makeMemoryManager("Main Memory Manager", "pcsx2", HostMemoryMap::MainSize, 0))
|
||||
, m_codeMemory(makeMemoryManager("Code Memory Manager", nullptr, HostMemoryMap::CodeSize, HostMemoryMap::MainSize))
|
||||
, m_bumpAllocator(m_mainMemory, HostMemoryMap::bumpAllocatorOffset, HostMemoryMap::MainSize - HostMemoryMap::bumpAllocatorOffset)
|
||||
void SysMemory::DumpMemoryMap()
|
||||
{
|
||||
uptr main_base = (uptr)MainMemory()->GetBase();
|
||||
uptr code_base = (uptr)MainMemory()->GetBase();
|
||||
HostMemoryMap::EEmem = main_base + HostMemoryMap::EEmemOffset;
|
||||
HostMemoryMap::IOPmem = main_base + HostMemoryMap::IOPmemOffset;
|
||||
HostMemoryMap::VUmem = main_base + HostMemoryMap::VUmemOffset;
|
||||
HostMemoryMap::EErec = code_base + HostMemoryMap::EErecOffset;
|
||||
HostMemoryMap::IOPrec = code_base + HostMemoryMap::IOPrecOffset;
|
||||
HostMemoryMap::VIF0rec = code_base + HostMemoryMap::VIF0recOffset;
|
||||
HostMemoryMap::VIF1rec = code_base + HostMemoryMap::VIF1recOffset;
|
||||
HostMemoryMap::mVU0rec = code_base + HostMemoryMap::mVU0recOffset;
|
||||
HostMemoryMap::mVU1rec = code_base + HostMemoryMap::mVU1recOffset;
|
||||
HostMemoryMap::bumpAllocator = main_base + HostMemoryMap::bumpAllocatorOffset;
|
||||
#define DUMP_REGION(name, base, offset, size) \
|
||||
DevCon.WriteLn(Color_Gray, "%-32s @ 0x%016" PRIXPTR " -> 0x%016" PRIXPTR " %s", name, \
|
||||
(uptr)(base + offset), (uptr)(base + offset + size), fmt::format("[{}mb]", size / _1mb).c_str());
|
||||
|
||||
DUMP_REGION("EE Main Memory", s_data_memory, HostMemoryMap::EEmemOffset, HostMemoryMap::EEmemSize);
|
||||
DUMP_REGION("IOP Main Memory", s_data_memory, HostMemoryMap::IOPmemOffset, HostMemoryMap::IOPmemSize);
|
||||
DUMP_REGION("VU0/1 On-Chip Memory", s_data_memory, HostMemoryMap::VUmemOffset, HostMemoryMap::VUmemSize);
|
||||
DUMP_REGION("VTLB Virtual Map", s_data_memory, HostMemoryMap::VTLBAddressMapOffset, HostMemoryMap::VTLBVirtualMapSize);
|
||||
DUMP_REGION("VTLB Address Map", s_data_memory, HostMemoryMap::VTLBAddressMapSize, HostMemoryMap::VTLBAddressMapSize);
|
||||
|
||||
DUMP_REGION("R5900 Recompiler Cache", s_code_memory, HostMemoryMap::EErecOffset, HostMemoryMap::EErecSize);
|
||||
DUMP_REGION("R3000A Recompiler Cache", s_code_memory, HostMemoryMap::IOPrecOffset, HostMemoryMap::IOPrecSize);
|
||||
DUMP_REGION("Micro VU0 Recompiler Cache", s_code_memory, HostMemoryMap::mVU0recOffset, HostMemoryMap::mVU0recSize);
|
||||
DUMP_REGION("Micro VU0 Recompiler Cache", s_code_memory, HostMemoryMap::mVU1recOffset, HostMemoryMap::mVU1recSize);
|
||||
DUMP_REGION("VIF0 Unpack Recompiler Cache", s_code_memory, HostMemoryMap::VIF0recOffset, HostMemoryMap::VIF0recSize);
|
||||
DUMP_REGION("VIF1 Unpack Recompiler Cache", s_code_memory, HostMemoryMap::VIF1recOffset, HostMemoryMap::VIF1recSize);
|
||||
DUMP_REGION("VIF Unpack Recompiler Cache", s_code_memory, HostMemoryMap::VIFUnpackRecOffset, HostMemoryMap::VIFUnpackRecSize);
|
||||
DUMP_REGION("GS Software Renderer", s_code_memory, HostMemoryMap::SWrecOffset, HostMemoryMap::SWrecSize);
|
||||
|
||||
|
||||
#undef DUMP_REGION
|
||||
}
|
||||
|
||||
SysMainMemory::~SysMainMemory()
|
||||
void SysMemory::ReleaseMemoryMap()
|
||||
{
|
||||
Release();
|
||||
if (s_code_memory)
|
||||
{
|
||||
HostSys::Munmap(s_code_memory, HostMemoryMap::CodeSize);
|
||||
s_code_memory = nullptr;
|
||||
}
|
||||
|
||||
if (s_data_memory)
|
||||
{
|
||||
HostSys::UnmapSharedMemory(s_data_memory, HostMemoryMap::MainSize);
|
||||
s_data_memory = nullptr;
|
||||
}
|
||||
|
||||
if (s_data_memory_file_handle)
|
||||
{
|
||||
HostSys::DestroySharedMemory(s_data_memory_file_handle);
|
||||
s_data_memory_file_handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool SysMainMemory::Allocate()
|
||||
bool SysMemory::Allocate()
|
||||
{
|
||||
DevCon.WriteLn(Color_StrongBlue, "Allocating host memory for virtual systems...");
|
||||
|
||||
ConsoleIndentScope indent(1);
|
||||
|
||||
m_ee.Assign(MainMemory());
|
||||
m_iop.Assign(MainMemory());
|
||||
m_vu.Assign(MainMemory());
|
||||
if (!AllocateMemoryMap())
|
||||
return false;
|
||||
|
||||
vtlb_Core_Alloc();
|
||||
memAllocate();
|
||||
iopMemAlloc();
|
||||
vuMemAllocate();
|
||||
|
||||
if (!vtlb_Core_Alloc())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SysMainMemory::Reset()
|
||||
void SysMemory::Reset()
|
||||
{
|
||||
DevCon.WriteLn(Color_StrongBlue, "Resetting host memory for virtual systems...");
|
||||
ConsoleIndentScope indent(1);
|
||||
|
||||
m_ee.Reset();
|
||||
m_iop.Reset();
|
||||
m_vu.Reset();
|
||||
memReset();
|
||||
iopMemReset();
|
||||
vuMemReset();
|
||||
|
||||
// Note: newVif is reset as part of other VIF structures.
|
||||
// Software is reset on the GS thread.
|
||||
}
|
||||
|
||||
void SysMainMemory::Release()
|
||||
void SysMemory::Release()
|
||||
{
|
||||
Console.WriteLn(Color_Blue, "Releasing host memory for virtual systems...");
|
||||
ConsoleIndentScope indent(1);
|
||||
|
||||
hwShutdown();
|
||||
|
||||
vtlb_Core_Free(); // Just to be sure... (calling order could result in it getting missed during Decommit).
|
||||
|
||||
releaseNewVif(0);
|
||||
releaseNewVif(1);
|
||||
|
||||
m_ee.Release();
|
||||
m_iop.Release();
|
||||
m_vu.Release();
|
||||
vuMemRelease();
|
||||
iopMemRelease();
|
||||
memRelease();
|
||||
|
||||
ReleaseMemoryMap();
|
||||
}
|
||||
|
||||
u8* SysMemory::GetDataPtr(size_t offset)
|
||||
{
|
||||
pxAssert(offset <= HostMemoryMap::MainSize);
|
||||
return s_data_memory + offset;
|
||||
}
|
||||
|
||||
u8* SysMemory::GetCodePtr(size_t offset)
|
||||
{
|
||||
pxAssert(offset <= HostMemoryMap::CodeSize);
|
||||
return s_code_memory + offset;
|
||||
}
|
||||
|
||||
void* SysMemory::GetDataFileHandle()
|
||||
{
|
||||
return s_data_memory_file_handle;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysCpuProviderPack (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
SysCpuProviderPack::SysCpuProviderPack()
|
||||
{
|
||||
Console.WriteLn(Color_StrongBlue, "Reserving memory for recompilers...");
|
||||
ConsoleIndentScope indent(1);
|
||||
|
||||
recCpu.Reserve();
|
||||
psxRec.Reserve();
|
||||
|
||||
CpuMicroVU0.Reserve();
|
||||
CpuMicroVU1.Reserve();
|
||||
|
||||
if constexpr (newVifDynaRec)
|
||||
{
|
||||
dVifReserve(0);
|
||||
dVifReserve(1);
|
||||
}
|
||||
|
||||
GSCodeReserve::GetInstance().Assign(GetVmMemory().CodeMemory());
|
||||
VifUnpackSSE_Init();
|
||||
}
|
||||
|
||||
SysCpuProviderPack::~SysCpuProviderPack()
|
||||
{
|
||||
GSCodeReserve::GetInstance().Release();
|
||||
|
||||
if (newVifDynaRec)
|
||||
{
|
||||
dVifRelease(1);
|
||||
|
|
141
pcsx2/System.h
141
pcsx2/System.h
|
@ -16,7 +16,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
#include "VirtualMemory.h"
|
||||
#include "vtlb.h"
|
||||
|
||||
// This is a table of default virtual map addresses for ps2vm components. These locations
|
||||
|
@ -35,85 +34,125 @@ namespace HostMemoryMap
|
|||
//////////////////////////////////////////////////////////////////////////
|
||||
// Main
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
static const u32 MainSize = 0x14000000;
|
||||
|
||||
// PS2 main memory, SPR, and ROMs (approximately 40.5MB, but we round up to 64MB for simplicity).
|
||||
static const u32 EEmemOffset = 0x00000000;
|
||||
// PS2 main memory, SPR, and ROMs (approximately 138.5MB, but we round up to 139MB for simplicity).
|
||||
static constexpr u32 EEmemOffset = 0x00000000;
|
||||
static constexpr u32 EEmemSize = 0x8B00000;
|
||||
|
||||
// IOP main memory and ROMs
|
||||
static const u32 IOPmemOffset = 0x04000000;
|
||||
// IOP main memory (2MB + 64K + 256b, rounded up to 3MB for simplicity).
|
||||
static constexpr u32 IOPmemOffset = EEmemOffset + EEmemSize;
|
||||
static constexpr u32 IOPmemSize = 0x300000;
|
||||
|
||||
// VU0 and VU1 memory.
|
||||
static const u32 VUmemOffset = 0x08000000;
|
||||
// VU0 and VU1 memory (40KB, rounded up to 1MB for simplicity).
|
||||
static constexpr u32 VUmemOffset = IOPmemOffset + IOPmemSize;
|
||||
static constexpr u32 VUmemSize = 0x100000;
|
||||
|
||||
// Bump allocator for any other small allocations
|
||||
// size: Difference between it and HostMemoryMap::Size, so nothing should allocate higher than it!
|
||||
static const u32 bumpAllocatorOffset = 0x10000000;
|
||||
// VTLB virtual map ((4GB / 4096) * sizeof(ptr))
|
||||
static constexpr u32 VTLBVirtualMapOffset = VUmemOffset + VUmemSize;
|
||||
static constexpr u32 VTLBVirtualMapSize = (0x100000000ULL / 4096) * sizeof(void*);
|
||||
|
||||
// VTLB address map ((4GB / 4096) * sizeof(u32))
|
||||
static constexpr u32 VTLBAddressMapOffset = VTLBVirtualMapOffset + VTLBVirtualMapSize;
|
||||
static constexpr u32 VTLBAddressMapSize = (0x100000000ULL / 4096) * sizeof(u32);
|
||||
|
||||
// Overall size.
|
||||
static constexpr u32 MainSize = VTLBAddressMapOffset + VTLBAddressMapSize;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Code
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
static const u32 CodeSize = 0x13100000; // 305 mb
|
||||
|
||||
// EE recompiler code cache area (64mb)
|
||||
static const u32 EErecOffset = 0x00000000;
|
||||
static constexpr u32 EErecOffset = 0x00000000;
|
||||
static constexpr u32 EErecSize = 0x4000000;
|
||||
|
||||
// IOP recompiler code cache area (32mb)
|
||||
static const u32 IOPrecOffset = 0x04000000;
|
||||
static constexpr u32 IOPrecOffset = EErecOffset + EErecSize;
|
||||
static constexpr u32 IOPrecSize = 0x2000000;
|
||||
|
||||
// newVif0 recompiler code cache area (8mb)
|
||||
static const u32 VIF0recOffset = 0x06000000;
|
||||
static constexpr u32 VIF0recOffset = IOPrecOffset + IOPrecSize;
|
||||
static constexpr u32 VIF0recSize = 0x800000;
|
||||
|
||||
// newVif1 recompiler code cache area (8mb)
|
||||
static const u32 VIF1recOffset = 0x06800000;
|
||||
static constexpr u32 VIF1recOffset = VIF0recOffset + VIF0recSize;
|
||||
static constexpr u32 VIF1recSize = 0x800000;
|
||||
|
||||
// microVU1 recompiler code cache area (64mb)
|
||||
static const u32 mVU0recOffset = 0x07000000;
|
||||
static constexpr u32 mVU0recOffset = VIF1recOffset + VIF1recSize;
|
||||
static constexpr u32 mVU0recSize = 0x4000000;
|
||||
|
||||
// microVU0 recompiler code cache area (64mb)
|
||||
static const u32 mVU1recOffset = 0x0B000000;
|
||||
static constexpr u32 mVU1recOffset = mVU0recOffset + mVU0recSize;
|
||||
static constexpr u32 mVU1recSize = 0x4000000;
|
||||
|
||||
// SSE-optimized VIF unpack functions (1mb)
|
||||
static const u32 VIFUnpackRecOffset = 0x0F000000;
|
||||
static constexpr u32 VIFUnpackRecOffset = mVU1recOffset + mVU1recSize;
|
||||
static constexpr u32 VIFUnpackRecSize = 0x100000;
|
||||
|
||||
// Software Renderer JIT buffer (64mb)
|
||||
static const u32 SWrecOffset = 0x0F100000;
|
||||
static const u32 SWrecSize = 0x04000000;
|
||||
}
|
||||
static constexpr u32 SWrecOffset = VIFUnpackRecOffset + VIFUnpackRecSize;
|
||||
static constexpr u32 SWrecSize = 0x04000000;
|
||||
|
||||
// Overall size.
|
||||
static constexpr u32 CodeSize = SWrecOffset + SWrecSize; // 305 mb
|
||||
} // namespace HostMemoryMap
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysMainMemory
|
||||
// HostMemory
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class provides the main memory for the virtual machines.
|
||||
class SysMainMemory final
|
||||
|
||||
namespace SysMemory
|
||||
{
|
||||
protected:
|
||||
const VirtualMemoryManagerPtr m_mainMemory;
|
||||
const VirtualMemoryManagerPtr m_codeMemory;
|
||||
|
||||
VirtualMemoryBumpAllocator m_bumpAllocator;
|
||||
|
||||
eeMemoryReserve m_ee;
|
||||
iopMemoryReserve m_iop;
|
||||
vuMemoryReserve m_vu;
|
||||
|
||||
public:
|
||||
SysMainMemory();
|
||||
~SysMainMemory();
|
||||
|
||||
const VirtualMemoryManagerPtr& MainMemory() { return m_mainMemory; }
|
||||
const VirtualMemoryManagerPtr& CodeMemory() { return m_codeMemory; }
|
||||
|
||||
VirtualMemoryBumpAllocator& BumpAllocator() { return m_bumpAllocator; }
|
||||
|
||||
const eeMemoryReserve& EEMemory() const { return m_ee; }
|
||||
const iopMemoryReserve& IOPMemory() const { return m_iop; }
|
||||
const vuMemoryReserve& VUMemory() const { return m_vu; }
|
||||
|
||||
bool Allocate();
|
||||
void Reset();
|
||||
void Release();
|
||||
};
|
||||
|
||||
/// Returns data memory (Main in Memory Map).
|
||||
u8* GetDataPtr(size_t offset);
|
||||
|
||||
/// Returns memory used for the recompilers.
|
||||
u8* GetCodePtr(size_t offset);
|
||||
|
||||
/// Returns the file mapping which backs the data memory.
|
||||
void* GetDataFileHandle();
|
||||
|
||||
// clang-format off
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Data Memory Accessors
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
__fi static u8* GetEEMem() { return GetDataPtr(HostMemoryMap::EEmemOffset); }
|
||||
__fi static u8* GetEEMemEnd() { return GetDataPtr(HostMemoryMap::EEmemOffset + HostMemoryMap::EEmemSize); }
|
||||
__fi static u8* GetIOPMem() { return GetDataPtr(HostMemoryMap::IOPmemOffset); }
|
||||
__fi static u8* GetIOPMemEnd() { return GetDataPtr(HostMemoryMap::IOPmemOffset + HostMemoryMap::IOPmemSize); }
|
||||
__fi static u8* GetVUMem() { return GetDataPtr(HostMemoryMap::VUmemOffset); }
|
||||
__fi static u8* GetVUMemEnd() { return GetDataPtr(HostMemoryMap::VUmemOffset + HostMemoryMap::VUmemSize); }
|
||||
__fi static u8* GetVTLBVirtualMap() { return GetDataPtr(HostMemoryMap::VTLBVirtualMapOffset); }
|
||||
__fi static u8* GetVTLBVirtualMapEnd() { return GetDataPtr(HostMemoryMap::VTLBVirtualMapOffset + HostMemoryMap::VTLBVirtualMapSize); }
|
||||
__fi static u8* GetVTLBAddressMap() { return GetDataPtr(HostMemoryMap::VTLBAddressMapOffset); }
|
||||
__fi static u8* GetVTLBAddressMapEnd() { return GetDataPtr(HostMemoryMap::VTLBAddressMapOffset + HostMemoryMap::VTLBAddressMapSize); }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Code Memory Accessors
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
__fi static u8* GetEERec() { return GetCodePtr(HostMemoryMap::EErecOffset); }
|
||||
__fi static u8* GetEERecEnd() { return GetCodePtr(HostMemoryMap::EErecOffset + HostMemoryMap::EErecSize); }
|
||||
__fi static u8* GetIOPRec() { return GetCodePtr(HostMemoryMap::IOPrecOffset); }
|
||||
__fi static u8* GetIOPRecEnd() { return GetCodePtr(HostMemoryMap::IOPrecOffset + HostMemoryMap::IOPrecSize); }
|
||||
__fi static u8* GetVU0Rec() { return GetCodePtr(HostMemoryMap::mVU0recOffset); }
|
||||
__fi static u8* GetVU0RecEnd() { return GetCodePtr(HostMemoryMap::mVU0recOffset + HostMemoryMap::mVU0recSize); }
|
||||
__fi static u8* GetVU1Rec() { return GetCodePtr(HostMemoryMap::mVU1recOffset); }
|
||||
__fi static u8* GetVU1RecEnd() { return GetCodePtr(HostMemoryMap::mVU1recOffset + HostMemoryMap::mVU1recSize); }
|
||||
__fi static u8* GetVIFUnpackRec() { return GetCodePtr(HostMemoryMap::VIFUnpackRecOffset); }
|
||||
__fi static u8* GetVIFUnpackRecEnd() { return GetCodePtr(HostMemoryMap::VIFUnpackRecOffset + HostMemoryMap::VIFUnpackRecSize); }
|
||||
__fi static u8* GetSWRec() { return GetCodePtr(HostMemoryMap::SWrecOffset); }
|
||||
__fi static u8* GetSWRecEnd() { return GetCodePtr(HostMemoryMap::SWrecOffset + HostMemoryMap::SWrecSize); }
|
||||
|
||||
// clang-format on
|
||||
} // namespace SysMemory
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysCpuProviderPack
|
||||
|
@ -131,10 +170,8 @@ public:
|
|||
// implemented by the provisioning interface.
|
||||
extern SysCpuProviderPack& GetCpuProviders();
|
||||
|
||||
extern void SysLogMachineCaps(); // Detects cpu type and fills cpuInfo structs.
|
||||
extern void SysClearExecutionCache(); // clears recompiled execution caches!
|
||||
|
||||
extern SysMainMemory& GetVmMemory();
|
||||
extern void SysLogMachineCaps(); // Detects cpu type and fills cpuInfo structs.
|
||||
extern void SysClearExecutionCache(); // clears recompiled execution caches!
|
||||
|
||||
extern void SetCPUState(SSE_MXCSR sseMXCSR, SSE_MXCSR sseVU0MXCSR, SSE_MXCSR sseVU1MXCSR);
|
||||
extern SSE_MXCSR g_sseVU0MXCSR, g_sseVU1MXCSR, g_sseMXCSR;
|
||||
|
|
|
@ -147,7 +147,6 @@ namespace VMManager
|
|||
|
||||
static constexpr u32 SETTINGS_VERSION = 1;
|
||||
|
||||
static std::unique_ptr<SysMainMemory> s_vm_memory;
|
||||
static std::unique_ptr<SysCpuProviderPack> s_cpu_provider_pack;
|
||||
static std::unique_ptr<INISettingsInterface> s_game_settings_interface;
|
||||
static std::unique_ptr<INISettingsInterface> s_input_settings_interface;
|
||||
|
@ -349,15 +348,15 @@ bool VMManager::Internal::CPUThreadInitialize()
|
|||
x86caps.SIMD_EstablishMXCSRmask();
|
||||
SysLogMachineCaps();
|
||||
|
||||
pxAssert(!s_vm_memory && !s_cpu_provider_pack);
|
||||
s_vm_memory = std::make_unique<SysMainMemory>();
|
||||
s_cpu_provider_pack = std::make_unique<SysCpuProviderPack>();
|
||||
if (!s_vm_memory->Allocate())
|
||||
if (!SysMemory::Allocate())
|
||||
{
|
||||
Host::ReportErrorAsync("Error", "Failed to allocate VM memory.");
|
||||
return false;
|
||||
}
|
||||
|
||||
pxAssert(!s_cpu_provider_pack);
|
||||
s_cpu_provider_pack = std::make_unique<SysCpuProviderPack>();
|
||||
|
||||
GSinit();
|
||||
USBinit();
|
||||
|
||||
|
@ -388,7 +387,6 @@ void VMManager::Internal::CPUThreadShutdown()
|
|||
WaitForSaveStateFlush();
|
||||
|
||||
s_cpu_provider_pack.reset();
|
||||
s_vm_memory.reset();
|
||||
|
||||
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle());
|
||||
|
||||
|
@ -397,16 +395,13 @@ void VMManager::Internal::CPUThreadShutdown()
|
|||
|
||||
MTGS::ShutdownThread();
|
||||
|
||||
SysMemory::Release();
|
||||
|
||||
#ifdef _WIN32
|
||||
CoUninitialize();
|
||||
#endif
|
||||
}
|
||||
|
||||
SysMainMemory& GetVmMemory()
|
||||
{
|
||||
return *s_vm_memory;
|
||||
}
|
||||
|
||||
SysCpuProviderPack& GetCpuProviders()
|
||||
{
|
||||
return *s_cpu_provider_pack;
|
||||
|
@ -1296,8 +1291,9 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
|||
SetCPUState(EmuConfig.Cpu.sseMXCSR, EmuConfig.Cpu.sseVU0MXCSR, EmuConfig.Cpu.sseVU1MXCSR);
|
||||
SysClearExecutionCache();
|
||||
memBindConditionalHandlers();
|
||||
|
||||
SysMemory::Reset();
|
||||
cpuReset();
|
||||
hwReset();
|
||||
|
||||
Console.WriteLn("VM subsystems initialized in %.2f ms", init_timer.GetTimeMilliseconds());
|
||||
s_state.store(VMState::Paused, std::memory_order_release);
|
||||
|
@ -1438,7 +1434,9 @@ void VMManager::Reset()
|
|||
|
||||
SysClearExecutionCache();
|
||||
memBindConditionalHandlers();
|
||||
SysMemory::Reset();
|
||||
cpuReset();
|
||||
hwReset();
|
||||
|
||||
if (g_InputRecording.isActive())
|
||||
{
|
||||
|
|
|
@ -233,4 +233,7 @@ static VURegs& VU1 = vuRegs[1];
|
|||
inline bool VURegs::IsVU1() const { return this == &vuRegs[1]; }
|
||||
inline bool VURegs::IsVU0() const { return this == &vuRegs[0]; }
|
||||
|
||||
extern void vuMemAllocate();
|
||||
extern void vuMemReset();
|
||||
extern void vuMemRelease();
|
||||
extern u32* GET_VU_MEM(VURegs* VU, u32 addr);
|
||||
|
|
|
@ -21,42 +21,23 @@
|
|||
|
||||
alignas(16) VURegs vuRegs[2];
|
||||
|
||||
|
||||
vuMemoryReserve::vuMemoryReserve()
|
||||
: _parent("VU0/1 on-chip memory")
|
||||
void vuMemAllocate()
|
||||
{
|
||||
}
|
||||
|
||||
vuMemoryReserve::~vuMemoryReserve()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
void vuMemoryReserve::Assign(VirtualMemoryManagerPtr allocator)
|
||||
{
|
||||
static constexpr u32 VU_MEMORY_RESERVE_SIZE = VU1_PROGSIZE + VU1_MEMSIZE + VU0_PROGSIZE + VU0_MEMSIZE;
|
||||
|
||||
_parent::Assign(std::move(allocator), HostMemoryMap::VUmemOffset, VU_MEMORY_RESERVE_SIZE);
|
||||
|
||||
u8* curpos = GetPtr();
|
||||
u8* curpos = SysMemory::GetDataPtr(HostMemoryMap::VUmemOffset);
|
||||
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()
|
||||
void vuMemRelease()
|
||||
{
|
||||
_parent::Release();
|
||||
|
||||
VU0.Micro = VU0.Mem = nullptr;
|
||||
VU1.Micro = VU1.Mem = nullptr;
|
||||
}
|
||||
|
||||
void vuMemoryReserve::Reset()
|
||||
void vuMemReset()
|
||||
{
|
||||
_parent::Reset();
|
||||
|
||||
pxAssert( VU0.Mem );
|
||||
pxAssert( VU1.Mem );
|
||||
|
||||
|
|
|
@ -1,336 +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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "VirtualMemory.h"
|
||||
|
||||
#include "common/BitUtils.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/Perf.h"
|
||||
|
||||
#include "fmt/core.h"
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VirtualMemoryManager (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
VirtualMemoryManager::VirtualMemoryManager(std::string name, const char* file_mapping_name, uptr base, size_t size, uptr upper_bounds, bool strict)
|
||||
: m_name(std::move(name))
|
||||
, m_file_handle(nullptr)
|
||||
, m_baseptr(0)
|
||||
, m_pageuse(nullptr)
|
||||
, m_pages_reserved(0)
|
||||
{
|
||||
if (!size)
|
||||
return;
|
||||
|
||||
size_t reserved_bytes = Common::PageAlign(size);
|
||||
m_pages_reserved = reserved_bytes / __pagesize;
|
||||
|
||||
if (file_mapping_name && file_mapping_name[0])
|
||||
{
|
||||
std::string real_file_mapping_name(HostSys::GetFileMappingName(file_mapping_name));
|
||||
m_file_handle = HostSys::CreateSharedMemory(real_file_mapping_name.c_str(), reserved_bytes);
|
||||
if (!m_file_handle)
|
||||
return;
|
||||
|
||||
m_baseptr = static_cast<u8*>(HostSys::MapSharedMemory(m_file_handle, 0, (void*)base, reserved_bytes, PageAccess_ReadWrite()));
|
||||
if (!m_baseptr || (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)))
|
||||
{
|
||||
DevCon.Warning("%s: host memory @ 0x%016" PRIXPTR " -> 0x%016" PRIXPTR " is unavailable; attempting to map elsewhere...",
|
||||
m_name.c_str(), base, base + size);
|
||||
|
||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||
|
||||
if (base)
|
||||
{
|
||||
// Let's try again at an OS-picked memory area, and then hope it meets needed
|
||||
// boundschecking criteria below.
|
||||
m_baseptr = static_cast<u8*>(HostSys::MapSharedMemory(m_file_handle, 0, nullptr, reserved_bytes, PageAccess_ReadWrite()));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_baseptr = static_cast<u8*>(HostSys::Mmap((void*)base, reserved_bytes, PageAccess_Any()));
|
||||
|
||||
if (!m_baseptr || (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)))
|
||||
{
|
||||
DevCon.Warning("%s: host memory @ 0x%016" PRIXPTR " -> 0x%016" PRIXPTR " is unavailable; attempting to map elsewhere...",
|
||||
m_name.c_str(), base, base + size);
|
||||
|
||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||
|
||||
if (base)
|
||||
{
|
||||
// Let's try again at an OS-picked memory area, and then hope it meets needed
|
||||
// boundschecking criteria below.
|
||||
m_baseptr = static_cast<u8*>(HostSys::Mmap(0, reserved_bytes, PageAccess_Any()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool fulfillsRequirements = true;
|
||||
if (strict && (uptr)m_baseptr != base)
|
||||
fulfillsRequirements = false;
|
||||
if ((upper_bounds != 0) && ((uptr)(m_baseptr + reserved_bytes) > upper_bounds))
|
||||
fulfillsRequirements = false;
|
||||
if (!fulfillsRequirements)
|
||||
{
|
||||
if (m_file_handle)
|
||||
{
|
||||
if (m_baseptr)
|
||||
HostSys::UnmapSharedMemory(m_baseptr, reserved_bytes);
|
||||
m_baseptr = 0;
|
||||
|
||||
HostSys::DestroySharedMemory(m_file_handle);
|
||||
m_file_handle = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
SafeSysMunmap(m_baseptr, reserved_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_baseptr)
|
||||
return;
|
||||
|
||||
m_pageuse = new std::atomic<bool>[m_pages_reserved]();
|
||||
|
||||
std::string mbkb;
|
||||
uint mbytes = reserved_bytes / _1mb;
|
||||
if (mbytes)
|
||||
mbkb = fmt::format("[{}mb]", mbytes);
|
||||
else
|
||||
mbkb = fmt::format("[{}kb]", reserved_bytes / 1024);
|
||||
|
||||
DevCon.WriteLn(Color_Gray, "%-32s @ 0x%016" PRIXPTR " -> 0x%016" PRIXPTR " %s", m_name.c_str(),
|
||||
m_baseptr, (uptr)m_baseptr + reserved_bytes, mbkb.c_str());
|
||||
}
|
||||
|
||||
VirtualMemoryManager::~VirtualMemoryManager()
|
||||
{
|
||||
if (m_pageuse)
|
||||
delete[] m_pageuse;
|
||||
if (m_baseptr)
|
||||
{
|
||||
if (m_file_handle)
|
||||
HostSys::UnmapSharedMemory((void*)m_baseptr, m_pages_reserved * __pagesize);
|
||||
else
|
||||
HostSys::Munmap(m_baseptr, m_pages_reserved * __pagesize);
|
||||
}
|
||||
if (m_file_handle)
|
||||
HostSys::DestroySharedMemory(m_file_handle);
|
||||
}
|
||||
|
||||
static bool VMMMarkPagesAsInUse(std::atomic<bool>* begin, std::atomic<bool>* end)
|
||||
{
|
||||
for (auto current = begin; current < end; current++)
|
||||
{
|
||||
bool expected = false;
|
||||
if (!current->compare_exchange_strong(expected, true, std::memory_order_relaxed))
|
||||
{
|
||||
// This was already allocated! Undo the things we've set until this point
|
||||
while (--current >= begin)
|
||||
{
|
||||
if (!current->compare_exchange_strong(expected, false, std::memory_order_relaxed))
|
||||
{
|
||||
// In the time we were doing this, someone set one of the things we just set to true back to false
|
||||
// This should never happen, but if it does we'll just stop and hope nothing bad happens
|
||||
pxAssert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
u8* VirtualMemoryManager::Alloc(uptr offsetLocation, size_t size) const
|
||||
{
|
||||
size = Common::PageAlign(size);
|
||||
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) alloc at unaligned offsetLocation"))
|
||||
return nullptr;
|
||||
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) alloc outside reserved area"))
|
||||
return nullptr;
|
||||
if (m_baseptr == 0)
|
||||
return nullptr;
|
||||
auto puStart = &m_pageuse[offsetLocation / __pagesize];
|
||||
auto puEnd = &m_pageuse[(offsetLocation + size) / __pagesize];
|
||||
if (!pxAssertDev(VMMMarkPagesAsInUse(puStart, puEnd), "(VirtualMemoryManager) allocation requests overlapped"))
|
||||
return nullptr;
|
||||
return m_baseptr + offsetLocation;
|
||||
}
|
||||
|
||||
void VirtualMemoryManager::Free(void* address, size_t size) const
|
||||
{
|
||||
uptr offsetLocation = (uptr)address - (uptr)m_baseptr;
|
||||
if (!pxAssertDev(offsetLocation % __pagesize == 0, "(VirtualMemoryManager) free at unaligned address"))
|
||||
{
|
||||
uptr newLoc = Common::PageAlign(offsetLocation);
|
||||
size -= (offsetLocation - newLoc);
|
||||
offsetLocation = newLoc;
|
||||
}
|
||||
if (!pxAssertDev(size % __pagesize == 0, "(VirtualMemoryManager) free with unaligned size"))
|
||||
size -= size % __pagesize;
|
||||
if (!pxAssertDev(size + offsetLocation <= m_pages_reserved * __pagesize, "(VirtualMemoryManager) free outside reserved area"))
|
||||
return;
|
||||
auto puStart = &m_pageuse[offsetLocation / __pagesize];
|
||||
auto puEnd = &m_pageuse[(offsetLocation + size) / __pagesize];
|
||||
for (; puStart < puEnd; puStart++)
|
||||
{
|
||||
bool expected = true;
|
||||
if (!puStart->compare_exchange_strong(expected, false, std::memory_order_relaxed))
|
||||
{
|
||||
pxAssertDev(0, "(VirtaulMemoryManager) double-free");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VirtualMemoryBumpAllocator (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
VirtualMemoryBumpAllocator::VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, uptr offsetLocation, size_t size)
|
||||
: m_allocator(std::move(allocator))
|
||||
, m_baseptr(m_allocator->Alloc(offsetLocation, size))
|
||||
, m_endptr(m_baseptr + size)
|
||||
{
|
||||
if (m_baseptr.load() == 0)
|
||||
pxAssertDev(0, "(VirtualMemoryBumpAllocator) tried to construct from bad VirtualMemoryManager");
|
||||
}
|
||||
|
||||
u8* VirtualMemoryBumpAllocator::Alloc(size_t size)
|
||||
{
|
||||
if (m_baseptr.load() == 0) // True if constructed from bad VirtualMemoryManager (assertion was on initialization)
|
||||
return nullptr;
|
||||
|
||||
size_t reservedSize = Common::PageAlign(size);
|
||||
|
||||
u8* out = m_baseptr.fetch_add(reservedSize, std::memory_order_relaxed);
|
||||
|
||||
if (!pxAssertDev(out - reservedSize + size <= m_endptr, "(VirtualMemoryBumpAllocator) ran out of memory"))
|
||||
return nullptr;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VirtualMemoryReserve (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
VirtualMemoryReserve::VirtualMemoryReserve(std::string name)
|
||||
: m_name(std::move(name))
|
||||
{
|
||||
}
|
||||
|
||||
VirtualMemoryReserve::~VirtualMemoryReserve()
|
||||
{
|
||||
pxAssertRel(!m_baseptr, "VirtualMemoryReserve has not been released.");
|
||||
}
|
||||
|
||||
// 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:
|
||||
// baseptr - the new base pointer that's about to be assigned
|
||||
// size - size of the region pointed to by baseptr
|
||||
//
|
||||
void VirtualMemoryReserve::Assign(VirtualMemoryManagerPtr allocator, u8* baseptr, size_t size)
|
||||
{
|
||||
pxAssertRel(size > 0 && Common::IsAlignedPow2(size, __pagesize), "VM allocation is not page aligned");
|
||||
pxAssertRel(!m_baseptr, "Virtual memory reserve has already been assigned");
|
||||
|
||||
m_allocator = std::move(allocator);
|
||||
m_baseptr = baseptr;
|
||||
m_size = size;
|
||||
|
||||
std::string mbkb;
|
||||
uint mbytes = size / _1mb;
|
||||
if (mbytes)
|
||||
mbkb = fmt::format("[{}mb]", mbytes);
|
||||
else
|
||||
mbkb = fmt::format("[{}kb]", size / 1024);
|
||||
|
||||
DevCon.WriteLn(Color_Gray, "%-32s @ 0x%016" PRIXPTR " -> 0x%016" PRIXPTR " %s", m_name.c_str(),
|
||||
m_baseptr, (uptr)m_baseptr + size, mbkb.c_str());
|
||||
}
|
||||
|
||||
u8* VirtualMemoryReserve::BumpAllocate(VirtualMemoryBumpAllocator& allocator, size_t size)
|
||||
{
|
||||
u8* base = allocator.Alloc(size);
|
||||
if (base)
|
||||
Assign(allocator.GetAllocator(), base, size);
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
void VirtualMemoryReserve::Release()
|
||||
{
|
||||
if (!m_baseptr)
|
||||
return;
|
||||
|
||||
m_allocator->Free(m_baseptr, m_size);
|
||||
m_baseptr = nullptr;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// RecompiledCodeReserve (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
// Constructor!
|
||||
// Parameters:
|
||||
// name - a nice long name that accurately describes the contents of this reserve.
|
||||
RecompiledCodeReserve::RecompiledCodeReserve(std::string name)
|
||||
: VirtualMemoryReserve(std::move(name))
|
||||
{
|
||||
}
|
||||
|
||||
RecompiledCodeReserve::~RecompiledCodeReserve()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
void RecompiledCodeReserve::Assign(VirtualMemoryManagerPtr allocator, size_t offset, size_t size)
|
||||
{
|
||||
// Anything passed to the memory allocator must be page aligned.
|
||||
size = Common::PageAlign(size);
|
||||
|
||||
// Since the memory has already been allocated as part of the main memory map, this should never fail.
|
||||
u8* base = allocator->Alloc(offset, size);
|
||||
if (!base)
|
||||
{
|
||||
Console.WriteLn("(RecompiledCodeReserve) Failed to allocate %zu bytes for %s at offset %zu", size, m_name.c_str(), offset);
|
||||
pxFailRel("RecompiledCodeReserve allocation failed.");
|
||||
}
|
||||
|
||||
VirtualMemoryReserve::Assign(std::move(allocator), base, size);
|
||||
}
|
||||
|
||||
void RecompiledCodeReserve::Reset()
|
||||
{
|
||||
if (IsDevBuild && m_baseptr)
|
||||
{
|
||||
// Clear the recompiled code block to 0xcc (INT3) -- this helps disasm tools show
|
||||
// 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.
|
||||
|
||||
std::memset(m_baseptr, 0xCC, m_size);
|
||||
}
|
||||
}
|
|
@ -1,166 +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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/General.h"
|
||||
#include "common/Assertions.h"
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VirtualMemoryManager: Manages the allocation of PCSX2 VM
|
||||
// Ensures that all memory is close enough together for rip-relative addressing
|
||||
// --------------------------------------------------------------------------------------
|
||||
class VirtualMemoryManager
|
||||
{
|
||||
DeclareNoncopyableObject(VirtualMemoryManager);
|
||||
|
||||
std::string m_name;
|
||||
|
||||
void* m_file_handle;
|
||||
u8* m_baseptr;
|
||||
|
||||
// An array to track page usage (to trigger asserts if things try to overlap)
|
||||
std::atomic<bool>* m_pageuse;
|
||||
|
||||
// reserved memory (in pages)
|
||||
u32 m_pages_reserved;
|
||||
|
||||
public:
|
||||
// If upper_bounds is nonzero and the OS fails to allocate memory that is below it,
|
||||
// calls to IsOk() will return false and Alloc() will always return null pointers
|
||||
// strict indicates that the allocation should quietly fail if the memory can't be mapped at `base`
|
||||
VirtualMemoryManager(std::string name, const char* file_mapping_name, uptr base, size_t size, uptr upper_bounds = 0, bool strict = false);
|
||||
~VirtualMemoryManager();
|
||||
|
||||
bool IsSharedMemory() const { return (m_file_handle != nullptr); }
|
||||
void* GetFileHandle() const { return m_file_handle; }
|
||||
u8* GetBase() const { return m_baseptr; }
|
||||
u8* GetEnd() const { return (m_baseptr + m_pages_reserved * __pagesize); }
|
||||
|
||||
// Request the use of the memory at offsetLocation bytes from the start of the reserved memory area
|
||||
// offsetLocation must be page-aligned
|
||||
u8* Alloc(uptr offsetLocation, size_t size) const;
|
||||
|
||||
u8* AllocAtAddress(void* address, size_t size) const
|
||||
{
|
||||
return Alloc(size, static_cast<const u8*>(address) - m_baseptr);
|
||||
}
|
||||
|
||||
void Free(void* address, size_t size) const;
|
||||
|
||||
// Was this VirtualMemoryManager successfully able to get its memory mapping?
|
||||
// (If not, calls to Alloc will return null pointers)
|
||||
bool IsOk() const { return m_baseptr != 0; }
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<const VirtualMemoryManager> VirtualMemoryManagerPtr;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VirtualMemoryBumpAllocator: Allocates memory for things that don't have explicitly-reserved spots
|
||||
// --------------------------------------------------------------------------------------
|
||||
class VirtualMemoryBumpAllocator
|
||||
{
|
||||
const VirtualMemoryManagerPtr m_allocator;
|
||||
std::atomic<u8*> m_baseptr{0};
|
||||
const u8* m_endptr = 0;
|
||||
|
||||
public:
|
||||
VirtualMemoryBumpAllocator(VirtualMemoryManagerPtr allocator, size_t size, uptr offsetLocation);
|
||||
u8* Alloc(size_t size);
|
||||
const VirtualMemoryManagerPtr& GetAllocator() { return m_allocator; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VirtualMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class VirtualMemoryReserve
|
||||
{
|
||||
DeclareNoncopyableObject(VirtualMemoryReserve);
|
||||
|
||||
protected:
|
||||
std::string m_name;
|
||||
|
||||
// Where the memory came from (so we can return it)
|
||||
VirtualMemoryManagerPtr m_allocator;
|
||||
|
||||
u8* m_baseptr = nullptr;
|
||||
size_t m_size = 0;
|
||||
|
||||
public:
|
||||
VirtualMemoryReserve(std::string name);
|
||||
virtual ~VirtualMemoryReserve();
|
||||
|
||||
// Initialize with the given piece of memory
|
||||
// Note: The memory is already allocated, the allocator is for future use to free the region
|
||||
// It may be null in which case there is no way to free the memory in a way it will be usable again
|
||||
void Assign(VirtualMemoryManagerPtr allocator, u8* baseptr, size_t size);
|
||||
|
||||
u8* BumpAllocate(VirtualMemoryBumpAllocator& allocator, size_t size);
|
||||
|
||||
void Release();
|
||||
|
||||
bool IsOk() const { return m_baseptr != NULL; }
|
||||
const std::string& GetName() const { return m_name; }
|
||||
|
||||
u8* GetPtr() { return m_baseptr; }
|
||||
const u8* GetPtr() const { return m_baseptr; }
|
||||
u8* GetPtrEnd() { return m_baseptr + m_size; }
|
||||
const u8* GetPtrEnd() const { return m_baseptr + m_size; }
|
||||
|
||||
size_t GetSize() const { return m_size; }
|
||||
|
||||
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; }
|
||||
|
||||
u8& operator[](uint idx)
|
||||
{
|
||||
pxAssert(idx < m_size);
|
||||
return *((u8*)m_baseptr + idx);
|
||||
}
|
||||
|
||||
const u8& operator[](uint idx) const
|
||||
{
|
||||
pxAssert(idx < m_size);
|
||||
return *((u8*)m_baseptr + idx);
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// RecompiledCodeReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
// 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 VirtualMemoryReserve
|
||||
{
|
||||
typedef VirtualMemoryReserve _parent;
|
||||
|
||||
public:
|
||||
RecompiledCodeReserve(std::string name);
|
||||
~RecompiledCodeReserve();
|
||||
|
||||
void Assign(VirtualMemoryManagerPtr allocator, size_t offset, size_t size);
|
||||
void Reset();
|
||||
|
||||
operator u8*() { return m_baseptr; }
|
||||
operator const u8*() const { return m_baseptr; }
|
||||
};
|
|
@ -352,7 +352,6 @@
|
|||
<ClCompile Include="USB\usb-pad\usb-turntable.cpp" />
|
||||
<ClCompile Include="USB\usb-printer\usb-printer.cpp" />
|
||||
<ClCompile Include="USB\USB.cpp" />
|
||||
<ClCompile Include="VirtualMemory.cpp" />
|
||||
<ClCompile Include="VMManager.cpp" />
|
||||
<ClCompile Include="windows\Optimus.cpp" />
|
||||
<ClCompile Include="Pcsx2Config.cpp" />
|
||||
|
@ -723,7 +722,6 @@
|
|||
<ClInclude Include="ps2\HwInternal.h" />
|
||||
<ClInclude Include="Cache.h" />
|
||||
<ClInclude Include="Memory.h" />
|
||||
<ClInclude Include="VirtualMemory.h" />
|
||||
<ClInclude Include="VMManager.h" />
|
||||
<ClInclude Include="vtlb.h" />
|
||||
<ClInclude Include="MTVU.h" />
|
||||
|
|
|
@ -1265,9 +1265,6 @@
|
|||
<ClCompile Include="GSDumpReplayer.cpp">
|
||||
<Filter>Tools</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VirtualMemory.cpp">
|
||||
<Filter>System</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\DX11\D3D11ShaderCache.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D11</Filter>
|
||||
</ClCompile>
|
||||
|
@ -2210,9 +2207,6 @@
|
|||
<ClInclude Include="GS.h">
|
||||
<Filter>System\Ps2\GS\GIF</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VirtualMemory.h">
|
||||
<Filter>System</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\DX11\D3D11ShaderCache.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D11</Filter>
|
||||
</ClInclude>
|
||||
|
|
114
pcsx2/vtlb.cpp
114
pcsx2/vtlb.cpp
|
@ -842,7 +842,6 @@ static bool vtlb_IsHostCoalesced(u32 page)
|
|||
static bool vtlb_GetMainMemoryOffsetFromPtr(uptr ptr, u32* mainmem_offset, u32* mainmem_size, PageProtectionMode* prot)
|
||||
{
|
||||
const uptr page_end = ptr + VTLB_PAGE_SIZE;
|
||||
SysMainMemory& vmmem = GetVmMemory();
|
||||
|
||||
// EE memory and ROMs.
|
||||
if (ptr >= (uptr)eeMem->Main && page_end <= (uptr)eeMem->ZeroRead)
|
||||
|
@ -867,11 +866,11 @@ static bool vtlb_GetMainMemoryOffsetFromPtr(uptr ptr, u32* mainmem_offset, u32*
|
|||
|
||||
// VU memory - this includes both data and code for VU0/VU1.
|
||||
// Practically speaking, this is only data, because the code goes through a handler.
|
||||
if (ptr >= (uptr)vmmem.VUMemory().GetPtr() && page_end <= (uptr)vmmem.VUMemory().GetPtrEnd())
|
||||
if (ptr >= (uptr)SysMemory::GetVUMem() && page_end <= (uptr)SysMemory::GetVUMemEnd())
|
||||
{
|
||||
const u32 vumem_offset = static_cast<u32>(ptr - (uptr)vmmem.VUMemory().GetPtr());
|
||||
const u32 vumem_offset = static_cast<u32>(ptr - (uptr)SysMemory::GetVUMem());
|
||||
*mainmem_offset = vumem_offset + HostMemoryMap::VUmemOffset;
|
||||
*mainmem_size = vmmem.VUMemory().GetSize() - vumem_offset;
|
||||
*mainmem_size = HostMemoryMap::VUmemSize - vumem_offset;
|
||||
*prot = PageProtectionMode().Read().Write();
|
||||
return true;
|
||||
}
|
||||
|
@ -932,7 +931,7 @@ static void vtlb_CreateFastmemMapping(u32 vaddr, u32 mainmem_offset, const PageP
|
|||
const u32 host_page = vtlb_HostPage(page);
|
||||
const u32 host_offset = vtlb_HostAlignOffset(mainmem_offset);
|
||||
|
||||
if (!s_fastmem_area->Map(GetVmMemory().MainMemory()->GetFileHandle(), host_offset,
|
||||
if (!s_fastmem_area->Map(SysMemory::GetDataFileHandle(), host_offset,
|
||||
s_fastmem_area->PagePointer(host_page), __pagesize, mode))
|
||||
{
|
||||
Console.Error("Failed to map vaddr %08X to mainmem offset %08X", vtlb_HostAlignOffset(vaddr), host_offset);
|
||||
|
@ -1023,7 +1022,7 @@ bool vtlb_ResolveFastmemMapping(uptr* addr)
|
|||
|
||||
const u32 mainmem_offset = s_fastmem_virtual_mapping[vpage] + (vaddr & VTLB_PAGE_MASK);
|
||||
FASTMEM_LOG("Resolved %p (vaddr %08X) to mainmem offset %08X", uaddr, vaddr, mainmem_offset);
|
||||
*addr = ((uptr)GetVmMemory().MainMemory()->GetBase()) + mainmem_offset;
|
||||
*addr = ((uptr)SysMemory::GetDataPtr(0)) + mainmem_offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1293,47 +1292,31 @@ void vtlb_ResetFastmem()
|
|||
}
|
||||
}
|
||||
|
||||
static constexpr size_t VMAP_SIZE = sizeof(VTLBVirtual) * VTLB_VMAP_ITEMS;
|
||||
|
||||
// Reserves the vtlb core allocation used by various emulation components!
|
||||
// [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.
|
||||
bool vtlb_Core_Alloc()
|
||||
{
|
||||
// Can't return regions to the bump allocator
|
||||
static VTLBVirtual* vmap = nullptr;
|
||||
if (!vmap)
|
||||
static constexpr size_t VMAP_SIZE = sizeof(VTLBVirtual) * VTLB_VMAP_ITEMS;
|
||||
static_assert(HostMemoryMap::VTLBVirtualMapSize == VMAP_SIZE);
|
||||
|
||||
pxAssert(!vtlbdata.vmap && !vtlbdata.fastmem_base && !s_fastmem_area);
|
||||
|
||||
vtlbdata.vmap = reinterpret_cast<VTLBVirtual*>(SysMemory::GetVTLBVirtualMap());
|
||||
|
||||
pxAssert(!s_fastmem_area);
|
||||
s_fastmem_area = SharedMemoryMappingArea::Create(FASTMEM_AREA_SIZE);
|
||||
if (!s_fastmem_area)
|
||||
{
|
||||
vmap = (VTLBVirtual*)GetVmMemory().BumpAllocator().Alloc(VMAP_SIZE);
|
||||
if (!vmap)
|
||||
{
|
||||
Host::ReportErrorAsync("Error", "Failed to allocate vtlb vmap");
|
||||
return false;
|
||||
}
|
||||
Host::ReportErrorAsync("Error", "Failed to allocate fastmem area");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vtlbdata.vmap)
|
||||
{
|
||||
HostSys::MemProtect(vmap, VMAP_SIZE, PageProtectionMode().Read().Write());
|
||||
vtlbdata.vmap = vmap;
|
||||
}
|
||||
|
||||
if (!vtlbdata.fastmem_base)
|
||||
{
|
||||
pxAssert(!s_fastmem_area);
|
||||
s_fastmem_area = SharedMemoryMappingArea::Create(FASTMEM_AREA_SIZE);
|
||||
if (!s_fastmem_area)
|
||||
{
|
||||
Host::ReportErrorAsync("Error", "Failed to allocate fastmem area");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_fastmem_virtual_mapping.resize(FASTMEM_PAGE_COUNT, NO_FASTMEM_MAPPING);
|
||||
vtlbdata.fastmem_base = (uptr)s_fastmem_area->BasePointer();
|
||||
Console.WriteLn(Color_StrongGreen, "Fastmem area: %p - %p",
|
||||
vtlbdata.fastmem_base, vtlbdata.fastmem_base + (FASTMEM_AREA_SIZE - 1));
|
||||
}
|
||||
s_fastmem_virtual_mapping.resize(FASTMEM_PAGE_COUNT, NO_FASTMEM_MAPPING);
|
||||
vtlbdata.fastmem_base = (uptr)s_fastmem_area->BasePointer();
|
||||
DevCon.WriteLn(Color_StrongGreen, "Fastmem area: %p - %p",
|
||||
vtlbdata.fastmem_base, vtlbdata.fastmem_base + (FASTMEM_AREA_SIZE - 1));
|
||||
|
||||
if (!HostSys::InstallPageFaultHandler(&vtlb_private::PageFaultHandler))
|
||||
{
|
||||
|
@ -1344,22 +1327,17 @@ bool vtlb_Core_Alloc()
|
|||
return true;
|
||||
}
|
||||
|
||||
static constexpr size_t PPMAP_SIZE = sizeof(*vtlbdata.ppmap) * VTLB_VMAP_ITEMS;
|
||||
|
||||
// The LUT is only used for 1 game so we allocate it only when the gamefix is enabled (save 4MB)
|
||||
// However automatic gamefix is done after the standard init so a new init function was done.
|
||||
void vtlb_Alloc_Ppmap()
|
||||
{
|
||||
static constexpr size_t PPMAP_SIZE = sizeof(*vtlbdata.ppmap) * VTLB_VMAP_ITEMS;
|
||||
static_assert(HostMemoryMap::VTLBAddressMapSize == PPMAP_SIZE);
|
||||
|
||||
if (vtlbdata.ppmap)
|
||||
return;
|
||||
|
||||
static u32* ppmap = nullptr;
|
||||
|
||||
if (!ppmap)
|
||||
ppmap = (u32*)GetVmMemory().BumpAllocator().Alloc(PPMAP_SIZE);
|
||||
|
||||
HostSys::MemProtect(ppmap, PPMAP_SIZE, PageProtectionMode().Read().Write());
|
||||
vtlbdata.ppmap = ppmap;
|
||||
vtlbdata.ppmap = reinterpret_cast<u32*>(SysMemory::GetVTLBAddressMap());
|
||||
|
||||
// By default a 1:1 virtual to physical mapping
|
||||
for (u32 i = 0; i < VTLB_VMAP_ITEMS; i++)
|
||||
|
@ -1370,16 +1348,8 @@ void vtlb_Core_Free()
|
|||
{
|
||||
HostSys::RemovePageFaultHandler(&vtlb_private::PageFaultHandler);
|
||||
|
||||
if (vtlbdata.vmap)
|
||||
{
|
||||
HostSys::MemProtect(vtlbdata.vmap, VMAP_SIZE, PageProtectionMode());
|
||||
vtlbdata.vmap = nullptr;
|
||||
}
|
||||
if (vtlbdata.ppmap)
|
||||
{
|
||||
HostSys::MemProtect(vtlbdata.ppmap, PPMAP_SIZE, PageProtectionMode());
|
||||
vtlbdata.ppmap = nullptr;
|
||||
}
|
||||
vtlbdata.vmap = nullptr;
|
||||
vtlbdata.ppmap = nullptr;
|
||||
|
||||
vtlb_RemoveFastmemMappings();
|
||||
vtlb_ClearLoadStoreInfo();
|
||||
|
@ -1390,36 +1360,6 @@ void vtlb_Core_Free()
|
|||
s_fastmem_area.reset();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VtlbMemoryReserve (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
VtlbMemoryReserve::VtlbMemoryReserve(std::string name)
|
||||
: VirtualMemoryReserve(std::move(name))
|
||||
{
|
||||
}
|
||||
|
||||
void VtlbMemoryReserve::Assign(VirtualMemoryManagerPtr allocator, size_t offset, size_t size)
|
||||
{
|
||||
// Anything passed to the memory allocator must be page aligned.
|
||||
size = Common::PageAlign(size);
|
||||
|
||||
// Since the memory has already been allocated as part of the main memory map, this should never fail.
|
||||
u8* base = allocator->Alloc(offset, size);
|
||||
if (!base)
|
||||
{
|
||||
Console.WriteLn("(VtlbMemoryReserve) Failed to allocate %zu bytes for %s at offset %zu", size, m_name.c_str(), offset);
|
||||
pxFailRel("VtlbMemoryReserve allocation failed.");
|
||||
}
|
||||
|
||||
VirtualMemoryReserve::Assign(std::move(allocator), base, size);
|
||||
}
|
||||
|
||||
void VtlbMemoryReserve::Reset()
|
||||
{
|
||||
std::memset(GetPtr(), 0, GetSize());
|
||||
}
|
||||
|
||||
|
||||
// ===========================================================================================
|
||||
// Memory Protection and Block Checking, vtlb Style!
|
||||
// ===========================================================================================
|
||||
|
|
66
pcsx2/vtlb.h
66
pcsx2/vtlb.h
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "MemoryTypes.h"
|
||||
#include "SingleRegisterTypes.h"
|
||||
#include "VirtualMemory.h"
|
||||
#include "System.h"
|
||||
|
||||
static const uptr VTLB_AllocUpperBounds = _1gb * 2;
|
||||
|
||||
|
@ -126,70 +126,6 @@ extern void vtlb_DynGenWrite_Const(u32 bits, bool xmm, u32 addr_const, int value
|
|||
|
||||
extern void vtlb_DynGenDispatchers();
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VtlbMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class VtlbMemoryReserve : public VirtualMemoryReserve
|
||||
{
|
||||
public:
|
||||
VtlbMemoryReserve(std::string name);
|
||||
|
||||
void Assign(VirtualMemoryManagerPtr allocator, size_t offset, size_t size);
|
||||
|
||||
virtual void Reset();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// eeMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class eeMemoryReserve : public VtlbMemoryReserve
|
||||
{
|
||||
typedef VtlbMemoryReserve _parent;
|
||||
|
||||
public:
|
||||
eeMemoryReserve();
|
||||
~eeMemoryReserve();
|
||||
|
||||
void Assign(VirtualMemoryManagerPtr allocator);
|
||||
void Release();
|
||||
|
||||
void Reset() override;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// iopMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class iopMemoryReserve : public VtlbMemoryReserve
|
||||
{
|
||||
typedef VtlbMemoryReserve _parent;
|
||||
|
||||
public:
|
||||
iopMemoryReserve();
|
||||
~iopMemoryReserve();
|
||||
|
||||
void Assign(VirtualMemoryManagerPtr allocator);
|
||||
void Release();
|
||||
|
||||
void Reset() override;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// vuMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
class vuMemoryReserve : public VtlbMemoryReserve
|
||||
{
|
||||
typedef VtlbMemoryReserve _parent;
|
||||
|
||||
public:
|
||||
vuMemoryReserve();
|
||||
~vuMemoryReserve();
|
||||
|
||||
void Assign(VirtualMemoryManagerPtr allocator);
|
||||
void Release();
|
||||
|
||||
void Reset() override;
|
||||
};
|
||||
|
||||
namespace vtlb_private
|
||||
{
|
||||
static const uint VTLB_PAGE_BITS = 12;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include "IopBios.h"
|
||||
#include "IopHw.h"
|
||||
#include "Common.h"
|
||||
#include "VirtualMemory.h"
|
||||
#include "System.h"
|
||||
#include "VMManager.h"
|
||||
|
||||
#include <time.h>
|
||||
|
@ -72,23 +72,22 @@ u32 psxhwLUT[0x10000];
|
|||
|
||||
static __fi u32 HWADDR(u32 mem) { return psxhwLUT[mem >> 16] + mem; }
|
||||
|
||||
static RecompiledCodeReserve* recMem = NULL;
|
||||
|
||||
static BASEBLOCK* recRAM = NULL; // and the ptr to the blocks here
|
||||
static BASEBLOCK* recROM = NULL; // and here
|
||||
static BASEBLOCK* recROM1 = NULL; // also here
|
||||
static BASEBLOCK* recROM2 = NULL; // also here
|
||||
static BASEBLOCK* recRAM = nullptr; // and the ptr to the blocks here
|
||||
static BASEBLOCK* recROM = nullptr; // and here
|
||||
static BASEBLOCK* recROM1 = nullptr; // also here
|
||||
static BASEBLOCK* recROM2 = nullptr; // also here
|
||||
static BaseBlocks recBlocks;
|
||||
static u8* recPtr = NULL;
|
||||
static u8* recPtr = nullptr;
|
||||
static u8* recPtrEnd = nullptr;
|
||||
u32 psxpc; // recompiler psxpc
|
||||
int psxbranch; // set for branch
|
||||
u32 g_iopCyclePenalty;
|
||||
|
||||
static EEINST* s_pInstCache = NULL;
|
||||
static EEINST* s_pInstCache = nullptr;
|
||||
static u32 s_nInstCacheSize = 0;
|
||||
|
||||
static BASEBLOCK* s_pCurBlock = NULL;
|
||||
static BASEBLOCKEX* s_pCurBlockEx = NULL;
|
||||
static BASEBLOCK* s_pCurBlock = nullptr;
|
||||
static BASEBLOCKEX* s_pCurBlockEx = nullptr;
|
||||
|
||||
static u32 s_nEndBlock = 0; // what psxpc the current block ends
|
||||
static u32 s_branchTo;
|
||||
|
@ -96,7 +95,7 @@ static bool s_nBlockFF;
|
|||
|
||||
static u32 s_saveConstRegs[32];
|
||||
static u32 s_saveHasConstReg = 0, s_saveFlushedConstReg = 0;
|
||||
static EEINST* s_psaveInstInfo = NULL;
|
||||
static EEINST* s_psaveInstInfo = nullptr;
|
||||
|
||||
u32 s_psxBlockCycles = 0; // cycles of current block recompiling
|
||||
static u32 s_savenBlockCycles = 0;
|
||||
|
@ -879,15 +878,9 @@ static const uint m_recBlockAllocSize =
|
|||
|
||||
static void recReserve()
|
||||
{
|
||||
if (recMem)
|
||||
return;
|
||||
recPtr = SysMemory::GetIOPRec();
|
||||
recPtrEnd = SysMemory::GetIOPRecEnd() - _64kb;
|
||||
|
||||
recMem = new RecompiledCodeReserve("R3000A Recompiler Cache");
|
||||
recMem->Assign(GetVmMemory().CodeMemory(), HostMemoryMap::IOPrecOffset, 32 * _1mb);
|
||||
}
|
||||
|
||||
static void recAlloc()
|
||||
{
|
||||
// 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).
|
||||
|
@ -910,23 +903,18 @@ static void recAlloc()
|
|||
recROM2 = (BASEBLOCK*)curpos;
|
||||
curpos += (Ps2MemSize::Rom2 / 4) * sizeof(BASEBLOCK);
|
||||
|
||||
|
||||
pxAssertRel(!s_pInstCache, "InstCache not allocated");
|
||||
s_nInstCacheSize = 128;
|
||||
s_pInstCache = (EEINST*)malloc(sizeof(EEINST) * s_nInstCacheSize);
|
||||
if (!s_pInstCache)
|
||||
{
|
||||
s_nInstCacheSize = 128;
|
||||
s_pInstCache = (EEINST*)malloc(sizeof(EEINST) * s_nInstCacheSize);
|
||||
if (!s_pInstCache)
|
||||
pxFailRel("Failed to allocate R3000 InstCache array.");
|
||||
}
|
||||
pxFailRel("Failed to allocate R3000 InstCache array.");
|
||||
}
|
||||
|
||||
void recResetIOP()
|
||||
{
|
||||
DevCon.WriteLn("iR3000A Recompiler reset.");
|
||||
|
||||
recAlloc();
|
||||
recMem->Reset();
|
||||
xSetPtr(*recMem);
|
||||
xSetPtr(SysMemory::GetIOPRec());
|
||||
_DynGen_Dispatchers();
|
||||
recPtr = xGetPtr();
|
||||
|
||||
|
@ -983,12 +971,13 @@ void recResetIOP()
|
|||
|
||||
static void recShutdown()
|
||||
{
|
||||
safe_delete(recMem);
|
||||
|
||||
safe_aligned_free(m_recBlockAlloc);
|
||||
|
||||
safe_free(s_pInstCache);
|
||||
s_nInstCacheSize = 0;
|
||||
|
||||
recPtr = nullptr;
|
||||
recPtrEnd = nullptr;
|
||||
}
|
||||
|
||||
static void iopClearRecLUT(BASEBLOCK* base, int count)
|
||||
|
@ -1561,7 +1550,7 @@ static void iopRecRecompile(const u32 startpc)
|
|||
pxAssert(startpc);
|
||||
|
||||
// if recPtr reached the mem limit reset whole mem
|
||||
if (recPtr >= (recMem->GetPtrEnd() - _64kb))
|
||||
if (recPtr >= recPtrEnd)
|
||||
{
|
||||
recResetIOP();
|
||||
}
|
||||
|
@ -1754,7 +1743,7 @@ StartRecomp:
|
|||
}
|
||||
}
|
||||
|
||||
pxAssert(xGetPtr() < recMem->GetPtrEnd());
|
||||
pxAssert(xGetPtr() < recPtrEnd);
|
||||
|
||||
pxAssert(xGetPtr() - recPtr < _64kb);
|
||||
s_pCurBlockEx->x86size = xGetPtr() - recPtr;
|
||||
|
|
|
@ -22,10 +22,10 @@
|
|||
#include "GS.h"
|
||||
#include "Memory.h"
|
||||
#include "Patch.h"
|
||||
#include "System.h"
|
||||
#include "R3000A.h"
|
||||
#include "R5900OpcodeTables.h"
|
||||
#include "VMManager.h"
|
||||
#include "VirtualMemory.h"
|
||||
#include "vtlb.h"
|
||||
#include "x86/BaseblockEx.h"
|
||||
#include "x86/iR5900.h"
|
||||
|
@ -83,23 +83,23 @@ eeProfiler EE::Profiler;
|
|||
|
||||
#define X86
|
||||
|
||||
static RecompiledCodeReserve* recMem = NULL;
|
||||
static u8* recRAMCopy = NULL;
|
||||
static u8* recLutReserve_RAM = NULL;
|
||||
static u8* recRAMCopy = nullptr;
|
||||
static u8* recLutReserve_RAM = nullptr;
|
||||
static const size_t recLutSize = (Ps2MemSize::MainRam + Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2) * wordsize / 4;
|
||||
|
||||
static BASEBLOCK* recRAM = NULL; // and the ptr to the blocks here
|
||||
static BASEBLOCK* recROM = NULL; // and here
|
||||
static BASEBLOCK* recROM1 = NULL; // also here
|
||||
static BASEBLOCK* recROM2 = NULL; // also here
|
||||
static BASEBLOCK* recRAM = nullptr; // and the ptr to the blocks here
|
||||
static BASEBLOCK* recROM = nullptr; // and here
|
||||
static BASEBLOCK* recROM1 = nullptr; // also here
|
||||
static BASEBLOCK* recROM2 = nullptr; // also here
|
||||
|
||||
static BaseBlocks recBlocks;
|
||||
static u8* recPtr = NULL;
|
||||
EEINST* s_pInstCache = NULL;
|
||||
static u8* recPtr = nullptr;
|
||||
static u8* recPtrEnd = nullptr;
|
||||
EEINST* s_pInstCache = nullptr;
|
||||
static u32 s_nInstCacheSize = 0;
|
||||
|
||||
static BASEBLOCK* s_pCurBlock = NULL;
|
||||
static BASEBLOCKEX* s_pCurBlockEx = NULL;
|
||||
static BASEBLOCK* s_pCurBlock = nullptr;
|
||||
static BASEBLOCKEX* s_pCurBlockEx = nullptr;
|
||||
u32 s_nEndBlock = 0; // what pc the current block ends
|
||||
u32 s_branchTo;
|
||||
static bool s_nBlockFF;
|
||||
|
@ -107,7 +107,7 @@ static bool s_nBlockFF;
|
|||
// save states for branches
|
||||
GPR_reg64 s_saveConstRegs[32];
|
||||
static u32 s_saveHasConstReg = 0, s_saveFlushedConstReg = 0;
|
||||
static EEINST* s_psaveInstInfo = NULL;
|
||||
static EEINST* s_psaveInstInfo = nullptr;
|
||||
|
||||
static u32 s_savenBlockCycles = 0;
|
||||
|
||||
|
@ -512,15 +512,9 @@ static __ri void ClearRecLUT(BASEBLOCK* base, int memsize)
|
|||
|
||||
static void recReserve()
|
||||
{
|
||||
if (recMem)
|
||||
return;
|
||||
recPtr = SysMemory::GetEERec();
|
||||
recPtrEnd = SysMemory::GetEERecEnd() - _64kb;
|
||||
|
||||
recMem = new RecompiledCodeReserve("R5900 Recompiler Cache");
|
||||
recMem->Assign(GetVmMemory().CodeMemory(), HostMemoryMap::EErecOffset, 64 * _1mb);
|
||||
}
|
||||
|
||||
static void recAlloc()
|
||||
{
|
||||
if (!recRAMCopy)
|
||||
{
|
||||
recRAMCopy = (u8*)_aligned_malloc(Ps2MemSize::MainRam, 4096);
|
||||
|
@ -577,13 +571,11 @@ static void recAlloc()
|
|||
recLUT_SetPage(recLUT, hwLUT, recROM2, 0xa000, i, i - 0x1e40);
|
||||
}
|
||||
|
||||
if (s_pInstCache == NULL)
|
||||
{
|
||||
s_nInstCacheSize = 128;
|
||||
s_pInstCache = (EEINST*)malloc(sizeof(EEINST) * s_nInstCacheSize);
|
||||
if (!s_pInstCache)
|
||||
pxFailRel("Failed to allocate R5900 InstCache array");
|
||||
}
|
||||
pxAssertRel(!s_pInstCache, "InstCache not allocated");
|
||||
s_nInstCacheSize = 128;
|
||||
s_pInstCache = (EEINST*)malloc(sizeof(EEINST) * s_nInstCacheSize);
|
||||
if (!s_pInstCache)
|
||||
pxFailRel("Failed to allocate R5900 InstCache array");
|
||||
}
|
||||
|
||||
alignas(16) static u16 manual_page[Ps2MemSize::MainRam >> 12];
|
||||
|
@ -596,10 +588,7 @@ static void recResetRaw()
|
|||
|
||||
EE::Profiler.Reset();
|
||||
|
||||
recAlloc();
|
||||
|
||||
recMem->Reset();
|
||||
xSetPtr(*recMem);
|
||||
xSetPtr(SysMemory::GetEERec());
|
||||
_DynGen_Dispatchers();
|
||||
vtlb_DynGenDispatchers();
|
||||
recPtr = xGetPtr();
|
||||
|
@ -620,9 +609,8 @@ static void recResetRaw()
|
|||
g_resetEeScalingStats = true;
|
||||
}
|
||||
|
||||
static void recShutdown()
|
||||
void recShutdown()
|
||||
{
|
||||
safe_delete(recMem);
|
||||
safe_aligned_free(recRAMCopy);
|
||||
safe_aligned_free(recLutReserve_RAM);
|
||||
|
||||
|
@ -632,6 +620,9 @@ static void recShutdown()
|
|||
|
||||
safe_free(s_pInstCache);
|
||||
s_nInstCacheSize = 0;
|
||||
|
||||
recPtr = nullptr;
|
||||
recPtrEnd = nullptr;
|
||||
}
|
||||
|
||||
void recStep()
|
||||
|
@ -909,7 +900,7 @@ void SetBranchImm(u32 imm)
|
|||
u8* recBeginThunk()
|
||||
{
|
||||
// if recPtr reached the mem limit reset whole mem
|
||||
if (recPtr >= (recMem->GetPtrEnd() - _64kb))
|
||||
if (recPtr >= recPtrEnd)
|
||||
eeRecNeedsReset = true;
|
||||
|
||||
xSetPtr(recPtr);
|
||||
|
@ -923,7 +914,7 @@ u8* recEndThunk()
|
|||
{
|
||||
u8* block_end = x86Ptr;
|
||||
|
||||
pxAssert(block_end < recMem->GetPtrEnd());
|
||||
pxAssert(block_end < recPtrEnd);
|
||||
recPtr = block_end;
|
||||
return block_end;
|
||||
}
|
||||
|
@ -2208,7 +2199,7 @@ static void recRecompile(const u32 startpc)
|
|||
pxAssert(startpc);
|
||||
|
||||
// if recPtr reached the mem limit reset whole mem
|
||||
if (recPtr >= (recMem->GetPtrEnd() - _64kb))
|
||||
if (recPtr >= recPtrEnd)
|
||||
eeRecNeedsReset = true;
|
||||
|
||||
if (HWADDR(startpc) == VMManager::Internal::GetCurrentELFEntryPoint())
|
||||
|
@ -2741,7 +2732,7 @@ StartRecomp:
|
|||
}
|
||||
}
|
||||
|
||||
pxAssert(xGetPtr() < recMem->GetPtrEnd());
|
||||
pxAssert(xGetPtr() < recPtrEnd);
|
||||
|
||||
s_pCurBlockEx->x86size = static_cast<u32>(xGetPtr() - recPtr);
|
||||
|
||||
|
@ -2757,8 +2748,8 @@ StartRecomp:
|
|||
|
||||
pxAssert((g_cpuHasConstReg & g_cpuFlushedConstReg) == g_cpuHasConstReg);
|
||||
|
||||
s_pCurBlock = NULL;
|
||||
s_pCurBlockEx = NULL;
|
||||
s_pCurBlock = nullptr;
|
||||
s_pCurBlockEx = nullptr;
|
||||
}
|
||||
|
||||
R5900cpu recCpu = {
|
||||
|
|
|
@ -26,15 +26,6 @@
|
|||
// Micro VU - Main Functions
|
||||
//------------------------------------------------------------------
|
||||
|
||||
void mVUreserveCache(microVU& mVU)
|
||||
{
|
||||
mVU.cache_reserve = new RecompiledCodeReserve(StringUtil::StdStringFromFormat("Micro VU%u Recompiler Cache", mVU.index));
|
||||
|
||||
const size_t alloc_offset = mVU.index ? HostMemoryMap::mVU0recOffset : HostMemoryMap::mVU1recOffset;
|
||||
mVU.cache_reserve->Assign(GetVmMemory().CodeMemory(), alloc_offset, mVU.cacheSize * _1mb);
|
||||
mVU.cache = mVU.cache_reserve->GetPtr();
|
||||
}
|
||||
|
||||
// Only run this once per VU! ;)
|
||||
void mVUinit(microVU& mVU, uint vuIndex)
|
||||
{
|
||||
|
@ -46,12 +37,8 @@ void mVUinit(microVU& mVU, uint vuIndex)
|
|||
mVU.microMemSize = (mVU.index ? 0x4000 : 0x1000);
|
||||
mVU.progSize = (mVU.index ? 0x4000 : 0x1000) / 4;
|
||||
mVU.progMemMask = mVU.progSize-1;
|
||||
mVU.cacheSize = mVUcacheReserve;
|
||||
mVU.cache = nullptr;
|
||||
mVU.startFunct = nullptr;
|
||||
mVU.exitFunct = nullptr;
|
||||
|
||||
mVUreserveCache(mVU);
|
||||
mVU.cache = vuIndex ? SysMemory::GetVU1Rec() : SysMemory::GetVU0Rec();
|
||||
mVU.prog.x86end = (vuIndex ? SysMemory::GetVU1RecEnd() : SysMemory::GetVU0RecEnd()) - (mVUcacheSafeZone * _1mb);
|
||||
|
||||
mVU.regAlloc.reset(new microRegAlloc(mVU.index));
|
||||
}
|
||||
|
@ -59,7 +46,6 @@ void mVUinit(microVU& mVU, uint vuIndex)
|
|||
// Resets Rec Data
|
||||
void mVUreset(microVU& mVU, bool resetReserve)
|
||||
{
|
||||
|
||||
if (THREAD_VU1)
|
||||
{
|
||||
DevCon.Warning("mVU Reset");
|
||||
|
@ -70,9 +56,6 @@ void mVUreset(microVU& mVU, bool resetReserve)
|
|||
}
|
||||
VU0.VI[REG_VPU_STAT].UL &= ~0x100;
|
||||
}
|
||||
// Restore reserve to uncommitted state
|
||||
if (resetReserve)
|
||||
mVU.cache_reserve->Reset();
|
||||
|
||||
xSetPtr(mVU.cache);
|
||||
mVUdispatcherAB(mVU);
|
||||
|
@ -95,7 +78,6 @@ void mVUreset(microVU& mVU, bool resetReserve)
|
|||
// Setup Dynarec Cache Limits for Each Program
|
||||
mVU.prog.x86start = xGetAlignedCallTarget();
|
||||
mVU.prog.x86ptr = mVU.prog.x86start;
|
||||
mVU.prog.x86end = mVU.cache + ((mVU.cacheSize - mVUcacheSafeZone) * _1mb);
|
||||
|
||||
for (u32 i = 0; i < (mVU.progSize / 2); i++)
|
||||
{
|
||||
|
@ -118,9 +100,6 @@ void mVUreset(microVU& mVU, bool resetReserve)
|
|||
// Free Allocated Resources
|
||||
void mVUclose(microVU& mVU)
|
||||
{
|
||||
|
||||
safe_delete(mVU.cache_reserve);
|
||||
|
||||
// Delete Programs and Block Managers
|
||||
for (u32 i = 0; i < (mVU.progSize / 2); i++)
|
||||
{
|
||||
|
|
|
@ -30,7 +30,7 @@ using namespace x86Emitter;
|
|||
#include "Gif_Unit.h"
|
||||
#include "iR5900.h"
|
||||
#include "R5900OpcodeTables.h"
|
||||
#include "VirtualMemory.h"
|
||||
#include "System.h"
|
||||
#include "common/emitter/x86emitter.h"
|
||||
#include "microVU_Misc.h"
|
||||
#include "microVU_IR.h"
|
||||
|
@ -91,9 +91,7 @@ struct microProgManager
|
|||
microRegInfo lpState; // Pipeline state from where program left off (useful for continuing execution)
|
||||
};
|
||||
|
||||
static const uint mVUdispCacheSize = __pagesize; // Dispatcher Cache Size (in bytes)
|
||||
static const uint mVUcacheSafeZone = 3; // Safe-Zone for program recompilation (in megabytes)
|
||||
static const uint mVUcacheReserve = 64; // mVU0, mVU1 Reserve Cache Size (in megabytes)
|
||||
|
||||
struct microVU
|
||||
{
|
||||
|
@ -117,7 +115,6 @@ struct microVU
|
|||
std::unique_ptr<microRegAlloc> regAlloc; // Reg Alloc Class
|
||||
std::FILE* logFile; // Log File Pointer
|
||||
|
||||
RecompiledCodeReserve* cache_reserve;
|
||||
u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to)
|
||||
u8* startFunct; // Function Ptr to the recompiler dispatcher (start)
|
||||
u8* exitFunct; // Function Ptr to the recompiler dispatcher (exit)
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include "Vif.h"
|
||||
#include "VU.h"
|
||||
#include "VirtualMemory.h"
|
||||
|
||||
#include "common/emitter/x86emitter.h"
|
||||
|
||||
|
@ -32,12 +31,10 @@ typedef void (*nVifrecCall)(uptr dest, uptr src);
|
|||
extern void mVUmergeRegs(const xRegisterSSE& dest, const xRegisterSSE& src, int xyzw, bool modXYZW = 0);
|
||||
extern void mVUsaveReg(const xRegisterSSE& reg, xAddressVoid ptr, int xyzw, bool modXYZW);
|
||||
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();
|
||||
extern void VifUnpackSSE_Destroy();
|
||||
|
||||
_vifT extern void dVifUnpack(const u8* data, bool isFill);
|
||||
|
||||
|
@ -64,8 +61,8 @@ struct nVifStruct
|
|||
// (templates are used for most or all VIF indexing)
|
||||
u32 idx;
|
||||
|
||||
RecompiledCodeReserve* recReserve;
|
||||
u8* recWritePtr; // current write pos into the reserve
|
||||
u8* recEndPtr;
|
||||
|
||||
HashBucket vifBlocks; // Vif Blocks
|
||||
|
||||
|
|
|
@ -24,42 +24,19 @@
|
|||
#include "common/StringUtil.h"
|
||||
#include "fmt/core.h"
|
||||
|
||||
static void recReset(int idx)
|
||||
void dVifReset(int idx)
|
||||
{
|
||||
nVif[idx].vifBlocks.reset();
|
||||
|
||||
nVif[idx].recReserve->Reset();
|
||||
|
||||
nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr();
|
||||
}
|
||||
|
||||
void dVifReserve(int idx)
|
||||
{
|
||||
if (nVif[idx].recReserve)
|
||||
return;
|
||||
|
||||
const size_t offset = idx ? HostMemoryMap::VIF1recOffset : HostMemoryMap::VIF0recOffset;
|
||||
nVif[idx].recReserve = new RecompiledCodeReserve(StringUtil::StdStringFromFormat("VIF%u Unpack Recompiler Cache", idx));
|
||||
nVif[idx].recReserve->Assign(GetVmMemory().CodeMemory(), offset, 8 * _1mb);
|
||||
}
|
||||
|
||||
void dVifReset(int idx)
|
||||
{
|
||||
pxAssertDev(nVif[idx].recReserve, "Dynamic VIF recompiler reserve must be created prior to VIF use or reset!");
|
||||
|
||||
recReset(idx);
|
||||
}
|
||||
|
||||
void dVifClose(int idx)
|
||||
{
|
||||
if (nVif[idx].recReserve)
|
||||
nVif[idx].recReserve->Reset();
|
||||
const size_t size = idx ? HostMemoryMap::VIF1recSize : HostMemoryMap::VIF0recSize;
|
||||
nVif[idx].recWritePtr = SysMemory::GetCodePtr(offset);
|
||||
nVif[idx].recEndPtr = nVif[idx].recWritePtr + (size - _256kb);
|
||||
}
|
||||
|
||||
void dVifRelease(int idx)
|
||||
{
|
||||
dVifClose(idx);
|
||||
safe_delete(nVif[idx].recReserve);
|
||||
nVif[idx].vifBlocks.clear();
|
||||
}
|
||||
|
||||
VifUnpackSSE_Dynarec::VifUnpackSSE_Dynarec(const nVifStruct& vif_, const nVifBlock& vifBlock_)
|
||||
|
@ -368,11 +345,11 @@ _vifT __fi nVifBlock* dVifCompile(nVifBlock& block, bool isFill)
|
|||
nVifStruct& v = nVif[idx];
|
||||
|
||||
// Check size before the compilation
|
||||
if (v.recWritePtr > (v.recReserve->GetPtrEnd() - _256kb))
|
||||
if (v.recWritePtr >= v.recEndPtr)
|
||||
{
|
||||
DevCon.WriteLn("nVif Recompiler Cache Reset! [0x%016" PRIXPTR " > 0x%016" PRIXPTR "]",
|
||||
v.recWritePtr, v.recReserve->GetPtrEnd());
|
||||
recReset(idx);
|
||||
v.recWritePtr, v.recEndPtr);
|
||||
dVifReset(idx);
|
||||
}
|
||||
|
||||
// Compile the block now
|
||||
|
|
|
@ -24,9 +24,6 @@
|
|||
#define xMOV64(regX, loc) xMOVUPS (regX, loc)
|
||||
#define xMOV128(regX, loc) xMOVUPS (regX, loc)
|
||||
|
||||
//alignas(__pagesize) static u8 nVifUpkExec[__pagesize*4];
|
||||
static RecompiledCodeReserve* nVifUpkExec = NULL;
|
||||
|
||||
// =====================================================================================================
|
||||
// VifUnpackSSE_Base Section
|
||||
// =====================================================================================================
|
||||
|
@ -376,14 +373,9 @@ static void nVifGen(int usn, int mask, int curCycle)
|
|||
|
||||
void VifUnpackSSE_Init()
|
||||
{
|
||||
if (nVifUpkExec)
|
||||
return;
|
||||
|
||||
DevCon.WriteLn("Generating SSE-optimized unpacking functions for VIF interpreters...");
|
||||
|
||||
nVifUpkExec = new RecompiledCodeReserve("VIF SSE-optimized Unpacking Functions");
|
||||
nVifUpkExec->Assign(GetVmMemory().CodeMemory(), HostMemoryMap::VIFUnpackRecOffset, _1mb);
|
||||
xSetPtr(*nVifUpkExec);
|
||||
xSetPtr(SysMemory::GetVIFUnpackRec());
|
||||
|
||||
for (int a = 0; a < 2; a++)
|
||||
for (int b = 0; b < 2; b++)
|
||||
|
@ -392,17 +384,12 @@ void VifUnpackSSE_Init()
|
|||
|
||||
DevCon.WriteLn("Unpack function generation complete. Generated function statistics:");
|
||||
DevCon.Indent().WriteLn(
|
||||
"Reserved buffer : %u bytes @ 0x%016" PRIXPTR "\n"
|
||||
"x86 code generated : %u bytes\n",
|
||||
(uint)nVifUpkExec->GetSize(),
|
||||
nVifUpkExec->GetPtr(),
|
||||
(uint)(xGetPtr() - nVifUpkExec->GetPtr())
|
||||
"Reserved buffer : %zu bytes @ 0x%016" PRIXPTR "\n"
|
||||
"x86 code generated : %zu bytes\n",
|
||||
SysMemory::GetVIFUnpackRecEnd() - SysMemory::GetVIFUnpackRec(),
|
||||
SysMemory::GetVIFUnpackRec(),
|
||||
xGetPtr() - SysMemory::GetVIFUnpackRec()
|
||||
);
|
||||
|
||||
Perf::any.Register(nVifUpkExec->GetPtr(), xGetPtr() - nVifUpkExec->GetPtr(), "VIF Unpack");
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Destroy()
|
||||
{
|
||||
safe_delete(nVifUpkExec);
|
||||
Perf::any.Register(SysMemory::GetVIFUnpackRec(), xGetPtr() - SysMemory::GetVIFUnpackRec(), "VIF Unpack");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue