mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
Merges yaps2/main (github.com/yaps2/yaps2,c16b88cb7) into ARMSX2, replacing the arm64 recompiler family with the yaps2 JITs and importing the yaps2 testing, perf, and libretro infrastructure. Common ancestor is upstream PCSX2342db5152(2026-06-19); git auto-merged all but 38 files. Replaced (deleted in this merge, recoverable from history): - arm64/aR5900*, aR3000A*, aVU* -> arm64/iR5900*/iR3000A*/microVU*-arm64: EE static-pin register file with lazy dirty tracking, dual-residence allocator, IOP block linking, native COP2 macro ops, inline unaligned fastmem, persisted VU program cache, call-ret shadow ring, VU0 spin fast-forward. - MVU_DIFF shadow-run hooks in shared VU interpreter TUs (superseded by the offline vurunner JIT-vs-interp oracle). Imported from yaps2: - tests/ctest/core/recompilers: ~80 gtest suites (EE/IOP/VU differential harnesses, fuzzers, ABI digest tripwire, capture format pins) plus the gs_vertex_tests kernel oracle. - pcsx2-vurunner / pcsx2-eerunner headless capture-replay runners. - tools/perf counter-based A/B rigs, perf jitdump productionization, PmuCounters, clang-perf/clang-handheld presets. - pcsx2-libretro core (ENABLE_LIBRETRO, default OFF; rename pending). - GS vertex-kick fast path (GV series): TBL-based packed parse, register-resident kick, scalar-outcode cull, fused draw-rect/FindMinMax. - Null renderer, VK_KHR_display direct WSI, swapchain PresentStats. - SPU2 NEON mixer vectorization, EE timer read clamp (NFL 2K5 hang), IOP ioman signed-compare fix, assorted UB fixes. Kept from ARMSX2 in the both-touched files: - iOS dual-map W^X and fastmem-unavailable resilience (Memory, HostSys, vtlb). The split data/code area model is retained; both areas now take fixed VA hints so cached VU JIT code stays deterministic on Linux. - Android thread-affinity model, VMState shutdown early-outs, all platform frontends, branding, CI, RetroAchievements identity/policy. - GSDeviceVK: ARMSX2's push-descriptor decision logic (Mali crash gate, proprietary-vs-turnip Adreno split) merged with yaps2's descriptor-pool exhaustion recovery (flush + render-pass restart instead of dropped binds). Vendor feature policy is the union: Mali fbfetch policy with MediaTek/G57/Xclipse gates from ARMSX2; Adreno stencil/ROV/ test-and-sample-depth hang avoidance and no_ps2_z_quantization from yaps2. Build-system notes: - The Qt debugger is now gated behind ENABLE_QT_DEBUGGER (default off on arm64) so handheld builds drop the KDDockWidgets dependency. - GSDeviceNone and remaining yaps2 GS code were ported to the newer upstream GSTexture Usage-flags API. The replaced backend's interpreter-fallback glue (intExecuteOneInst, AndroidEEOpHist) and the EEDiffVerify runtime differ are retained for now; dead pieces will be removed in a follow-up commit.
219 lines
6.1 KiB
C++
219 lines
6.1 KiB
C++
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
|
|
#pragma once
|
|
|
|
#include "common/Pcsx2Defs.h"
|
|
|
|
#include <atomic>
|
|
#include <functional>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
class Error;
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
// PageProtectionMode
|
|
// --------------------------------------------------------------------------------------
|
|
class PageProtectionMode
|
|
{
|
|
protected:
|
|
bool m_read = false;
|
|
bool m_write = false;
|
|
bool m_exec = false;
|
|
|
|
public:
|
|
__fi constexpr PageProtectionMode() = default;
|
|
|
|
__fi constexpr PageProtectionMode& Read(bool allow = true)
|
|
{
|
|
m_read = allow;
|
|
return *this;
|
|
}
|
|
|
|
__fi constexpr PageProtectionMode& Write(bool allow = true)
|
|
{
|
|
m_write = allow;
|
|
return *this;
|
|
}
|
|
|
|
__fi constexpr PageProtectionMode& Execute(bool allow = true)
|
|
{
|
|
m_exec = allow;
|
|
return *this;
|
|
}
|
|
|
|
__fi constexpr PageProtectionMode& All(bool allow = true)
|
|
{
|
|
m_read = m_write = m_exec = allow;
|
|
return *this;
|
|
}
|
|
|
|
__fi constexpr bool CanRead() const { return m_read; }
|
|
__fi constexpr bool CanWrite() const { return m_write; }
|
|
__fi constexpr bool CanExecute() const { return m_exec && m_read; }
|
|
__fi constexpr bool IsNone() const { return !m_read && !m_write; }
|
|
};
|
|
|
|
static __fi PageProtectionMode PageAccess_None()
|
|
{
|
|
return PageProtectionMode();
|
|
}
|
|
|
|
static __fi PageProtectionMode PageAccess_ReadOnly()
|
|
{
|
|
return PageProtectionMode().Read();
|
|
}
|
|
|
|
static __fi PageProtectionMode PageAccess_WriteOnly()
|
|
{
|
|
return PageProtectionMode().Write();
|
|
}
|
|
|
|
static __fi PageProtectionMode PageAccess_ReadWrite()
|
|
{
|
|
return PageAccess_ReadOnly().Write();
|
|
}
|
|
|
|
static __fi PageProtectionMode PageAccess_ExecOnly()
|
|
{
|
|
return PageAccess_ReadOnly().Execute();
|
|
}
|
|
|
|
static __fi PageProtectionMode PageAccess_Any()
|
|
{
|
|
return PageProtectionMode().All();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
// HostSys
|
|
// --------------------------------------------------------------------------------------
|
|
namespace HostSys
|
|
{
|
|
extern void MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode);
|
|
|
|
extern std::string GetFileMappingName(const char* prefix);
|
|
extern void* CreateSharedMemory(const char* name, size_t size);
|
|
extern void DestroySharedMemory(void* ptr);
|
|
|
|
/// JIT write protect for Apple Silicon. Needs to be called prior to writing to any RWX pages.
|
|
#if !defined(__APPLE__) || !defined(ARCH_ARM64)
|
|
// clang-format -off
|
|
[[maybe_unused]] __fi static void BeginCodeWrite() {}
|
|
[[maybe_unused]] __fi static void EndCodeWrite() {}
|
|
[[maybe_unused]] __fi static void BeginCodeWriteRange(void*, size_t) {}
|
|
[[maybe_unused]] __fi static void EndCodeWriteRange(void*, size_t) {}
|
|
// clang-format on
|
|
#else
|
|
void BeginCodeWrite();
|
|
void EndCodeWrite();
|
|
void BeginCodeWriteRange(void* address, size_t size);
|
|
void EndCodeWriteRange(void* address, size_t size);
|
|
#endif
|
|
|
|
/// Flushes the instruction cache on the host for the specified range.
|
|
/// Only needed on ARM64, X86 has coherent D/I cache.
|
|
#ifdef ARCH_X86
|
|
[[maybe_unused]] __fi static void FlushInstructionCache(void* address, u32 size) {}
|
|
#else
|
|
void FlushInstructionCache(void* address, u32 size);
|
|
#endif
|
|
|
|
/// Returns the size of pages for the current host.
|
|
size_t GetRuntimePageSize();
|
|
|
|
/// Returns the size of a cache line for the current host.
|
|
size_t GetRuntimeCacheLineSize();
|
|
} // namespace HostSys
|
|
|
|
namespace PageFaultHandler
|
|
{
|
|
enum class HandlerResult
|
|
{
|
|
ContinueExecution,
|
|
ExecuteNextHandler,
|
|
};
|
|
|
|
HandlerResult HandlePageFault(void* exception_pc, void* fault_address, bool is_write);
|
|
bool Install(Error* error = nullptr);
|
|
bool InstallSecondaryThread();
|
|
} // namespace PageFaultHandler
|
|
|
|
class SharedMemoryMappingArea
|
|
{
|
|
public:
|
|
// fixed_base_hint: when non-zero, the area is placed at that VA (256MB-stride
|
|
// fallback slots, then kernel placement) so the reserved region — and any JIT
|
|
// code mapped inside it — lands at the same address every run, which a caller
|
|
// can rely on for address-stable code caching. Zero = kernel-chosen placement
|
|
// (the default).
|
|
static std::unique_ptr<SharedMemoryMappingArea> Create(size_t size, bool jit = false, uptr fixed_base_hint = 0);
|
|
|
|
~SharedMemoryMappingArea();
|
|
|
|
__fi size_t GetSize() const { return m_size; }
|
|
__fi size_t GetNumPages() const { return m_num_pages; }
|
|
|
|
__fi u8* BasePointer() const { return m_base_ptr; }
|
|
__fi u8* OffsetPointer(size_t offset) const { return m_base_ptr + offset; }
|
|
__fi u8* PagePointer(size_t page) const { return m_base_ptr + __pagesize * page; }
|
|
|
|
u8* Map(void* file_handle, size_t file_offset, void* map_base, size_t map_size, const PageProtectionMode& mode);
|
|
bool Unmap(void* map_base, size_t map_size, bool is_file = true);
|
|
|
|
private:
|
|
SharedMemoryMappingArea(u8* base_ptr, size_t size, size_t num_pages);
|
|
|
|
u8* m_base_ptr;
|
|
size_t m_size;
|
|
size_t m_num_pages;
|
|
size_t m_num_mappings = 0;
|
|
|
|
#ifdef _WIN32
|
|
using PlaceholderMap = std::map<size_t, size_t>;
|
|
|
|
PlaceholderMap::iterator FindPlaceholder(size_t page);
|
|
|
|
PlaceholderMap m_placeholder_ranges;
|
|
#endif
|
|
};
|
|
|
|
extern u64 GetTickFrequency();
|
|
extern u64 GetCPUTicks();
|
|
extern u64 GetPhysicalMemory();
|
|
extern u64 GetAvailablePhysicalMemory();
|
|
/// Spin for a short period of time (call while spinning waiting for a lock)
|
|
/// Returns the approximate number of ns that passed
|
|
extern u32 ShortSpin();
|
|
/// Number of ns to spin for before sleeping a thread
|
|
extern const u32 SPIN_TIME_NS;
|
|
/// Like C abort() but adds the given message to the crashlog
|
|
[[noreturn]] void AbortWithMessage(const char* msg);
|
|
|
|
extern std::string GetOSVersionString();
|
|
|
|
struct CPUInfo {
|
|
std::string name;
|
|
u32 num_big_cores;
|
|
u32 num_small_cores;
|
|
u32 num_threads;
|
|
u32 num_clusters;
|
|
};
|
|
|
|
const CPUInfo& GetCPUInfo();
|
|
|
|
namespace Common
|
|
{
|
|
/// Enables or disables the screen saver from starting.
|
|
bool InhibitScreensaver(bool inhibit);
|
|
|
|
/// Abstracts platform-specific code for asynchronously playing a sound.
|
|
/// On Windows, this will use PlaySound(). On Linux, it will shell out to aplay. On MacOS, it uses NSSound.
|
|
bool PlaySoundAsync(const char* path);
|
|
|
|
void SetMousePosition(int x, int y);
|
|
bool AttachMousePositionCb(std::function<void(int,int)> cb);
|
|
void DetachMousePositionCb();
|
|
} // namespace Common
|