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
|
#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 GetTickFrequency();
|
||||||
extern u64 GetCPUTicks();
|
extern u64 GetCPUTicks();
|
||||||
extern u64 GetPhysicalMemory();
|
extern u64 GetPhysicalMemory();
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#include "pcsx2/GameList.h"
|
#include "pcsx2/GameList.h"
|
||||||
#include "pcsx2/Patch.h"
|
#include "pcsx2/Patch.h"
|
||||||
|
|
||||||
|
#include "common/Assertions.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
GamePatchDetailsWidget::GamePatchDetailsWidget(std::string name, const std::string& author,
|
GamePatchDetailsWidget::GamePatchDetailsWidget(std::string name, const std::string& author,
|
||||||
|
|
|
@ -140,7 +140,6 @@ set(pcsx2Sources
|
||||||
Vif_Codes.cpp
|
Vif_Codes.cpp
|
||||||
Vif_Transfer.cpp
|
Vif_Transfer.cpp
|
||||||
Vif_Unpack.cpp
|
Vif_Unpack.cpp
|
||||||
VirtualMemory.cpp
|
|
||||||
VMManager.cpp
|
VMManager.cpp
|
||||||
vtlb.cpp
|
vtlb.cpp
|
||||||
VU0.cpp
|
VU0.cpp
|
||||||
|
@ -217,7 +216,6 @@ set(pcsx2Headers
|
||||||
Vif_Dma.h
|
Vif_Dma.h
|
||||||
Vif.h
|
Vif.h
|
||||||
Vif_Unpack.h
|
Vif_Unpack.h
|
||||||
VirtualMemory.h
|
|
||||||
VMManager.h
|
VMManager.h
|
||||||
vtlb.h
|
vtlb.h
|
||||||
VUflags.h
|
VUflags.h
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/Assertions.h"
|
||||||
#include "common/StringUtil.h"
|
#include "common/StringUtil.h"
|
||||||
|
|
||||||
// Useful enums for some of the fields.
|
// Useful enums for some of the fields.
|
||||||
|
|
|
@ -17,39 +17,33 @@
|
||||||
#include "GS/Renderers/Common/GSFunctionMap.h"
|
#include "GS/Renderers/Common/GSFunctionMap.h"
|
||||||
#include "System.h"
|
#include "System.h"
|
||||||
|
|
||||||
static GSCodeReserve s_instance;
|
namespace GSCodeReserve
|
||||||
|
|
||||||
GSCodeReserve::GSCodeReserve()
|
|
||||||
: RecompiledCodeReserve("GS Software Renderer")
|
|
||||||
{
|
{
|
||||||
|
static u8* s_memory_base;
|
||||||
|
static u8* s_memory_end;
|
||||||
|
static u8* s_memory_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
GSCodeReserve::~GSCodeReserve() = default;
|
void GSCodeReserve::ResetMemory()
|
||||||
|
|
||||||
GSCodeReserve& GSCodeReserve::GetInstance()
|
|
||||||
{
|
{
|
||||||
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();
|
pxAssert((s_memory_ptr + size) <= s_memory_end);
|
||||||
m_memory_used = 0;
|
return s_memory_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* GSCodeReserve::Reserve(size_t size)
|
void GSCodeReserve::CommitMemory(size_t size)
|
||||||
{
|
{
|
||||||
pxAssert((m_memory_used + size) <= m_size);
|
pxAssert((s_memory_ptr + size) <= s_memory_end);
|
||||||
return m_baseptr + m_memory_used;
|
s_memory_ptr += size;
|
||||||
}
|
|
||||||
|
|
||||||
void GSCodeReserve::Commit(size_t size)
|
|
||||||
{
|
|
||||||
pxAssert((m_memory_used + size) <= m_size);
|
|
||||||
m_memory_used += size;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#include "GS/GSExtra.h"
|
#include "GS/GSExtra.h"
|
||||||
#include "GS/Renderers/SW/GSScanlineEnvironment.h"
|
#include "GS/Renderers/SW/GSScanlineEnvironment.h"
|
||||||
#include "VirtualMemory.h"
|
#include "System.h"
|
||||||
#include "common/emitter/tools.h"
|
#include "common/emitter/tools.h"
|
||||||
|
|
||||||
template <class KEY, class VALUE>
|
template <class KEY, class VALUE>
|
||||||
|
@ -147,25 +147,15 @@ public:
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// Stores code buffers for the GS software JIT.
|
// Stores code buffers for the GS software JIT.
|
||||||
//
|
//
|
||||||
class GSCodeReserve : public RecompiledCodeReserve
|
namespace GSCodeReserve
|
||||||
{
|
{
|
||||||
public:
|
void ResetMemory();
|
||||||
GSCodeReserve();
|
|
||||||
~GSCodeReserve();
|
|
||||||
|
|
||||||
static GSCodeReserve& GetInstance();
|
size_t GetMemoryUsed();
|
||||||
|
|
||||||
size_t GetMemoryUsed() const { return m_memory_used; }
|
u8* ReserveMemory(size_t size);
|
||||||
|
void CommitMemory(size_t size);
|
||||||
void Assign(VirtualMemoryManagerPtr allocator);
|
}
|
||||||
void Reset();
|
|
||||||
|
|
||||||
u8* Reserve(size_t size);
|
|
||||||
void Commit(size_t size);
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t m_memory_used = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class CG, class KEY, class VALUE>
|
template <class CG, class KEY, class VALUE>
|
||||||
class GSCodeGeneratorFunctionMap : public GSFunctionMap<KEY, VALUE>
|
class GSCodeGeneratorFunctionMap : public GSFunctionMap<KEY, VALUE>
|
||||||
|
@ -200,7 +190,7 @@ public:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u8* code_ptr = GSCodeReserve::GetInstance().Reserve(MAX_SIZE);
|
u8* code_ptr = GSCodeReserve::ReserveMemory(MAX_SIZE);
|
||||||
CG cg(key, code_ptr, MAX_SIZE);
|
CG cg(key, code_ptr, MAX_SIZE);
|
||||||
ASSERT(cg.getSize() < MAX_SIZE);
|
ASSERT(cg.getSize() < MAX_SIZE);
|
||||||
|
|
||||||
|
@ -210,7 +200,7 @@ public:
|
||||||
sel.Print();
|
sel.Print();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GSCodeReserve::GetInstance().Commit(cg.getSize());
|
GSCodeReserve::CommitMemory(cg.getSize());
|
||||||
|
|
||||||
ret = (VALUE)cg.getCode();
|
ret = (VALUE)cg.getCode();
|
||||||
|
|
||||||
|
|
|
@ -38,12 +38,12 @@ GSDrawScanline::GSDrawScanline()
|
||||||
: m_sp_map("GSSetupPrim")
|
: m_sp_map("GSSetupPrim")
|
||||||
, m_ds_map("GSDrawScanline")
|
, m_ds_map("GSDrawScanline")
|
||||||
{
|
{
|
||||||
GSCodeReserve::GetInstance().Reset();
|
GSCodeReserve::ResetMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
GSDrawScanline::~GSDrawScanline()
|
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);
|
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.");
|
Console.Warning("GS Software JIT cache overflow, resetting.");
|
||||||
m_sp_map.Clear();
|
m_sp_map.Clear();
|
||||||
m_ds_map.Clear();
|
m_ds_map.Clear();
|
||||||
GSCodeReserve::GetInstance().Reset();
|
GSCodeReserve::ResetMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GSDrawScanline::SetupDraw(GSRasterizerData& data)
|
bool GSDrawScanline::SetupDraw(GSRasterizerData& data)
|
||||||
|
|
28
pcsx2/Hw.cpp
28
pcsx2/Hw.cpp
|
@ -20,7 +20,6 @@
|
||||||
#include "Hardware.h"
|
#include "Hardware.h"
|
||||||
#include "SPU2/spu2.h"
|
#include "SPU2/spu2.h"
|
||||||
#include "USB/USB.h"
|
#include "USB/USB.h"
|
||||||
#include "x86/newVif.h"
|
|
||||||
|
|
||||||
#include "common/WrappedMemCopy.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
|
const int rdram_devices = 2; // put 8 for TOOL and 2 for PS2 and PSX
|
||||||
int rdram_sdevid = 0;
|
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()
|
void hwReset()
|
||||||
{
|
{
|
||||||
hwInit();
|
|
||||||
|
|
||||||
std::memset(eeHw, 0, sizeof(eeHw));
|
std::memset(eeHw, 0, sizeof(eeHw));
|
||||||
|
|
||||||
psHu32(SBUS_F260) = 0x1D000060;
|
psHu32(SBUS_F260) = 0x1D000060;
|
||||||
|
|
|
@ -364,7 +364,6 @@ enum GSRegisterAddresses
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void hwReset();
|
extern void hwReset();
|
||||||
extern void hwShutdown();
|
|
||||||
|
|
||||||
extern const int rdram_devices;
|
extern const int rdram_devices;
|
||||||
extern int rdram_sdevid;
|
extern int rdram_sdevid;
|
||||||
|
|
|
@ -30,35 +30,20 @@ IopVM_MemoryAllocMess* iopMem = NULL;
|
||||||
|
|
||||||
alignas(__pagesize) u8 iopHw[Ps2MemSize::IopHardware];
|
alignas(__pagesize) u8 iopHw[Ps2MemSize::IopHardware];
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
void iopMemAlloc()
|
||||||
// iopMemoryReserve
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
iopMemoryReserve::iopMemoryReserve()
|
|
||||||
: _parent("IOP Main Memory (2mb)")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
iopMemoryReserve::~iopMemoryReserve()
|
|
||||||
{
|
|
||||||
Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
void iopMemoryReserve::Assign(VirtualMemoryManagerPtr allocator)
|
|
||||||
{
|
{
|
||||||
|
// TODO: Move to memmap
|
||||||
psxMemWLUT = (uptr*)_aligned_malloc(0x2000 * sizeof(uptr) * 2, 16);
|
psxMemWLUT = (uptr*)_aligned_malloc(0x2000 * sizeof(uptr) * 2, 16);
|
||||||
if (!psxMemWLUT)
|
if (!psxMemWLUT)
|
||||||
pxFailRel("Failed to allocate IOP memory lookup table");
|
pxFailRel("Failed to allocate IOP memory lookup table");
|
||||||
|
|
||||||
psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
|
psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
|
||||||
|
|
||||||
VtlbMemoryReserve::Assign(std::move(allocator), HostMemoryMap::IOPmemOffset, sizeof(*iopMem));
|
iopMem = reinterpret_cast<IopVM_MemoryAllocMess*>(SysMemory::GetCodePtr(HostMemoryMap::IOPmemOffset));
|
||||||
iopMem = reinterpret_cast<IopVM_MemoryAllocMess*>(GetPtr());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void iopMemoryReserve::Release()
|
void iopMemRelease()
|
||||||
{
|
{
|
||||||
_parent::Release();
|
|
||||||
|
|
||||||
safe_aligned_free(psxMemWLUT);
|
safe_aligned_free(psxMemWLUT);
|
||||||
psxMemRLUT = nullptr;
|
psxMemRLUT = nullptr;
|
||||||
iopMem = 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,
|
// Note! Resetting the IOP's memory state is dependent on having *all* psx memory allocated,
|
||||||
// which is performed by MemInit and PsxMemInit()
|
// which is performed by MemInit and PsxMemInit()
|
||||||
void iopMemoryReserve::Reset()
|
void iopMemReset()
|
||||||
{
|
{
|
||||||
_parent::Reset();
|
|
||||||
|
|
||||||
pxAssert( iopMem );
|
pxAssert( iopMem );
|
||||||
|
|
||||||
DbgCon.WriteLn("IOP resetting main memory...");
|
DbgCon.WriteLn("IOP resetting main memory...");
|
||||||
|
|
|
@ -71,10 +71,9 @@ static __fi u8* iopPhysMem( u32 addr )
|
||||||
#define psxHu16(mem) (*(u16*)&iopHw[(mem) & 0xffff])
|
#define psxHu16(mem) (*(u16*)&iopHw[(mem) & 0xffff])
|
||||||
#define psxHu32(mem) (*(u32*)&iopHw[(mem) & 0xffff])
|
#define psxHu32(mem) (*(u32*)&iopHw[(mem) & 0xffff])
|
||||||
|
|
||||||
extern void psxMemReserve();
|
extern void iopMemAlloc();
|
||||||
extern void psxMemAlloc();
|
extern void iopMemReset();
|
||||||
extern void psxMemReset();
|
extern void iopMemRelease();
|
||||||
extern void psxMemShutdown();
|
|
||||||
|
|
||||||
extern u8 iopMemRead8 (u32 mem);
|
extern u8 iopMemRead8 (u32 mem);
|
||||||
extern u16 iopMemRead16(u32 mem);
|
extern u16 iopMemRead16(u32 mem);
|
||||||
|
|
|
@ -701,28 +701,13 @@ void memBindConditionalHandlers()
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// eeMemoryReserve (implementations)
|
// eeMemoryReserve (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
eeMemoryReserve::eeMemoryReserve()
|
void memAllocate()
|
||||||
: _parent("EE Main Memory")
|
|
||||||
{
|
{
|
||||||
|
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
|
// 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
|
// 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
|
// 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();
|
CopyBIOSToMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
void eeMemoryReserve::Release()
|
void memRelease()
|
||||||
{
|
{
|
||||||
eeMem = nullptr;
|
eeMem = nullptr;
|
||||||
_parent::Release();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,9 @@ static __fi void ZeroQWC( u128& dest )
|
||||||
#define psSu64(mem) (*(u64 *)&eeMem->Scratch[(mem) & 0x3fff])
|
#define psSu64(mem) (*(u64 *)&eeMem->Scratch[(mem) & 0x3fff])
|
||||||
#define psSu128(mem) (*(u128*)&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 memSetKernelMode();
|
||||||
//extern void memSetSupervisorMode();
|
//extern void memSetSupervisorMode();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
/* 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
|
* 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-
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
@ -18,18 +18,19 @@
|
||||||
|
|
||||||
namespace Ps2MemSize
|
namespace Ps2MemSize
|
||||||
{
|
{
|
||||||
static const uint MainRam = _32mb; // 32 MB main memory!
|
static constexpr u32 MainRam = _32mb; // 32 MB main memory.
|
||||||
static const uint Rom = _1mb * 4; // 4 MB main rom
|
static constexpr u32 ExtraRam = _1mb * 96; // 32+96 MB devkit memory.
|
||||||
static const uint Rom1 = _1mb * 4; // DVD player
|
static constexpr u32 Rom = _1mb * 4; // 4 MB main rom
|
||||||
static const uint Rom2 = 0x00080000; // Chinese rom extension
|
static constexpr u32 Rom1 = _1mb * 4; // DVD player
|
||||||
static const uint Hardware = _64kb;
|
static constexpr u32 Rom2 = 0x00080000; // Chinese rom extension
|
||||||
static const uint Scratch = _16kb;
|
static constexpr u32 Hardware = _64kb;
|
||||||
|
static constexpr u32 Scratch = _16kb;
|
||||||
|
|
||||||
static const uint IopRam = _1mb * 2; // 2MB main ram on the IOP.
|
static constexpr u32 IopRam = _1mb * 2; // 2MB main ram on the IOP.
|
||||||
static const uint IopHardware = _64kb;
|
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 u8 mem8_t;
|
||||||
typedef u16 mem16_t;
|
typedef u16 mem16_t;
|
||||||
|
@ -40,6 +41,7 @@ typedef u128 mem128_t;
|
||||||
struct EEVM_MemoryAllocMess
|
struct EEVM_MemoryAllocMess
|
||||||
{
|
{
|
||||||
u8 Main[Ps2MemSize::MainRam]; // Main memory (hard-wired to 32MB)
|
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 Scratch[Ps2MemSize::Scratch]; // Scratchpad!
|
||||||
u8 ROM[Ps2MemSize::Rom]; // Boot rom (4MB)
|
u8 ROM[Ps2MemSize::Rom]; // Boot rom (4MB)
|
||||||
u8 ROM1[Ps2MemSize::Rom1]; // DVD player (4MB)
|
u8 ROM1[Ps2MemSize::Rom1]; // DVD player (4MB)
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#define _PC_ // disables MIPS opcode macros.
|
#define _PC_ // disables MIPS opcode macros.
|
||||||
|
|
||||||
|
#include "common/Assertions.h"
|
||||||
#include "common/ByteSwap.h"
|
#include "common/ByteSwap.h"
|
||||||
#include "common/FileSystem.h"
|
#include "common/FileSystem.h"
|
||||||
#include "common/Path.h"
|
#include "common/Path.h"
|
||||||
|
|
|
@ -207,7 +207,6 @@ extern R3000Acpu psxRec;
|
||||||
extern void psxReset();
|
extern void psxReset();
|
||||||
extern void psxException(u32 code, u32 step);
|
extern void psxException(u32 code, u32 step);
|
||||||
extern void iopEventTest();
|
extern void iopEventTest();
|
||||||
extern void psxMemReset();
|
|
||||||
|
|
||||||
int psxIsBreakpointNeeded(u32 addr);
|
int psxIsBreakpointNeeded(u32 addr);
|
||||||
int psxIsMemcheckNeeded(u32 pc);
|
int psxIsMemcheckNeeded(u32 pc);
|
||||||
|
|
|
@ -67,12 +67,8 @@ const int kMaxArgs = 16;
|
||||||
uptr g_argPtrs[kMaxArgs];
|
uptr g_argPtrs[kMaxArgs];
|
||||||
#define DEBUG_LAUNCHARG 0 // show lots of helpful console messages as the launch arguments are passed to the game
|
#define DEBUG_LAUNCHARG 0 // show lots of helpful console messages as the launch arguments are passed to the game
|
||||||
|
|
||||||
extern SysMainMemory& GetVmMemory();
|
|
||||||
|
|
||||||
void cpuReset()
|
void cpuReset()
|
||||||
{
|
{
|
||||||
GetVmMemory().Reset();
|
|
||||||
|
|
||||||
std::memset(&cpuRegs, 0, sizeof(cpuRegs));
|
std::memset(&cpuRegs, 0, sizeof(cpuRegs));
|
||||||
std::memset(&fpuRegs, 0, sizeof(fpuRegs));
|
std::memset(&fpuRegs, 0, sizeof(fpuRegs));
|
||||||
std::memset(&tlb, 0, sizeof(tlb));
|
std::memset(&tlb, 0, sizeof(tlb));
|
||||||
|
@ -91,8 +87,6 @@ void cpuReset()
|
||||||
psxReset();
|
psxReset();
|
||||||
pgifInit();
|
pgifInit();
|
||||||
|
|
||||||
hwReset();
|
|
||||||
|
|
||||||
extern void Deci2Reset(); // lazy, no good header for it yet.
|
extern void Deci2Reset(); // lazy, no good header for it yet.
|
||||||
Deci2Reset();
|
Deci2Reset();
|
||||||
|
|
||||||
|
|
|
@ -248,48 +248,19 @@ struct R5900cpu
|
||||||
// the virtual cpu provider. Allocating additional heap memory from this method is
|
// the virtual cpu provider. Allocating additional heap memory from this method is
|
||||||
// NOT recommended. Heap allocations should be performed by Reset only. This
|
// NOT recommended. Heap allocations should be performed by Reset only. This
|
||||||
// maximizes the likeliness of reservations claiming addresses they prefer.
|
// 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)();
|
void (*Reserve)();
|
||||||
|
|
||||||
// Deallocates ram allocated by Allocate, Reserve, and/or by runtime code execution.
|
// 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)();
|
void (*Shutdown)();
|
||||||
|
|
||||||
// Initializes / Resets code execution states. Typically implementation is only
|
// Initializes / Resets code execution states. Typically implementation is only
|
||||||
// needed for recompilers, as interpreters have no internal execution states and
|
// needed for recompilers, as interpreters have no internal execution states and
|
||||||
// rely on the CPU/VM states almost entirely.
|
// 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)();
|
void (*Reset)();
|
||||||
|
|
||||||
// Steps a single instruction. Meant to be used by debuggers. Is currently unused
|
// Steps a single instruction. Meant to be used by debuggers. Is currently unused
|
||||||
// and unimplemented. Future note: recompiler "step" should *always* fall back
|
// and unimplemented. Future note: recompiler "step" should *always* fall back
|
||||||
// on interpreters.
|
// on interpreters.
|
||||||
//
|
|
||||||
// Exception Throws: [TODO] (possible execution-related throws to be added)
|
|
||||||
//
|
|
||||||
void (*Step)();
|
void (*Step)();
|
||||||
|
|
||||||
// Executes code until a break is signaled. Execution can be paused or suspended
|
// 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
|
// 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
|
// call to return at the nearest state check (typically handled internally using
|
||||||
// either C++ exceptions or setjmp/longjmp).
|
// 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)();
|
void (*Execute)();
|
||||||
|
|
||||||
// Immediately exits execution of recompiled code if we are in a state to do so, or
|
// 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
|
// 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
|
// 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).
|
// 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);
|
void (*Clear)(u32 Addr, u32 Size);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "SIO/Memcard/MemoryCardFolder.h"
|
#include "SIO/Memcard/MemoryCardFolder.h"
|
||||||
#include "SIO/Sio.h"
|
#include "SIO/Sio.h"
|
||||||
|
|
||||||
|
#include "common/Assertions.h"
|
||||||
#include "common/FileSystem.h"
|
#include "common/FileSystem.h"
|
||||||
#include "common/Path.h"
|
#include "common/Path.h"
|
||||||
#include "common/StringUtil.h"
|
#include "common/StringUtil.h"
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "SIO/Memcard/MemoryCardFile.h"
|
#include "SIO/Memcard/MemoryCardFile.h"
|
||||||
#include "SIO/Memcard/MemoryCardFolder.h"
|
#include "SIO/Memcard/MemoryCardFolder.h"
|
||||||
|
|
||||||
|
#include "common/Assertions.h"
|
||||||
#include "common/Path.h"
|
#include "common/Path.h"
|
||||||
|
|
||||||
#include "System.h"
|
#include "System.h"
|
||||||
|
|
236
pcsx2/System.cpp
236
pcsx2/System.cpp
|
@ -20,6 +20,8 @@
|
||||||
#include "CDVD/CDVD.h"
|
#include "CDVD/CDVD.h"
|
||||||
#include "Elfheader.h"
|
#include "Elfheader.h"
|
||||||
#include "GSDumpReplayer.h"
|
#include "GSDumpReplayer.h"
|
||||||
|
#include "Host.h"
|
||||||
|
#include "IopMem.h"
|
||||||
#include "MTVU.h"
|
#include "MTVU.h"
|
||||||
#include "R3000A.h"
|
#include "R3000A.h"
|
||||||
#include "VUmicro.h"
|
#include "VUmicro.h"
|
||||||
|
@ -44,6 +46,20 @@ SSE_MXCSR g_sseMXCSR = {DEFAULT_sseMXCSR};
|
||||||
SSE_MXCSR g_sseVU0MXCSR = {DEFAULT_sseVUMXCSR};
|
SSE_MXCSR g_sseVU0MXCSR = {DEFAULT_sseVUMXCSR};
|
||||||
SSE_MXCSR g_sseVU1MXCSR = {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.
|
// SetCPUState -- for assignment of SSE roundmodes and clampmodes.
|
||||||
//
|
//
|
||||||
void SetCPUState(SSE_MXCSR sseMXCSR, SSE_MXCSR sseVU0MXCSR, SSE_MXCSR sseVU1MXCSR)
|
void SetCPUState(SSE_MXCSR sseMXCSR, SSE_MXCSR sseVU0MXCSR, SSE_MXCSR sseVU1MXCSR)
|
||||||
|
@ -140,20 +156,55 @@ namespace HostMemoryMap
|
||||||
// For debuggers
|
// For debuggers
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
_declspec(dllexport) uptr EEmem, IOPmem, VUmem, EErec, IOPrec, VIF0rec, VIF1rec, mVU0rec, mVU1rec, SWjit, bumpAllocator;
|
_declspec(dllexport) uptr EEmem, IOPmem, VUmem;
|
||||||
#else
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
} // namespace HostMemoryMap
|
} // namespace HostMemoryMap
|
||||||
|
|
||||||
/// Attempts to find a spot near static variables for the main memory
|
u8* SysMemory::TryAllocateVirtualMemory(const char* name, void* file_handle, uptr base, size_t size)
|
||||||
static VirtualMemoryManagerPtr makeMemoryManager(const char* name, const char* file_mapping_name, size_t size, size_t offset_from_base)
|
|
||||||
{
|
{
|
||||||
|
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.
|
// 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.
|
// 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
|
// 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.
|
// 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)
|
// 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
|
// VTLB will throw a fit if we try to put EE main memory here
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto mgr = std::make_shared<VirtualMemoryManager>(name, file_mapping_name, base, size, /*upper_bounds=*/0, /*strict=*/true);
|
|
||||||
if (mgr->IsOk())
|
if (u8* ret = TryAllocateVirtualMemory(name, file_handle, base, size))
|
||||||
{
|
return ret;
|
||||||
return mgr;
|
|
||||||
}
|
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!
|
return nullptr;
|
||||||
// If it's i386 anything can reach anything so it doesn't matter
|
|
||||||
if (sizeof(void*) == 8)
|
|
||||||
{
|
|
||||||
pxAssertRel(0, "Failed to find a good place for the memory allocation, recompilers may fail");
|
|
||||||
}
|
|
||||||
return std::make_shared<VirtualMemoryManager>(name, file_mapping_name, 0, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
bool SysMemory::AllocateMemoryMap()
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
uptr main_base = (uptr)MainMemory()->GetBase();
|
s_data_memory_file_handle = HostSys::CreateSharedMemory(HostSys::GetFileMappingName("pcsx2").c_str(), HostMemoryMap::MainSize);
|
||||||
uptr code_base = (uptr)MainMemory()->GetBase();
|
if (!s_data_memory_file_handle)
|
||||||
HostMemoryMap::EEmem = main_base + HostMemoryMap::EEmemOffset;
|
{
|
||||||
HostMemoryMap::IOPmem = main_base + HostMemoryMap::IOPmemOffset;
|
Host::ReportErrorAsync("Error", "Failed to create shared memory file.");
|
||||||
HostMemoryMap::VUmem = main_base + HostMemoryMap::VUmemOffset;
|
ReleaseMemoryMap();
|
||||||
HostMemoryMap::EErec = code_base + HostMemoryMap::EErecOffset;
|
return false;
|
||||||
HostMemoryMap::IOPrec = code_base + HostMemoryMap::IOPrecOffset;
|
}
|
||||||
HostMemoryMap::VIF0rec = code_base + HostMemoryMap::VIF0recOffset;
|
|
||||||
HostMemoryMap::VIF1rec = code_base + HostMemoryMap::VIF1recOffset;
|
if ((s_data_memory = AllocateVirtualMemory("Data Memory", s_data_memory_file_handle, HostMemoryMap::MainSize, 0)) == nullptr)
|
||||||
HostMemoryMap::mVU0rec = code_base + HostMemoryMap::mVU0recOffset;
|
{
|
||||||
HostMemoryMap::mVU1rec = code_base + HostMemoryMap::mVU1recOffset;
|
Host::ReportErrorAsync("Error", "Failed to map data memory at an acceptable location.");
|
||||||
HostMemoryMap::bumpAllocator = main_base + HostMemoryMap::bumpAllocatorOffset;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
SysMainMemory::~SysMainMemory()
|
void SysMemory::DumpMemoryMap()
|
||||||
{
|
{
|
||||||
Release();
|
#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
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SysMainMemory::Allocate()
|
void SysMemory::ReleaseMemoryMap()
|
||||||
|
{
|
||||||
|
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 SysMemory::Allocate()
|
||||||
{
|
{
|
||||||
DevCon.WriteLn(Color_StrongBlue, "Allocating host memory for virtual systems...");
|
DevCon.WriteLn(Color_StrongBlue, "Allocating host memory for virtual systems...");
|
||||||
|
|
||||||
ConsoleIndentScope indent(1);
|
ConsoleIndentScope indent(1);
|
||||||
|
|
||||||
m_ee.Assign(MainMemory());
|
if (!AllocateMemoryMap())
|
||||||
m_iop.Assign(MainMemory());
|
return false;
|
||||||
m_vu.Assign(MainMemory());
|
|
||||||
|
|
||||||
vtlb_Core_Alloc();
|
memAllocate();
|
||||||
|
iopMemAlloc();
|
||||||
|
vuMemAllocate();
|
||||||
|
|
||||||
|
if (!vtlb_Core_Alloc())
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysMainMemory::Reset()
|
void SysMemory::Reset()
|
||||||
{
|
{
|
||||||
DevCon.WriteLn(Color_StrongBlue, "Resetting host memory for virtual systems...");
|
DevCon.WriteLn(Color_StrongBlue, "Resetting host memory for virtual systems...");
|
||||||
ConsoleIndentScope indent(1);
|
ConsoleIndentScope indent(1);
|
||||||
|
|
||||||
m_ee.Reset();
|
memReset();
|
||||||
m_iop.Reset();
|
iopMemReset();
|
||||||
m_vu.Reset();
|
vuMemReset();
|
||||||
|
|
||||||
// Note: newVif is reset as part of other VIF structures.
|
// Note: newVif is reset as part of other VIF structures.
|
||||||
// Software is reset on the GS thread.
|
// Software is reset on the GS thread.
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysMainMemory::Release()
|
void SysMemory::Release()
|
||||||
{
|
{
|
||||||
Console.WriteLn(Color_Blue, "Releasing host memory for virtual systems...");
|
Console.WriteLn(Color_Blue, "Releasing host memory for virtual systems...");
|
||||||
ConsoleIndentScope indent(1);
|
ConsoleIndentScope indent(1);
|
||||||
|
|
||||||
hwShutdown();
|
|
||||||
|
|
||||||
vtlb_Core_Free(); // Just to be sure... (calling order could result in it getting missed during Decommit).
|
vtlb_Core_Free(); // Just to be sure... (calling order could result in it getting missed during Decommit).
|
||||||
|
|
||||||
releaseNewVif(0);
|
releaseNewVif(0);
|
||||||
releaseNewVif(1);
|
releaseNewVif(1);
|
||||||
|
|
||||||
m_ee.Release();
|
vuMemRelease();
|
||||||
m_iop.Release();
|
iopMemRelease();
|
||||||
m_vu.Release();
|
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 (implementations)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
SysCpuProviderPack::SysCpuProviderPack()
|
SysCpuProviderPack::SysCpuProviderPack()
|
||||||
{
|
{
|
||||||
Console.WriteLn(Color_StrongBlue, "Reserving memory for recompilers...");
|
|
||||||
ConsoleIndentScope indent(1);
|
|
||||||
|
|
||||||
recCpu.Reserve();
|
recCpu.Reserve();
|
||||||
psxRec.Reserve();
|
psxRec.Reserve();
|
||||||
|
|
||||||
CpuMicroVU0.Reserve();
|
CpuMicroVU0.Reserve();
|
||||||
CpuMicroVU1.Reserve();
|
CpuMicroVU1.Reserve();
|
||||||
|
|
||||||
if constexpr (newVifDynaRec)
|
VifUnpackSSE_Init();
|
||||||
{
|
|
||||||
dVifReserve(0);
|
|
||||||
dVifReserve(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
GSCodeReserve::GetInstance().Assign(GetVmMemory().CodeMemory());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SysCpuProviderPack::~SysCpuProviderPack()
|
SysCpuProviderPack::~SysCpuProviderPack()
|
||||||
{
|
{
|
||||||
GSCodeReserve::GetInstance().Release();
|
|
||||||
|
|
||||||
if (newVifDynaRec)
|
if (newVifDynaRec)
|
||||||
{
|
{
|
||||||
dVifRelease(1);
|
dVifRelease(1);
|
||||||
|
|
137
pcsx2/System.h
137
pcsx2/System.h
|
@ -16,7 +16,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "VirtualMemory.h"
|
|
||||||
#include "vtlb.h"
|
#include "vtlb.h"
|
||||||
|
|
||||||
// This is a table of default virtual map addresses for ps2vm components. These locations
|
// This is a table of default virtual map addresses for ps2vm components. These locations
|
||||||
|
@ -35,85 +34,125 @@ namespace HostMemoryMap
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Main
|
// Main
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
static const u32 MainSize = 0x14000000;
|
|
||||||
|
|
||||||
// PS2 main memory, SPR, and ROMs (approximately 40.5MB, but we round up to 64MB for simplicity).
|
// PS2 main memory, SPR, and ROMs (approximately 138.5MB, but we round up to 139MB for simplicity).
|
||||||
static const u32 EEmemOffset = 0x00000000;
|
static constexpr u32 EEmemOffset = 0x00000000;
|
||||||
|
static constexpr u32 EEmemSize = 0x8B00000;
|
||||||
|
|
||||||
// IOP main memory and ROMs
|
// IOP main memory (2MB + 64K + 256b, rounded up to 3MB for simplicity).
|
||||||
static const u32 IOPmemOffset = 0x04000000;
|
static constexpr u32 IOPmemOffset = EEmemOffset + EEmemSize;
|
||||||
|
static constexpr u32 IOPmemSize = 0x300000;
|
||||||
|
|
||||||
// VU0 and VU1 memory.
|
// VU0 and VU1 memory (40KB, rounded up to 1MB for simplicity).
|
||||||
static const u32 VUmemOffset = 0x08000000;
|
static constexpr u32 VUmemOffset = IOPmemOffset + IOPmemSize;
|
||||||
|
static constexpr u32 VUmemSize = 0x100000;
|
||||||
|
|
||||||
// Bump allocator for any other small allocations
|
// VTLB virtual map ((4GB / 4096) * sizeof(ptr))
|
||||||
// size: Difference between it and HostMemoryMap::Size, so nothing should allocate higher than it!
|
static constexpr u32 VTLBVirtualMapOffset = VUmemOffset + VUmemSize;
|
||||||
static const u32 bumpAllocatorOffset = 0x10000000;
|
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
|
// Code
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
static const u32 CodeSize = 0x13100000; // 305 mb
|
|
||||||
|
|
||||||
// EE recompiler code cache area (64mb)
|
// 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)
|
// 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)
|
// 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)
|
// 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)
|
// 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)
|
// 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)
|
// 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)
|
// Software Renderer JIT buffer (64mb)
|
||||||
static const u32 SWrecOffset = 0x0F100000;
|
static constexpr u32 SWrecOffset = VIFUnpackRecOffset + VIFUnpackRecSize;
|
||||||
static const u32 SWrecSize = 0x04000000;
|
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.
|
// 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();
|
bool Allocate();
|
||||||
void Reset();
|
void Reset();
|
||||||
void Release();
|
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
|
// SysCpuProviderPack
|
||||||
|
@ -134,7 +173,5 @@ extern SysCpuProviderPack& GetCpuProviders();
|
||||||
extern void SysLogMachineCaps(); // Detects cpu type and fills cpuInfo structs.
|
extern void SysLogMachineCaps(); // Detects cpu type and fills cpuInfo structs.
|
||||||
extern void SysClearExecutionCache(); // clears recompiled execution caches!
|
extern void SysClearExecutionCache(); // clears recompiled execution caches!
|
||||||
|
|
||||||
extern SysMainMemory& GetVmMemory();
|
|
||||||
|
|
||||||
extern void SetCPUState(SSE_MXCSR sseMXCSR, SSE_MXCSR sseVU0MXCSR, SSE_MXCSR sseVU1MXCSR);
|
extern void SetCPUState(SSE_MXCSR sseMXCSR, SSE_MXCSR sseVU0MXCSR, SSE_MXCSR sseVU1MXCSR);
|
||||||
extern SSE_MXCSR g_sseVU0MXCSR, g_sseVU1MXCSR, g_sseMXCSR;
|
extern SSE_MXCSR g_sseVU0MXCSR, g_sseVU1MXCSR, g_sseMXCSR;
|
||||||
|
|
|
@ -147,7 +147,6 @@ namespace VMManager
|
||||||
|
|
||||||
static constexpr u32 SETTINGS_VERSION = 1;
|
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<SysCpuProviderPack> s_cpu_provider_pack;
|
||||||
static std::unique_ptr<INISettingsInterface> s_game_settings_interface;
|
static std::unique_ptr<INISettingsInterface> s_game_settings_interface;
|
||||||
static std::unique_ptr<INISettingsInterface> s_input_settings_interface;
|
static std::unique_ptr<INISettingsInterface> s_input_settings_interface;
|
||||||
|
@ -349,15 +348,15 @@ bool VMManager::Internal::CPUThreadInitialize()
|
||||||
x86caps.SIMD_EstablishMXCSRmask();
|
x86caps.SIMD_EstablishMXCSRmask();
|
||||||
SysLogMachineCaps();
|
SysLogMachineCaps();
|
||||||
|
|
||||||
pxAssert(!s_vm_memory && !s_cpu_provider_pack);
|
if (!SysMemory::Allocate())
|
||||||
s_vm_memory = std::make_unique<SysMainMemory>();
|
|
||||||
s_cpu_provider_pack = std::make_unique<SysCpuProviderPack>();
|
|
||||||
if (!s_vm_memory->Allocate())
|
|
||||||
{
|
{
|
||||||
Host::ReportErrorAsync("Error", "Failed to allocate VM memory.");
|
Host::ReportErrorAsync("Error", "Failed to allocate VM memory.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pxAssert(!s_cpu_provider_pack);
|
||||||
|
s_cpu_provider_pack = std::make_unique<SysCpuProviderPack>();
|
||||||
|
|
||||||
GSinit();
|
GSinit();
|
||||||
USBinit();
|
USBinit();
|
||||||
|
|
||||||
|
@ -388,7 +387,6 @@ void VMManager::Internal::CPUThreadShutdown()
|
||||||
WaitForSaveStateFlush();
|
WaitForSaveStateFlush();
|
||||||
|
|
||||||
s_cpu_provider_pack.reset();
|
s_cpu_provider_pack.reset();
|
||||||
s_vm_memory.reset();
|
|
||||||
|
|
||||||
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle());
|
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle());
|
||||||
|
|
||||||
|
@ -397,16 +395,13 @@ void VMManager::Internal::CPUThreadShutdown()
|
||||||
|
|
||||||
MTGS::ShutdownThread();
|
MTGS::ShutdownThread();
|
||||||
|
|
||||||
|
SysMemory::Release();
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SysMainMemory& GetVmMemory()
|
|
||||||
{
|
|
||||||
return *s_vm_memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
SysCpuProviderPack& GetCpuProviders()
|
SysCpuProviderPack& GetCpuProviders()
|
||||||
{
|
{
|
||||||
return *s_cpu_provider_pack;
|
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);
|
SetCPUState(EmuConfig.Cpu.sseMXCSR, EmuConfig.Cpu.sseVU0MXCSR, EmuConfig.Cpu.sseVU1MXCSR);
|
||||||
SysClearExecutionCache();
|
SysClearExecutionCache();
|
||||||
memBindConditionalHandlers();
|
memBindConditionalHandlers();
|
||||||
|
SysMemory::Reset();
|
||||||
cpuReset();
|
cpuReset();
|
||||||
|
hwReset();
|
||||||
|
|
||||||
Console.WriteLn("VM subsystems initialized in %.2f ms", init_timer.GetTimeMilliseconds());
|
Console.WriteLn("VM subsystems initialized in %.2f ms", init_timer.GetTimeMilliseconds());
|
||||||
s_state.store(VMState::Paused, std::memory_order_release);
|
s_state.store(VMState::Paused, std::memory_order_release);
|
||||||
|
@ -1438,7 +1434,9 @@ void VMManager::Reset()
|
||||||
|
|
||||||
SysClearExecutionCache();
|
SysClearExecutionCache();
|
||||||
memBindConditionalHandlers();
|
memBindConditionalHandlers();
|
||||||
|
SysMemory::Reset();
|
||||||
cpuReset();
|
cpuReset();
|
||||||
|
hwReset();
|
||||||
|
|
||||||
if (g_InputRecording.isActive())
|
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::IsVU1() const { return this == &vuRegs[1]; }
|
||||||
inline bool VURegs::IsVU0() const { return this == &vuRegs[0]; }
|
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);
|
extern u32* GET_VU_MEM(VURegs* VU, u32 addr);
|
||||||
|
|
|
@ -21,42 +21,23 @@
|
||||||
|
|
||||||
alignas(16) VURegs vuRegs[2];
|
alignas(16) VURegs vuRegs[2];
|
||||||
|
|
||||||
|
void vuMemAllocate()
|
||||||
vuMemoryReserve::vuMemoryReserve()
|
|
||||||
: _parent("VU0/1 on-chip memory")
|
|
||||||
{
|
{
|
||||||
}
|
u8* curpos = SysMemory::GetDataPtr(HostMemoryMap::VUmemOffset);
|
||||||
|
|
||||||
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();
|
|
||||||
VU0.Micro = curpos; curpos += VU0_PROGSIZE;
|
VU0.Micro = curpos; curpos += VU0_PROGSIZE;
|
||||||
VU0.Mem = curpos; curpos += VU0_MEMSIZE;
|
VU0.Mem = curpos; curpos += VU0_MEMSIZE;
|
||||||
VU1.Micro = curpos; curpos += VU1_PROGSIZE;
|
VU1.Micro = curpos; curpos += VU1_PROGSIZE;
|
||||||
VU1.Mem = curpos; curpos += VU1_MEMSIZE;
|
VU1.Mem = curpos; curpos += VU1_MEMSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vuMemoryReserve::Release()
|
void vuMemRelease()
|
||||||
{
|
{
|
||||||
_parent::Release();
|
|
||||||
|
|
||||||
VU0.Micro = VU0.Mem = nullptr;
|
VU0.Micro = VU0.Mem = nullptr;
|
||||||
VU1.Micro = VU1.Mem = nullptr;
|
VU1.Micro = VU1.Mem = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vuMemoryReserve::Reset()
|
void vuMemReset()
|
||||||
{
|
{
|
||||||
_parent::Reset();
|
|
||||||
|
|
||||||
pxAssert( VU0.Mem );
|
pxAssert( VU0.Mem );
|
||||||
pxAssert( VU1.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-pad\usb-turntable.cpp" />
|
||||||
<ClCompile Include="USB\usb-printer\usb-printer.cpp" />
|
<ClCompile Include="USB\usb-printer\usb-printer.cpp" />
|
||||||
<ClCompile Include="USB\USB.cpp" />
|
<ClCompile Include="USB\USB.cpp" />
|
||||||
<ClCompile Include="VirtualMemory.cpp" />
|
|
||||||
<ClCompile Include="VMManager.cpp" />
|
<ClCompile Include="VMManager.cpp" />
|
||||||
<ClCompile Include="windows\Optimus.cpp" />
|
<ClCompile Include="windows\Optimus.cpp" />
|
||||||
<ClCompile Include="Pcsx2Config.cpp" />
|
<ClCompile Include="Pcsx2Config.cpp" />
|
||||||
|
@ -723,7 +722,6 @@
|
||||||
<ClInclude Include="ps2\HwInternal.h" />
|
<ClInclude Include="ps2\HwInternal.h" />
|
||||||
<ClInclude Include="Cache.h" />
|
<ClInclude Include="Cache.h" />
|
||||||
<ClInclude Include="Memory.h" />
|
<ClInclude Include="Memory.h" />
|
||||||
<ClInclude Include="VirtualMemory.h" />
|
|
||||||
<ClInclude Include="VMManager.h" />
|
<ClInclude Include="VMManager.h" />
|
||||||
<ClInclude Include="vtlb.h" />
|
<ClInclude Include="vtlb.h" />
|
||||||
<ClInclude Include="MTVU.h" />
|
<ClInclude Include="MTVU.h" />
|
||||||
|
|
|
@ -1265,9 +1265,6 @@
|
||||||
<ClCompile Include="GSDumpReplayer.cpp">
|
<ClCompile Include="GSDumpReplayer.cpp">
|
||||||
<Filter>Tools</Filter>
|
<Filter>Tools</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="VirtualMemory.cpp">
|
|
||||||
<Filter>System</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="GS\Renderers\DX11\D3D11ShaderCache.cpp">
|
<ClCompile Include="GS\Renderers\DX11\D3D11ShaderCache.cpp">
|
||||||
<Filter>System\Ps2\GS\Renderers\Direct3D11</Filter>
|
<Filter>System\Ps2\GS\Renderers\Direct3D11</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -2210,9 +2207,6 @@
|
||||||
<ClInclude Include="GS.h">
|
<ClInclude Include="GS.h">
|
||||||
<Filter>System\Ps2\GS\GIF</Filter>
|
<Filter>System\Ps2\GS\GIF</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="VirtualMemory.h">
|
|
||||||
<Filter>System</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="GS\Renderers\DX11\D3D11ShaderCache.h">
|
<ClInclude Include="GS\Renderers\DX11\D3D11ShaderCache.h">
|
||||||
<Filter>System\Ps2\GS\Renderers\Direct3D11</Filter>
|
<Filter>System\Ps2\GS\Renderers\Direct3D11</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -842,7 +842,6 @@ static bool vtlb_IsHostCoalesced(u32 page)
|
||||||
static bool vtlb_GetMainMemoryOffsetFromPtr(uptr ptr, u32* mainmem_offset, u32* mainmem_size, PageProtectionMode* prot)
|
static bool vtlb_GetMainMemoryOffsetFromPtr(uptr ptr, u32* mainmem_offset, u32* mainmem_size, PageProtectionMode* prot)
|
||||||
{
|
{
|
||||||
const uptr page_end = ptr + VTLB_PAGE_SIZE;
|
const uptr page_end = ptr + VTLB_PAGE_SIZE;
|
||||||
SysMainMemory& vmmem = GetVmMemory();
|
|
||||||
|
|
||||||
// EE memory and ROMs.
|
// EE memory and ROMs.
|
||||||
if (ptr >= (uptr)eeMem->Main && page_end <= (uptr)eeMem->ZeroRead)
|
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.
|
// VU memory - this includes both data and code for VU0/VU1.
|
||||||
// Practically speaking, this is only data, because the code goes through a handler.
|
// 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_offset = vumem_offset + HostMemoryMap::VUmemOffset;
|
||||||
*mainmem_size = vmmem.VUMemory().GetSize() - vumem_offset;
|
*mainmem_size = HostMemoryMap::VUmemSize - vumem_offset;
|
||||||
*prot = PageProtectionMode().Read().Write();
|
*prot = PageProtectionMode().Read().Write();
|
||||||
return true;
|
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_page = vtlb_HostPage(page);
|
||||||
const u32 host_offset = vtlb_HostAlignOffset(mainmem_offset);
|
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))
|
s_fastmem_area->PagePointer(host_page), __pagesize, mode))
|
||||||
{
|
{
|
||||||
Console.Error("Failed to map vaddr %08X to mainmem offset %08X", vtlb_HostAlignOffset(vaddr), host_offset);
|
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);
|
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);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1293,34 +1292,19 @@ void vtlb_ResetFastmem()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr size_t VMAP_SIZE = sizeof(VTLBVirtual) * VTLB_VMAP_ITEMS;
|
|
||||||
|
|
||||||
// Reserves the vtlb core allocation used by various emulation components!
|
// Reserves the vtlb core allocation used by various emulation components!
|
||||||
// [TODO] basemem - request allocating memory at the specified virtual location, which can allow
|
// [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
|
// for easier debugging and/or 3rd party cheat programs. If 0, the operating system
|
||||||
// default is used.
|
// default is used.
|
||||||
bool vtlb_Core_Alloc()
|
bool vtlb_Core_Alloc()
|
||||||
{
|
{
|
||||||
// Can't return regions to the bump allocator
|
static constexpr size_t VMAP_SIZE = sizeof(VTLBVirtual) * VTLB_VMAP_ITEMS;
|
||||||
static VTLBVirtual* vmap = nullptr;
|
static_assert(HostMemoryMap::VTLBVirtualMapSize == VMAP_SIZE);
|
||||||
if (!vmap)
|
|
||||||
{
|
|
||||||
vmap = (VTLBVirtual*)GetVmMemory().BumpAllocator().Alloc(VMAP_SIZE);
|
|
||||||
if (!vmap)
|
|
||||||
{
|
|
||||||
Host::ReportErrorAsync("Error", "Failed to allocate vtlb vmap");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vtlbdata.vmap)
|
pxAssert(!vtlbdata.vmap && !vtlbdata.fastmem_base && !s_fastmem_area);
|
||||||
{
|
|
||||||
HostSys::MemProtect(vmap, VMAP_SIZE, PageProtectionMode().Read().Write());
|
vtlbdata.vmap = reinterpret_cast<VTLBVirtual*>(SysMemory::GetVTLBVirtualMap());
|
||||||
vtlbdata.vmap = vmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vtlbdata.fastmem_base)
|
|
||||||
{
|
|
||||||
pxAssert(!s_fastmem_area);
|
pxAssert(!s_fastmem_area);
|
||||||
s_fastmem_area = SharedMemoryMappingArea::Create(FASTMEM_AREA_SIZE);
|
s_fastmem_area = SharedMemoryMappingArea::Create(FASTMEM_AREA_SIZE);
|
||||||
if (!s_fastmem_area)
|
if (!s_fastmem_area)
|
||||||
|
@ -1331,9 +1315,8 @@ bool vtlb_Core_Alloc()
|
||||||
|
|
||||||
s_fastmem_virtual_mapping.resize(FASTMEM_PAGE_COUNT, NO_FASTMEM_MAPPING);
|
s_fastmem_virtual_mapping.resize(FASTMEM_PAGE_COUNT, NO_FASTMEM_MAPPING);
|
||||||
vtlbdata.fastmem_base = (uptr)s_fastmem_area->BasePointer();
|
vtlbdata.fastmem_base = (uptr)s_fastmem_area->BasePointer();
|
||||||
Console.WriteLn(Color_StrongGreen, "Fastmem area: %p - %p",
|
DevCon.WriteLn(Color_StrongGreen, "Fastmem area: %p - %p",
|
||||||
vtlbdata.fastmem_base, vtlbdata.fastmem_base + (FASTMEM_AREA_SIZE - 1));
|
vtlbdata.fastmem_base, vtlbdata.fastmem_base + (FASTMEM_AREA_SIZE - 1));
|
||||||
}
|
|
||||||
|
|
||||||
if (!HostSys::InstallPageFaultHandler(&vtlb_private::PageFaultHandler))
|
if (!HostSys::InstallPageFaultHandler(&vtlb_private::PageFaultHandler))
|
||||||
{
|
{
|
||||||
|
@ -1344,22 +1327,17 @@ bool vtlb_Core_Alloc()
|
||||||
return true;
|
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)
|
// 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.
|
// However automatic gamefix is done after the standard init so a new init function was done.
|
||||||
void vtlb_Alloc_Ppmap()
|
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)
|
if (vtlbdata.ppmap)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
static u32* ppmap = nullptr;
|
vtlbdata.ppmap = reinterpret_cast<u32*>(SysMemory::GetVTLBAddressMap());
|
||||||
|
|
||||||
if (!ppmap)
|
|
||||||
ppmap = (u32*)GetVmMemory().BumpAllocator().Alloc(PPMAP_SIZE);
|
|
||||||
|
|
||||||
HostSys::MemProtect(ppmap, PPMAP_SIZE, PageProtectionMode().Read().Write());
|
|
||||||
vtlbdata.ppmap = ppmap;
|
|
||||||
|
|
||||||
// By default a 1:1 virtual to physical mapping
|
// By default a 1:1 virtual to physical mapping
|
||||||
for (u32 i = 0; i < VTLB_VMAP_ITEMS; i++)
|
for (u32 i = 0; i < VTLB_VMAP_ITEMS; i++)
|
||||||
|
@ -1370,16 +1348,8 @@ void vtlb_Core_Free()
|
||||||
{
|
{
|
||||||
HostSys::RemovePageFaultHandler(&vtlb_private::PageFaultHandler);
|
HostSys::RemovePageFaultHandler(&vtlb_private::PageFaultHandler);
|
||||||
|
|
||||||
if (vtlbdata.vmap)
|
|
||||||
{
|
|
||||||
HostSys::MemProtect(vtlbdata.vmap, VMAP_SIZE, PageProtectionMode());
|
|
||||||
vtlbdata.vmap = nullptr;
|
vtlbdata.vmap = nullptr;
|
||||||
}
|
|
||||||
if (vtlbdata.ppmap)
|
|
||||||
{
|
|
||||||
HostSys::MemProtect(vtlbdata.ppmap, PPMAP_SIZE, PageProtectionMode());
|
|
||||||
vtlbdata.ppmap = nullptr;
|
vtlbdata.ppmap = nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
vtlb_RemoveFastmemMappings();
|
vtlb_RemoveFastmemMappings();
|
||||||
vtlb_ClearLoadStoreInfo();
|
vtlb_ClearLoadStoreInfo();
|
||||||
|
@ -1390,36 +1360,6 @@ void vtlb_Core_Free()
|
||||||
s_fastmem_area.reset();
|
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!
|
// Memory Protection and Block Checking, vtlb Style!
|
||||||
// ===========================================================================================
|
// ===========================================================================================
|
||||||
|
|
66
pcsx2/vtlb.h
66
pcsx2/vtlb.h
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#include "MemoryTypes.h"
|
#include "MemoryTypes.h"
|
||||||
#include "SingleRegisterTypes.h"
|
#include "SingleRegisterTypes.h"
|
||||||
#include "VirtualMemory.h"
|
#include "System.h"
|
||||||
|
|
||||||
static const uptr VTLB_AllocUpperBounds = _1gb * 2;
|
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();
|
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
|
namespace vtlb_private
|
||||||
{
|
{
|
||||||
static const uint VTLB_PAGE_BITS = 12;
|
static const uint VTLB_PAGE_BITS = 12;
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#include "IopBios.h"
|
#include "IopBios.h"
|
||||||
#include "IopHw.h"
|
#include "IopHw.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "VirtualMemory.h"
|
#include "System.h"
|
||||||
#include "VMManager.h"
|
#include "VMManager.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -72,23 +72,22 @@ u32 psxhwLUT[0x10000];
|
||||||
|
|
||||||
static __fi u32 HWADDR(u32 mem) { return psxhwLUT[mem >> 16] + mem; }
|
static __fi u32 HWADDR(u32 mem) { return psxhwLUT[mem >> 16] + mem; }
|
||||||
|
|
||||||
static RecompiledCodeReserve* recMem = NULL;
|
static BASEBLOCK* recRAM = nullptr; // and the ptr to the blocks here
|
||||||
|
static BASEBLOCK* recROM = nullptr; // and here
|
||||||
static BASEBLOCK* recRAM = NULL; // and the ptr to the blocks here
|
static BASEBLOCK* recROM1 = nullptr; // also here
|
||||||
static BASEBLOCK* recROM = NULL; // and here
|
static BASEBLOCK* recROM2 = nullptr; // also here
|
||||||
static BASEBLOCK* recROM1 = NULL; // also here
|
|
||||||
static BASEBLOCK* recROM2 = NULL; // also here
|
|
||||||
static BaseBlocks recBlocks;
|
static BaseBlocks recBlocks;
|
||||||
static u8* recPtr = NULL;
|
static u8* recPtr = nullptr;
|
||||||
|
static u8* recPtrEnd = nullptr;
|
||||||
u32 psxpc; // recompiler psxpc
|
u32 psxpc; // recompiler psxpc
|
||||||
int psxbranch; // set for branch
|
int psxbranch; // set for branch
|
||||||
u32 g_iopCyclePenalty;
|
u32 g_iopCyclePenalty;
|
||||||
|
|
||||||
static EEINST* s_pInstCache = NULL;
|
static EEINST* s_pInstCache = nullptr;
|
||||||
static u32 s_nInstCacheSize = 0;
|
static u32 s_nInstCacheSize = 0;
|
||||||
|
|
||||||
static BASEBLOCK* s_pCurBlock = NULL;
|
static BASEBLOCK* s_pCurBlock = nullptr;
|
||||||
static BASEBLOCKEX* s_pCurBlockEx = NULL;
|
static BASEBLOCKEX* s_pCurBlockEx = nullptr;
|
||||||
|
|
||||||
static u32 s_nEndBlock = 0; // what psxpc the current block ends
|
static u32 s_nEndBlock = 0; // what psxpc the current block ends
|
||||||
static u32 s_branchTo;
|
static u32 s_branchTo;
|
||||||
|
@ -96,7 +95,7 @@ static bool s_nBlockFF;
|
||||||
|
|
||||||
static u32 s_saveConstRegs[32];
|
static u32 s_saveConstRegs[32];
|
||||||
static u32 s_saveHasConstReg = 0, s_saveFlushedConstReg = 0;
|
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
|
u32 s_psxBlockCycles = 0; // cycles of current block recompiling
|
||||||
static u32 s_savenBlockCycles = 0;
|
static u32 s_savenBlockCycles = 0;
|
||||||
|
@ -879,15 +878,9 @@ static const uint m_recBlockAllocSize =
|
||||||
|
|
||||||
static void recReserve()
|
static void recReserve()
|
||||||
{
|
{
|
||||||
if (recMem)
|
recPtr = SysMemory::GetIOPRec();
|
||||||
return;
|
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.
|
// 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
|
// Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
|
||||||
// always 4 bytes long).
|
// always 4 bytes long).
|
||||||
|
@ -910,23 +903,18 @@ static void recAlloc()
|
||||||
recROM2 = (BASEBLOCK*)curpos;
|
recROM2 = (BASEBLOCK*)curpos;
|
||||||
curpos += (Ps2MemSize::Rom2 / 4) * sizeof(BASEBLOCK);
|
curpos += (Ps2MemSize::Rom2 / 4) * sizeof(BASEBLOCK);
|
||||||
|
|
||||||
|
pxAssertRel(!s_pInstCache, "InstCache not allocated");
|
||||||
if (!s_pInstCache)
|
|
||||||
{
|
|
||||||
s_nInstCacheSize = 128;
|
s_nInstCacheSize = 128;
|
||||||
s_pInstCache = (EEINST*)malloc(sizeof(EEINST) * s_nInstCacheSize);
|
s_pInstCache = (EEINST*)malloc(sizeof(EEINST) * s_nInstCacheSize);
|
||||||
if (!s_pInstCache)
|
if (!s_pInstCache)
|
||||||
pxFailRel("Failed to allocate R3000 InstCache array.");
|
pxFailRel("Failed to allocate R3000 InstCache array.");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void recResetIOP()
|
void recResetIOP()
|
||||||
{
|
{
|
||||||
DevCon.WriteLn("iR3000A Recompiler reset.");
|
DevCon.WriteLn("iR3000A Recompiler reset.");
|
||||||
|
|
||||||
recAlloc();
|
xSetPtr(SysMemory::GetIOPRec());
|
||||||
recMem->Reset();
|
|
||||||
xSetPtr(*recMem);
|
|
||||||
_DynGen_Dispatchers();
|
_DynGen_Dispatchers();
|
||||||
recPtr = xGetPtr();
|
recPtr = xGetPtr();
|
||||||
|
|
||||||
|
@ -983,12 +971,13 @@ void recResetIOP()
|
||||||
|
|
||||||
static void recShutdown()
|
static void recShutdown()
|
||||||
{
|
{
|
||||||
safe_delete(recMem);
|
|
||||||
|
|
||||||
safe_aligned_free(m_recBlockAlloc);
|
safe_aligned_free(m_recBlockAlloc);
|
||||||
|
|
||||||
safe_free(s_pInstCache);
|
safe_free(s_pInstCache);
|
||||||
s_nInstCacheSize = 0;
|
s_nInstCacheSize = 0;
|
||||||
|
|
||||||
|
recPtr = nullptr;
|
||||||
|
recPtrEnd = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iopClearRecLUT(BASEBLOCK* base, int count)
|
static void iopClearRecLUT(BASEBLOCK* base, int count)
|
||||||
|
@ -1561,7 +1550,7 @@ static void iopRecRecompile(const u32 startpc)
|
||||||
pxAssert(startpc);
|
pxAssert(startpc);
|
||||||
|
|
||||||
// if recPtr reached the mem limit reset whole mem
|
// if recPtr reached the mem limit reset whole mem
|
||||||
if (recPtr >= (recMem->GetPtrEnd() - _64kb))
|
if (recPtr >= recPtrEnd)
|
||||||
{
|
{
|
||||||
recResetIOP();
|
recResetIOP();
|
||||||
}
|
}
|
||||||
|
@ -1754,7 +1743,7 @@ StartRecomp:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pxAssert(xGetPtr() < recMem->GetPtrEnd());
|
pxAssert(xGetPtr() < recPtrEnd);
|
||||||
|
|
||||||
pxAssert(xGetPtr() - recPtr < _64kb);
|
pxAssert(xGetPtr() - recPtr < _64kb);
|
||||||
s_pCurBlockEx->x86size = xGetPtr() - recPtr;
|
s_pCurBlockEx->x86size = xGetPtr() - recPtr;
|
||||||
|
|
|
@ -22,10 +22,10 @@
|
||||||
#include "GS.h"
|
#include "GS.h"
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "Patch.h"
|
#include "Patch.h"
|
||||||
|
#include "System.h"
|
||||||
#include "R3000A.h"
|
#include "R3000A.h"
|
||||||
#include "R5900OpcodeTables.h"
|
#include "R5900OpcodeTables.h"
|
||||||
#include "VMManager.h"
|
#include "VMManager.h"
|
||||||
#include "VirtualMemory.h"
|
|
||||||
#include "vtlb.h"
|
#include "vtlb.h"
|
||||||
#include "x86/BaseblockEx.h"
|
#include "x86/BaseblockEx.h"
|
||||||
#include "x86/iR5900.h"
|
#include "x86/iR5900.h"
|
||||||
|
@ -83,23 +83,23 @@ eeProfiler EE::Profiler;
|
||||||
|
|
||||||
#define X86
|
#define X86
|
||||||
|
|
||||||
static RecompiledCodeReserve* recMem = NULL;
|
static u8* recRAMCopy = nullptr;
|
||||||
static u8* recRAMCopy = NULL;
|
static u8* recLutReserve_RAM = nullptr;
|
||||||
static u8* recLutReserve_RAM = NULL;
|
|
||||||
static const size_t recLutSize = (Ps2MemSize::MainRam + Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2) * wordsize / 4;
|
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* recRAM = nullptr; // and the ptr to the blocks here
|
||||||
static BASEBLOCK* recROM = NULL; // and here
|
static BASEBLOCK* recROM = nullptr; // and here
|
||||||
static BASEBLOCK* recROM1 = NULL; // also here
|
static BASEBLOCK* recROM1 = nullptr; // also here
|
||||||
static BASEBLOCK* recROM2 = NULL; // also here
|
static BASEBLOCK* recROM2 = nullptr; // also here
|
||||||
|
|
||||||
static BaseBlocks recBlocks;
|
static BaseBlocks recBlocks;
|
||||||
static u8* recPtr = NULL;
|
static u8* recPtr = nullptr;
|
||||||
EEINST* s_pInstCache = NULL;
|
static u8* recPtrEnd = nullptr;
|
||||||
|
EEINST* s_pInstCache = nullptr;
|
||||||
static u32 s_nInstCacheSize = 0;
|
static u32 s_nInstCacheSize = 0;
|
||||||
|
|
||||||
static BASEBLOCK* s_pCurBlock = NULL;
|
static BASEBLOCK* s_pCurBlock = nullptr;
|
||||||
static BASEBLOCKEX* s_pCurBlockEx = NULL;
|
static BASEBLOCKEX* s_pCurBlockEx = nullptr;
|
||||||
u32 s_nEndBlock = 0; // what pc the current block ends
|
u32 s_nEndBlock = 0; // what pc the current block ends
|
||||||
u32 s_branchTo;
|
u32 s_branchTo;
|
||||||
static bool s_nBlockFF;
|
static bool s_nBlockFF;
|
||||||
|
@ -107,7 +107,7 @@ static bool s_nBlockFF;
|
||||||
// save states for branches
|
// save states for branches
|
||||||
GPR_reg64 s_saveConstRegs[32];
|
GPR_reg64 s_saveConstRegs[32];
|
||||||
static u32 s_saveHasConstReg = 0, s_saveFlushedConstReg = 0;
|
static u32 s_saveHasConstReg = 0, s_saveFlushedConstReg = 0;
|
||||||
static EEINST* s_psaveInstInfo = NULL;
|
static EEINST* s_psaveInstInfo = nullptr;
|
||||||
|
|
||||||
static u32 s_savenBlockCycles = 0;
|
static u32 s_savenBlockCycles = 0;
|
||||||
|
|
||||||
|
@ -512,15 +512,9 @@ static __ri void ClearRecLUT(BASEBLOCK* base, int memsize)
|
||||||
|
|
||||||
static void recReserve()
|
static void recReserve()
|
||||||
{
|
{
|
||||||
if (recMem)
|
recPtr = SysMemory::GetEERec();
|
||||||
return;
|
recPtrEnd = SysMemory::GetEERecEnd() - _64kb;
|
||||||
|
|
||||||
recMem = new RecompiledCodeReserve("R5900 Recompiler Cache");
|
|
||||||
recMem->Assign(GetVmMemory().CodeMemory(), HostMemoryMap::EErecOffset, 64 * _1mb);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void recAlloc()
|
|
||||||
{
|
|
||||||
if (!recRAMCopy)
|
if (!recRAMCopy)
|
||||||
{
|
{
|
||||||
recRAMCopy = (u8*)_aligned_malloc(Ps2MemSize::MainRam, 4096);
|
recRAMCopy = (u8*)_aligned_malloc(Ps2MemSize::MainRam, 4096);
|
||||||
|
@ -577,13 +571,11 @@ static void recAlloc()
|
||||||
recLUT_SetPage(recLUT, hwLUT, recROM2, 0xa000, i, i - 0x1e40);
|
recLUT_SetPage(recLUT, hwLUT, recROM2, 0xa000, i, i - 0x1e40);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_pInstCache == NULL)
|
pxAssertRel(!s_pInstCache, "InstCache not allocated");
|
||||||
{
|
|
||||||
s_nInstCacheSize = 128;
|
s_nInstCacheSize = 128;
|
||||||
s_pInstCache = (EEINST*)malloc(sizeof(EEINST) * s_nInstCacheSize);
|
s_pInstCache = (EEINST*)malloc(sizeof(EEINST) * s_nInstCacheSize);
|
||||||
if (!s_pInstCache)
|
if (!s_pInstCache)
|
||||||
pxFailRel("Failed to allocate R5900 InstCache array");
|
pxFailRel("Failed to allocate R5900 InstCache array");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
alignas(16) static u16 manual_page[Ps2MemSize::MainRam >> 12];
|
alignas(16) static u16 manual_page[Ps2MemSize::MainRam >> 12];
|
||||||
|
@ -596,10 +588,7 @@ static void recResetRaw()
|
||||||
|
|
||||||
EE::Profiler.Reset();
|
EE::Profiler.Reset();
|
||||||
|
|
||||||
recAlloc();
|
xSetPtr(SysMemory::GetEERec());
|
||||||
|
|
||||||
recMem->Reset();
|
|
||||||
xSetPtr(*recMem);
|
|
||||||
_DynGen_Dispatchers();
|
_DynGen_Dispatchers();
|
||||||
vtlb_DynGenDispatchers();
|
vtlb_DynGenDispatchers();
|
||||||
recPtr = xGetPtr();
|
recPtr = xGetPtr();
|
||||||
|
@ -620,9 +609,8 @@ static void recResetRaw()
|
||||||
g_resetEeScalingStats = true;
|
g_resetEeScalingStats = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recShutdown()
|
void recShutdown()
|
||||||
{
|
{
|
||||||
safe_delete(recMem);
|
|
||||||
safe_aligned_free(recRAMCopy);
|
safe_aligned_free(recRAMCopy);
|
||||||
safe_aligned_free(recLutReserve_RAM);
|
safe_aligned_free(recLutReserve_RAM);
|
||||||
|
|
||||||
|
@ -632,6 +620,9 @@ static void recShutdown()
|
||||||
|
|
||||||
safe_free(s_pInstCache);
|
safe_free(s_pInstCache);
|
||||||
s_nInstCacheSize = 0;
|
s_nInstCacheSize = 0;
|
||||||
|
|
||||||
|
recPtr = nullptr;
|
||||||
|
recPtrEnd = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void recStep()
|
void recStep()
|
||||||
|
@ -909,7 +900,7 @@ void SetBranchImm(u32 imm)
|
||||||
u8* recBeginThunk()
|
u8* recBeginThunk()
|
||||||
{
|
{
|
||||||
// if recPtr reached the mem limit reset whole mem
|
// if recPtr reached the mem limit reset whole mem
|
||||||
if (recPtr >= (recMem->GetPtrEnd() - _64kb))
|
if (recPtr >= recPtrEnd)
|
||||||
eeRecNeedsReset = true;
|
eeRecNeedsReset = true;
|
||||||
|
|
||||||
xSetPtr(recPtr);
|
xSetPtr(recPtr);
|
||||||
|
@ -923,7 +914,7 @@ u8* recEndThunk()
|
||||||
{
|
{
|
||||||
u8* block_end = x86Ptr;
|
u8* block_end = x86Ptr;
|
||||||
|
|
||||||
pxAssert(block_end < recMem->GetPtrEnd());
|
pxAssert(block_end < recPtrEnd);
|
||||||
recPtr = block_end;
|
recPtr = block_end;
|
||||||
return block_end;
|
return block_end;
|
||||||
}
|
}
|
||||||
|
@ -2208,7 +2199,7 @@ static void recRecompile(const u32 startpc)
|
||||||
pxAssert(startpc);
|
pxAssert(startpc);
|
||||||
|
|
||||||
// if recPtr reached the mem limit reset whole mem
|
// if recPtr reached the mem limit reset whole mem
|
||||||
if (recPtr >= (recMem->GetPtrEnd() - _64kb))
|
if (recPtr >= recPtrEnd)
|
||||||
eeRecNeedsReset = true;
|
eeRecNeedsReset = true;
|
||||||
|
|
||||||
if (HWADDR(startpc) == VMManager::Internal::GetCurrentELFEntryPoint())
|
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);
|
s_pCurBlockEx->x86size = static_cast<u32>(xGetPtr() - recPtr);
|
||||||
|
|
||||||
|
@ -2757,8 +2748,8 @@ StartRecomp:
|
||||||
|
|
||||||
pxAssert((g_cpuHasConstReg & g_cpuFlushedConstReg) == g_cpuHasConstReg);
|
pxAssert((g_cpuHasConstReg & g_cpuFlushedConstReg) == g_cpuHasConstReg);
|
||||||
|
|
||||||
s_pCurBlock = NULL;
|
s_pCurBlock = nullptr;
|
||||||
s_pCurBlockEx = NULL;
|
s_pCurBlockEx = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
R5900cpu recCpu = {
|
R5900cpu recCpu = {
|
||||||
|
|
|
@ -26,15 +26,6 @@
|
||||||
// Micro VU - Main Functions
|
// 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! ;)
|
// Only run this once per VU! ;)
|
||||||
void mVUinit(microVU& mVU, uint vuIndex)
|
void mVUinit(microVU& mVU, uint vuIndex)
|
||||||
{
|
{
|
||||||
|
@ -46,12 +37,8 @@ void mVUinit(microVU& mVU, uint vuIndex)
|
||||||
mVU.microMemSize = (mVU.index ? 0x4000 : 0x1000);
|
mVU.microMemSize = (mVU.index ? 0x4000 : 0x1000);
|
||||||
mVU.progSize = (mVU.index ? 0x4000 : 0x1000) / 4;
|
mVU.progSize = (mVU.index ? 0x4000 : 0x1000) / 4;
|
||||||
mVU.progMemMask = mVU.progSize-1;
|
mVU.progMemMask = mVU.progSize-1;
|
||||||
mVU.cacheSize = mVUcacheReserve;
|
mVU.cache = vuIndex ? SysMemory::GetVU1Rec() : SysMemory::GetVU0Rec();
|
||||||
mVU.cache = nullptr;
|
mVU.prog.x86end = (vuIndex ? SysMemory::GetVU1RecEnd() : SysMemory::GetVU0RecEnd()) - (mVUcacheSafeZone * _1mb);
|
||||||
mVU.startFunct = nullptr;
|
|
||||||
mVU.exitFunct = nullptr;
|
|
||||||
|
|
||||||
mVUreserveCache(mVU);
|
|
||||||
|
|
||||||
mVU.regAlloc.reset(new microRegAlloc(mVU.index));
|
mVU.regAlloc.reset(new microRegAlloc(mVU.index));
|
||||||
}
|
}
|
||||||
|
@ -59,7 +46,6 @@ void mVUinit(microVU& mVU, uint vuIndex)
|
||||||
// Resets Rec Data
|
// Resets Rec Data
|
||||||
void mVUreset(microVU& mVU, bool resetReserve)
|
void mVUreset(microVU& mVU, bool resetReserve)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (THREAD_VU1)
|
if (THREAD_VU1)
|
||||||
{
|
{
|
||||||
DevCon.Warning("mVU Reset");
|
DevCon.Warning("mVU Reset");
|
||||||
|
@ -70,9 +56,6 @@ void mVUreset(microVU& mVU, bool resetReserve)
|
||||||
}
|
}
|
||||||
VU0.VI[REG_VPU_STAT].UL &= ~0x100;
|
VU0.VI[REG_VPU_STAT].UL &= ~0x100;
|
||||||
}
|
}
|
||||||
// Restore reserve to uncommitted state
|
|
||||||
if (resetReserve)
|
|
||||||
mVU.cache_reserve->Reset();
|
|
||||||
|
|
||||||
xSetPtr(mVU.cache);
|
xSetPtr(mVU.cache);
|
||||||
mVUdispatcherAB(mVU);
|
mVUdispatcherAB(mVU);
|
||||||
|
@ -95,7 +78,6 @@ void mVUreset(microVU& mVU, bool resetReserve)
|
||||||
// Setup Dynarec Cache Limits for Each Program
|
// Setup Dynarec Cache Limits for Each Program
|
||||||
mVU.prog.x86start = xGetAlignedCallTarget();
|
mVU.prog.x86start = xGetAlignedCallTarget();
|
||||||
mVU.prog.x86ptr = mVU.prog.x86start;
|
mVU.prog.x86ptr = mVU.prog.x86start;
|
||||||
mVU.prog.x86end = mVU.cache + ((mVU.cacheSize - mVUcacheSafeZone) * _1mb);
|
|
||||||
|
|
||||||
for (u32 i = 0; i < (mVU.progSize / 2); i++)
|
for (u32 i = 0; i < (mVU.progSize / 2); i++)
|
||||||
{
|
{
|
||||||
|
@ -118,9 +100,6 @@ void mVUreset(microVU& mVU, bool resetReserve)
|
||||||
// Free Allocated Resources
|
// Free Allocated Resources
|
||||||
void mVUclose(microVU& mVU)
|
void mVUclose(microVU& mVU)
|
||||||
{
|
{
|
||||||
|
|
||||||
safe_delete(mVU.cache_reserve);
|
|
||||||
|
|
||||||
// Delete Programs and Block Managers
|
// Delete Programs and Block Managers
|
||||||
for (u32 i = 0; i < (mVU.progSize / 2); i++)
|
for (u32 i = 0; i < (mVU.progSize / 2); i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,7 +30,7 @@ using namespace x86Emitter;
|
||||||
#include "Gif_Unit.h"
|
#include "Gif_Unit.h"
|
||||||
#include "iR5900.h"
|
#include "iR5900.h"
|
||||||
#include "R5900OpcodeTables.h"
|
#include "R5900OpcodeTables.h"
|
||||||
#include "VirtualMemory.h"
|
#include "System.h"
|
||||||
#include "common/emitter/x86emitter.h"
|
#include "common/emitter/x86emitter.h"
|
||||||
#include "microVU_Misc.h"
|
#include "microVU_Misc.h"
|
||||||
#include "microVU_IR.h"
|
#include "microVU_IR.h"
|
||||||
|
@ -91,9 +91,7 @@ struct microProgManager
|
||||||
microRegInfo lpState; // Pipeline state from where program left off (useful for continuing execution)
|
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 mVUcacheSafeZone = 3; // Safe-Zone for program recompilation (in megabytes)
|
||||||
static const uint mVUcacheReserve = 64; // mVU0, mVU1 Reserve Cache Size (in megabytes)
|
|
||||||
|
|
||||||
struct microVU
|
struct microVU
|
||||||
{
|
{
|
||||||
|
@ -117,7 +115,6 @@ struct microVU
|
||||||
std::unique_ptr<microRegAlloc> regAlloc; // Reg Alloc Class
|
std::unique_ptr<microRegAlloc> regAlloc; // Reg Alloc Class
|
||||||
std::FILE* logFile; // Log File Pointer
|
std::FILE* logFile; // Log File Pointer
|
||||||
|
|
||||||
RecompiledCodeReserve* cache_reserve;
|
|
||||||
u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to)
|
u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to)
|
||||||
u8* startFunct; // Function Ptr to the recompiler dispatcher (start)
|
u8* startFunct; // Function Ptr to the recompiler dispatcher (start)
|
||||||
u8* exitFunct; // Function Ptr to the recompiler dispatcher (exit)
|
u8* exitFunct; // Function Ptr to the recompiler dispatcher (exit)
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
#include "Vif.h"
|
#include "Vif.h"
|
||||||
#include "VU.h"
|
#include "VU.h"
|
||||||
#include "VirtualMemory.h"
|
|
||||||
|
|
||||||
#include "common/emitter/x86emitter.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 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 mVUsaveReg(const xRegisterSSE& reg, xAddressVoid ptr, int xyzw, bool modXYZW);
|
||||||
extern void _nVifUnpack (int idx, const u8* data, uint mode, bool isFill);
|
extern void _nVifUnpack (int idx, const u8* data, uint mode, bool isFill);
|
||||||
extern void dVifReserve (int idx);
|
|
||||||
extern void dVifReset (int idx);
|
extern void dVifReset (int idx);
|
||||||
extern void dVifClose (int idx);
|
extern void dVifClose (int idx);
|
||||||
extern void dVifRelease (int idx);
|
extern void dVifRelease (int idx);
|
||||||
extern void VifUnpackSSE_Init();
|
extern void VifUnpackSSE_Init();
|
||||||
extern void VifUnpackSSE_Destroy();
|
|
||||||
|
|
||||||
_vifT extern void dVifUnpack(const u8* data, bool isFill);
|
_vifT extern void dVifUnpack(const u8* data, bool isFill);
|
||||||
|
|
||||||
|
@ -64,8 +61,8 @@ struct nVifStruct
|
||||||
// (templates are used for most or all VIF indexing)
|
// (templates are used for most or all VIF indexing)
|
||||||
u32 idx;
|
u32 idx;
|
||||||
|
|
||||||
RecompiledCodeReserve* recReserve;
|
|
||||||
u8* recWritePtr; // current write pos into the reserve
|
u8* recWritePtr; // current write pos into the reserve
|
||||||
|
u8* recEndPtr;
|
||||||
|
|
||||||
HashBucket vifBlocks; // Vif Blocks
|
HashBucket vifBlocks; // Vif Blocks
|
||||||
|
|
||||||
|
|
|
@ -24,42 +24,19 @@
|
||||||
#include "common/StringUtil.h"
|
#include "common/StringUtil.h"
|
||||||
#include "fmt/core.h"
|
#include "fmt/core.h"
|
||||||
|
|
||||||
static void recReset(int idx)
|
void dVifReset(int idx)
|
||||||
{
|
{
|
||||||
nVif[idx].vifBlocks.reset();
|
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;
|
const size_t offset = idx ? HostMemoryMap::VIF1recOffset : HostMemoryMap::VIF0recOffset;
|
||||||
nVif[idx].recReserve = new RecompiledCodeReserve(StringUtil::StdStringFromFormat("VIF%u Unpack Recompiler Cache", idx));
|
const size_t size = idx ? HostMemoryMap::VIF1recSize : HostMemoryMap::VIF0recSize;
|
||||||
nVif[idx].recReserve->Assign(GetVmMemory().CodeMemory(), offset, 8 * _1mb);
|
nVif[idx].recWritePtr = SysMemory::GetCodePtr(offset);
|
||||||
}
|
nVif[idx].recEndPtr = nVif[idx].recWritePtr + (size - _256kb);
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dVifRelease(int idx)
|
void dVifRelease(int idx)
|
||||||
{
|
{
|
||||||
dVifClose(idx);
|
nVif[idx].vifBlocks.clear();
|
||||||
safe_delete(nVif[idx].recReserve);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VifUnpackSSE_Dynarec::VifUnpackSSE_Dynarec(const nVifStruct& vif_, const nVifBlock& vifBlock_)
|
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];
|
nVifStruct& v = nVif[idx];
|
||||||
|
|
||||||
// Check size before the compilation
|
// 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 "]",
|
DevCon.WriteLn("nVif Recompiler Cache Reset! [0x%016" PRIXPTR " > 0x%016" PRIXPTR "]",
|
||||||
v.recWritePtr, v.recReserve->GetPtrEnd());
|
v.recWritePtr, v.recEndPtr);
|
||||||
recReset(idx);
|
dVifReset(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile the block now
|
// Compile the block now
|
||||||
|
|
|
@ -24,9 +24,6 @@
|
||||||
#define xMOV64(regX, loc) xMOVUPS (regX, loc)
|
#define xMOV64(regX, loc) xMOVUPS (regX, loc)
|
||||||
#define xMOV128(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
|
// VifUnpackSSE_Base Section
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
|
@ -376,14 +373,9 @@ static void nVifGen(int usn, int mask, int curCycle)
|
||||||
|
|
||||||
void VifUnpackSSE_Init()
|
void VifUnpackSSE_Init()
|
||||||
{
|
{
|
||||||
if (nVifUpkExec)
|
|
||||||
return;
|
|
||||||
|
|
||||||
DevCon.WriteLn("Generating SSE-optimized unpacking functions for VIF interpreters...");
|
DevCon.WriteLn("Generating SSE-optimized unpacking functions for VIF interpreters...");
|
||||||
|
|
||||||
nVifUpkExec = new RecompiledCodeReserve("VIF SSE-optimized Unpacking Functions");
|
xSetPtr(SysMemory::GetVIFUnpackRec());
|
||||||
nVifUpkExec->Assign(GetVmMemory().CodeMemory(), HostMemoryMap::VIFUnpackRecOffset, _1mb);
|
|
||||||
xSetPtr(*nVifUpkExec);
|
|
||||||
|
|
||||||
for (int a = 0; a < 2; a++)
|
for (int a = 0; a < 2; a++)
|
||||||
for (int b = 0; b < 2; b++)
|
for (int b = 0; b < 2; b++)
|
||||||
|
@ -392,17 +384,12 @@ void VifUnpackSSE_Init()
|
||||||
|
|
||||||
DevCon.WriteLn("Unpack function generation complete. Generated function statistics:");
|
DevCon.WriteLn("Unpack function generation complete. Generated function statistics:");
|
||||||
DevCon.Indent().WriteLn(
|
DevCon.Indent().WriteLn(
|
||||||
"Reserved buffer : %u bytes @ 0x%016" PRIXPTR "\n"
|
"Reserved buffer : %zu bytes @ 0x%016" PRIXPTR "\n"
|
||||||
"x86 code generated : %u bytes\n",
|
"x86 code generated : %zu bytes\n",
|
||||||
(uint)nVifUpkExec->GetSize(),
|
SysMemory::GetVIFUnpackRecEnd() - SysMemory::GetVIFUnpackRec(),
|
||||||
nVifUpkExec->GetPtr(),
|
SysMemory::GetVIFUnpackRec(),
|
||||||
(uint)(xGetPtr() - nVifUpkExec->GetPtr())
|
xGetPtr() - SysMemory::GetVIFUnpackRec()
|
||||||
);
|
);
|
||||||
|
|
||||||
Perf::any.Register(nVifUpkExec->GetPtr(), xGetPtr() - nVifUpkExec->GetPtr(), "VIF Unpack");
|
Perf::any.Register(SysMemory::GetVIFUnpackRec(), xGetPtr() - SysMemory::GetVIFUnpackRec(), "VIF Unpack");
|
||||||
}
|
|
||||||
|
|
||||||
void VifUnpackSSE_Destroy()
|
|
||||||
{
|
|
||||||
safe_delete(nVifUpkExec);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue