mirror of
https://github.com/stenzek/duckstation.git
synced 2024-11-22 21:39:40 +00:00
CPU/Recompiler: Tidy up type names
And reduce global namespace pollution.
This commit is contained in:
parent
6cb5aa9ab4
commit
7e23a23536
@ -129,8 +129,6 @@ add_library(core
|
||||
set(RECOMPILER_SRCS
|
||||
cpu_recompiler.cpp
|
||||
cpu_recompiler.h
|
||||
cpu_recompiler_thunks.h
|
||||
cpu_recompiler_types.h
|
||||
)
|
||||
|
||||
target_precompile_headers(core PRIVATE "pch.h")
|
||||
|
@ -106,8 +106,6 @@
|
||||
<ClInclude Include="cpu_recompiler_x64.h">
|
||||
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cpu_recompiler_thunks.h" />
|
||||
<ClInclude Include="cpu_recompiler_types.h" />
|
||||
<ClInclude Include="digital_controller.h" />
|
||||
<ClInclude Include="fullscreen_ui.h" />
|
||||
<ClInclude Include="game_database.h" />
|
||||
|
@ -90,9 +90,7 @@
|
||||
<ClInclude Include="gpu_sw.h" />
|
||||
<ClInclude Include="gpu_hw_shadergen.h" />
|
||||
<ClInclude Include="bios.h" />
|
||||
<ClInclude Include="cpu_recompiler_types.h" />
|
||||
<ClInclude Include="cpu_code_cache.h" />
|
||||
<ClInclude Include="cpu_recompiler_thunks.h" />
|
||||
<ClInclude Include="sio.h" />
|
||||
<ClInclude Include="controller.h" />
|
||||
<ClInclude Include="analog_controller.h" />
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "cpu_core.h"
|
||||
#include "cpu_core_private.h"
|
||||
#include "cpu_disasm.h"
|
||||
#include "cpu_recompiler_types.h"
|
||||
#include "host.h"
|
||||
#include "settings.h"
|
||||
#include "system.h"
|
||||
@ -1564,7 +1563,7 @@ bool CPU::CodeCache::CompileBlock(Block* block)
|
||||
|
||||
#ifdef ENABLE_RECOMPILER
|
||||
if (g_settings.cpu_execution_mode == CPUExecutionMode::Recompiler)
|
||||
host_code = Recompiler::g_compiler->CompileBlock(block, &host_code_size, &host_far_code_size);
|
||||
host_code = g_compiler->CompileBlock(block, &host_code_size, &host_far_code_size);
|
||||
#endif
|
||||
|
||||
block->host_code = host_code;
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "cpu_core_private.h"
|
||||
#include "cpu_disasm.h"
|
||||
#include "cpu_pgxp.h"
|
||||
#include "cpu_recompiler_thunks.h"
|
||||
#include "gte.h"
|
||||
#include "host.h"
|
||||
#include "pcdrv.h"
|
||||
@ -2628,13 +2627,13 @@ template void CPU::CodeCache::InterpretUncachedBlock<PGXPMode::Disabled>();
|
||||
template void CPU::CodeCache::InterpretUncachedBlock<PGXPMode::Memory>();
|
||||
template void CPU::CodeCache::InterpretUncachedBlock<PGXPMode::CPU>();
|
||||
|
||||
bool CPU::Recompiler::Thunks::InterpretInstruction()
|
||||
bool CPU::RecompilerThunks::InterpretInstruction()
|
||||
{
|
||||
ExecuteInstruction<PGXPMode::Disabled, false>();
|
||||
return g_state.exception_raised;
|
||||
}
|
||||
|
||||
bool CPU::Recompiler::Thunks::InterpretInstructionPGXP()
|
||||
bool CPU::RecompilerThunks::InterpretInstructionPGXP()
|
||||
{
|
||||
ExecuteInstruction<PGXPMode::Memory, false>();
|
||||
return g_state.exception_raised;
|
||||
@ -3477,7 +3476,7 @@ bool CPU::WriteMemoryWord(VirtualMemoryAddress addr, u32 value)
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 CPU::Recompiler::Thunks::ReadMemoryByte(u32 address)
|
||||
u64 CPU::RecompilerThunks::ReadMemoryByte(u32 address)
|
||||
{
|
||||
const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::Byte)(address);
|
||||
if (g_state.bus_error) [[unlikely]]
|
||||
@ -3490,7 +3489,7 @@ u64 CPU::Recompiler::Thunks::ReadMemoryByte(u32 address)
|
||||
return ZeroExtend64(value);
|
||||
}
|
||||
|
||||
u64 CPU::Recompiler::Thunks::ReadMemoryHalfWord(u32 address)
|
||||
u64 CPU::RecompilerThunks::ReadMemoryHalfWord(u32 address)
|
||||
{
|
||||
if (!Common::IsAlignedPow2(address, 2)) [[unlikely]]
|
||||
{
|
||||
@ -3509,7 +3508,7 @@ u64 CPU::Recompiler::Thunks::ReadMemoryHalfWord(u32 address)
|
||||
return ZeroExtend64(value);
|
||||
}
|
||||
|
||||
u64 CPU::Recompiler::Thunks::ReadMemoryWord(u32 address)
|
||||
u64 CPU::RecompilerThunks::ReadMemoryWord(u32 address)
|
||||
{
|
||||
if (!Common::IsAlignedPow2(address, 4)) [[unlikely]]
|
||||
{
|
||||
@ -3528,7 +3527,7 @@ u64 CPU::Recompiler::Thunks::ReadMemoryWord(u32 address)
|
||||
return ZeroExtend64(value);
|
||||
}
|
||||
|
||||
u32 CPU::Recompiler::Thunks::WriteMemoryByte(u32 address, u32 value)
|
||||
u32 CPU::RecompilerThunks::WriteMemoryByte(u32 address, u32 value)
|
||||
{
|
||||
MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Byte, address, value);
|
||||
|
||||
@ -3542,7 +3541,7 @@ u32 CPU::Recompiler::Thunks::WriteMemoryByte(u32 address, u32 value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 CPU::Recompiler::Thunks::WriteMemoryHalfWord(u32 address, u32 value)
|
||||
u32 CPU::RecompilerThunks::WriteMemoryHalfWord(u32 address, u32 value)
|
||||
{
|
||||
MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::HalfWord, address, value);
|
||||
|
||||
@ -3562,7 +3561,7 @@ u32 CPU::Recompiler::Thunks::WriteMemoryHalfWord(u32 address, u32 value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 CPU::Recompiler::Thunks::WriteMemoryWord(u32 address, u32 value)
|
||||
u32 CPU::RecompilerThunks::WriteMemoryWord(u32 address, u32 value)
|
||||
{
|
||||
MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Word, address, value);
|
||||
|
||||
@ -3582,40 +3581,40 @@ u32 CPU::Recompiler::Thunks::WriteMemoryWord(u32 address, u32 value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 CPU::Recompiler::Thunks::UncheckedReadMemoryByte(u32 address)
|
||||
u32 CPU::RecompilerThunks::UncheckedReadMemoryByte(u32 address)
|
||||
{
|
||||
const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::Byte)(address);
|
||||
MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::Byte, address, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
u32 CPU::Recompiler::Thunks::UncheckedReadMemoryHalfWord(u32 address)
|
||||
u32 CPU::RecompilerThunks::UncheckedReadMemoryHalfWord(u32 address)
|
||||
{
|
||||
const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::HalfWord)(address);
|
||||
MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::HalfWord, address, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
u32 CPU::Recompiler::Thunks::UncheckedReadMemoryWord(u32 address)
|
||||
u32 CPU::RecompilerThunks::UncheckedReadMemoryWord(u32 address)
|
||||
{
|
||||
const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::Word)(address);
|
||||
MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::Word, address, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void CPU::Recompiler::Thunks::UncheckedWriteMemoryByte(u32 address, u32 value)
|
||||
void CPU::RecompilerThunks::UncheckedWriteMemoryByte(u32 address, u32 value)
|
||||
{
|
||||
MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Byte, address, value);
|
||||
GetMemoryWriteHandler(address, MemoryAccessSize::Byte)(address, value);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::Thunks::UncheckedWriteMemoryHalfWord(u32 address, u32 value)
|
||||
void CPU::RecompilerThunks::UncheckedWriteMemoryHalfWord(u32 address, u32 value)
|
||||
{
|
||||
MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::HalfWord, address, value);
|
||||
GetMemoryWriteHandler(address, MemoryAccessSize::HalfWord)(address, value);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::Thunks::UncheckedWriteMemoryWord(u32 address, u32 value)
|
||||
void CPU::RecompilerThunks::UncheckedWriteMemoryWord(u32 address, u32 value)
|
||||
{
|
||||
MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Word, address, value);
|
||||
GetMemoryWriteHandler(address, MemoryAccessSize::Word)(address, value);
|
||||
|
@ -132,4 +132,36 @@ ALWAYS_INLINE static void StallUntilGTEComplete()
|
||||
void HandleA0Syscall();
|
||||
void HandleB0Syscall();
|
||||
|
||||
#ifdef ENABLE_RECOMPILER
|
||||
|
||||
namespace RecompilerThunks {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Trampolines for calling back from the JIT
|
||||
// Needed because we can't cast member functions to void*...
|
||||
// TODO: Abuse carry flag or something else for exception
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool InterpretInstruction();
|
||||
bool InterpretInstructionPGXP();
|
||||
|
||||
// Memory access functions for the JIT - MSB is set on exception.
|
||||
u64 ReadMemoryByte(u32 address);
|
||||
u64 ReadMemoryHalfWord(u32 address);
|
||||
u64 ReadMemoryWord(u32 address);
|
||||
u32 WriteMemoryByte(u32 address, u32 value);
|
||||
u32 WriteMemoryHalfWord(u32 address, u32 value);
|
||||
u32 WriteMemoryWord(u32 address, u32 value);
|
||||
|
||||
// Unchecked memory access variants. No alignment or bus exceptions.
|
||||
u32 UncheckedReadMemoryByte(u32 address);
|
||||
u32 UncheckedReadMemoryHalfWord(u32 address);
|
||||
u32 UncheckedReadMemoryWord(u32 address);
|
||||
void UncheckedWriteMemoryByte(u32 address, u32 value);
|
||||
void UncheckedWriteMemoryHalfWord(u32 address, u32 value);
|
||||
void UncheckedWriteMemoryWord(u32 address, u32 value);
|
||||
|
||||
} // namespace RecompilerThunks
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace CPU
|
@ -4,7 +4,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "cpu_code_cache_private.h"
|
||||
#include "cpu_recompiler_types.h"
|
||||
#include "cpu_types.h"
|
||||
|
||||
#include <array>
|
||||
@ -13,36 +12,72 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace CPU::Recompiler {
|
||||
|
||||
// Global options
|
||||
static constexpr bool EMULATE_LOAD_DELAYS = true;
|
||||
static constexpr bool SWAP_BRANCH_DELAY_SLOTS = true;
|
||||
|
||||
// Arch-specific options
|
||||
#if defined(CPU_ARCH_X64)
|
||||
static constexpr u32 NUM_HOST_REGS = 16;
|
||||
static constexpr bool HAS_MEMORY_OPERANDS = true;
|
||||
#elif defined(CPU_ARCH_ARM32)
|
||||
static constexpr u32 NUM_HOST_REGS = 16;
|
||||
static constexpr bool HAS_MEMORY_OPERANDS = false;
|
||||
#elif defined(CPU_ARCH_ARM64)
|
||||
static constexpr u32 NUM_HOST_REGS = 32;
|
||||
static constexpr bool HAS_MEMORY_OPERANDS = false;
|
||||
#elif defined(CPU_ARCH_RISCV64)
|
||||
static constexpr u32 NUM_HOST_REGS = 32;
|
||||
static constexpr bool HAS_MEMORY_OPERANDS = false;
|
||||
#endif
|
||||
namespace CPU {
|
||||
|
||||
// TODO: Get rid of the virtuals... somehow.
|
||||
class Recompiler
|
||||
{
|
||||
public:
|
||||
// Global options
|
||||
static constexpr bool EMULATE_LOAD_DELAYS = true;
|
||||
static constexpr bool SWAP_BRANCH_DELAY_SLOTS = true;
|
||||
|
||||
// Arch-specific options
|
||||
#if defined(CPU_ARCH_X64)
|
||||
|
||||
// A reasonable "maximum" number of bytes per instruction.
|
||||
static constexpr u32 MAX_NEAR_HOST_BYTES_PER_INSTRUCTION = 64;
|
||||
static constexpr u32 MAX_FAR_HOST_BYTES_PER_INSTRUCTION = 128;
|
||||
|
||||
// Number of host registers.
|
||||
static constexpr u32 NUM_HOST_REGS = 16;
|
||||
static constexpr bool HAS_MEMORY_OPERANDS = true;
|
||||
|
||||
#elif defined(CPU_ARCH_ARM32)
|
||||
|
||||
// A reasonable "maximum" number of bytes per instruction.
|
||||
static constexpr u32 MAX_NEAR_HOST_BYTES_PER_INSTRUCTION = 64;
|
||||
static constexpr u32 MAX_FAR_HOST_BYTES_PER_INSTRUCTION = 128;
|
||||
|
||||
// Number of host registers.
|
||||
static constexpr u32 NUM_HOST_REGS = 16;
|
||||
static constexpr bool HAS_MEMORY_OPERANDS = false;
|
||||
|
||||
#elif defined(CPU_ARCH_ARM64)
|
||||
|
||||
// Number of host registers.
|
||||
static constexpr u32 NUM_HOST_REGS = 32;
|
||||
static constexpr bool HAS_MEMORY_OPERANDS = false;
|
||||
|
||||
// A reasonable "maximum" number of bytes per instruction.
|
||||
static constexpr u32 MAX_NEAR_HOST_BYTES_PER_INSTRUCTION = 64;
|
||||
static constexpr u32 MAX_FAR_HOST_BYTES_PER_INSTRUCTION = 128;
|
||||
|
||||
#elif defined(CPU_ARCH_RISCV64)
|
||||
|
||||
// Number of host registers.
|
||||
static constexpr u32 NUM_HOST_REGS = 32;
|
||||
static constexpr bool HAS_MEMORY_OPERANDS = false;
|
||||
|
||||
// A reasonable "maximum" number of bytes per instruction.
|
||||
static constexpr u32 MAX_NEAR_HOST_BYTES_PER_INSTRUCTION = 64;
|
||||
static constexpr u32 MAX_FAR_HOST_BYTES_PER_INSTRUCTION = 128;
|
||||
|
||||
#endif
|
||||
|
||||
public:
|
||||
Recompiler();
|
||||
virtual ~Recompiler();
|
||||
|
||||
const void* CompileBlock(CodeCache::Block* block, u32* host_code_size, u32* host_far_code_size);
|
||||
|
||||
static void BackpatchLoadStore(void* exception_pc, const CodeCache::LoadstoreBackpatchInfo& info);
|
||||
|
||||
static u32 CompileLoadStoreThunk(void* thunk_code, u32 thunk_space, void* code_address, u32 code_size,
|
||||
TickCount cycles_to_add, TickCount cycles_to_remove, u32 gpr_bitmask,
|
||||
u8 address_register, u8 data_register, MemoryAccessSize size, bool is_signed,
|
||||
bool is_load);
|
||||
|
||||
protected:
|
||||
enum FlushFlags : u32
|
||||
{
|
||||
@ -274,7 +309,7 @@ protected:
|
||||
void CompileTemplate(void (Recompiler::*const_func)(CompileFlags), void (Recompiler::*func)(CompileFlags),
|
||||
const void* pgxp_cpu_func, u32 tflags);
|
||||
void CompileLoadStoreTemplate(void (Recompiler::*func)(CompileFlags, MemoryAccessSize, bool, bool,
|
||||
const std::optional<VirtualMemoryAddress>&),
|
||||
const std::optional<VirtualMemoryAddress>&),
|
||||
MemoryAccessSize size, bool store, bool sign, u32 tflags);
|
||||
void FlushForLoadStore(const std::optional<VirtualMemoryAddress>& address, bool store, bool use_fastmem);
|
||||
void CompileMoveRegTemplate(Reg dst, Reg src, bool pgxp_move);
|
||||
@ -533,11 +568,5 @@ protected:
|
||||
static const std::array<const void*, 3> s_pgxp_mem_store_functions;
|
||||
};
|
||||
|
||||
void BackpatchLoadStore(void* exception_pc, const CodeCache::LoadstoreBackpatchInfo& info);
|
||||
|
||||
u32 CompileLoadStoreThunk(void* thunk_code, u32 thunk_space, void* code_address, u32 code_size, TickCount cycles_to_add,
|
||||
TickCount cycles_to_remove, u32 gpr_bitmask, u8 address_register, u8 data_register,
|
||||
MemoryAccessSize size, bool is_signed, bool is_load);
|
||||
|
||||
extern Recompiler* g_compiler;
|
||||
} // namespace CPU::Recompiler
|
||||
} // namespace CPU
|
||||
|
@ -4,8 +4,6 @@
|
||||
#include "cpu_recompiler_arm32.h"
|
||||
#include "cpu_core_private.h"
|
||||
#include "cpu_pgxp.h"
|
||||
#include "cpu_recompiler_thunks.h"
|
||||
#include "cpu_recompiler_types.h"
|
||||
#include "gte.h"
|
||||
#include "settings.h"
|
||||
#include "timing_event.h"
|
||||
@ -20,6 +18,9 @@
|
||||
|
||||
#ifdef CPU_ARCH_ARM32
|
||||
|
||||
#include "vixl/aarch32/constants-aarch32.h"
|
||||
#include "vixl/aarch32/instructions-aarch32.h"
|
||||
|
||||
#ifdef ENABLE_HOST_DISASSEMBLY
|
||||
#include "vixl/aarch32/disasm-aarch32.h"
|
||||
#include <iostream>
|
||||
@ -30,43 +31,64 @@ LOG_CHANNEL(Recompiler);
|
||||
#define PTR(x) vixl::aarch32::MemOperand(RSTATE, (((u8*)(x)) - ((u8*)&g_state)))
|
||||
#define RMEMBASE vixl::aarch32::r3
|
||||
|
||||
namespace CPU::Recompiler {
|
||||
static constexpr u32 FUNCTION_CALLEE_SAVED_SPACE_RESERVE = 80; // 8 registers
|
||||
static constexpr u32 FUNCTION_CALLER_SAVED_SPACE_RESERVE = 144; // 18 registers -> 224 bytes
|
||||
static constexpr u32 FUNCTION_STACK_SIZE = FUNCTION_CALLEE_SAVED_SPACE_RESERVE + FUNCTION_CALLER_SAVED_SPACE_RESERVE;
|
||||
|
||||
using namespace vixl::aarch32;
|
||||
#define RRET vixl::aarch32::r0
|
||||
#define RRETHI vixl::aarch32::r1
|
||||
#define RARG1 vixl::aarch32::r0
|
||||
#define RARG2 vixl::aarch32::r1
|
||||
#define RARG3 vixl::aarch32::r2
|
||||
#define RSCRATCH vixl::aarch32::r12
|
||||
#define RSTATE vixl::aarch32::r4
|
||||
|
||||
constexpr u32 FUNCTION_CALLEE_SAVED_SPACE_RESERVE = 80; // 8 registers
|
||||
constexpr u32 FUNCTION_CALLER_SAVED_SPACE_RESERVE = 144; // 18 registers -> 224 bytes
|
||||
constexpr u32 FUNCTION_STACK_SIZE = FUNCTION_CALLEE_SAVED_SPACE_RESERVE + FUNCTION_CALLER_SAVED_SPACE_RESERVE;
|
||||
static bool armIsCallerSavedRegister(u32 id);
|
||||
static s32 armGetPCDisplacement(const void* current, const void* target);
|
||||
static bool armIsPCDisplacementInImmediateRange(s32 displacement);
|
||||
static void armMoveAddressToReg(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg, const void* addr);
|
||||
static void armEmitMov(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& rd, u32 imm);
|
||||
static void armEmitJmp(vixl::aarch32::Assembler* armAsm, const void* ptr, bool force_inline);
|
||||
static void armEmitCall(vixl::aarch32::Assembler* armAsm, const void* ptr, bool force_inline);
|
||||
static void armEmitCondBranch(vixl::aarch32::Assembler* armAsm, vixl::aarch32::Condition cond, const void* ptr);
|
||||
static void armEmitFarLoad(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg, const void* addr);
|
||||
static void armEmitFarStore(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg, const void* addr,
|
||||
const vixl::aarch32::Register& tempreg = RSCRATCH);
|
||||
static u8* armGetJumpTrampoline(const void* target);
|
||||
|
||||
static constexpr u32 TRAMPOLINE_AREA_SIZE = 4 * 1024;
|
||||
static std::unordered_map<const void*, u32> s_trampoline_targets;
|
||||
static u8* s_trampoline_start_ptr = nullptr;
|
||||
static u32 s_trampoline_used = 0;
|
||||
|
||||
namespace CPU {
|
||||
|
||||
using namespace vixl::aarch32;
|
||||
|
||||
static ARM32Recompiler s_instance;
|
||||
Recompiler* g_compiler = &s_instance;
|
||||
|
||||
} // namespace CPU::Recompiler
|
||||
} // namespace CPU
|
||||
|
||||
bool CPU::Recompiler::armIsCallerSavedRegister(u32 id)
|
||||
bool armIsCallerSavedRegister(u32 id)
|
||||
{
|
||||
return ((id >= 0 && id <= 3) || // r0-r3
|
||||
(id == 12 || id == 14)); // sp, pc
|
||||
}
|
||||
|
||||
s32 CPU::Recompiler::armGetPCDisplacement(const void* current, const void* target)
|
||||
s32 armGetPCDisplacement(const void* current, const void* target)
|
||||
{
|
||||
Assert(Common::IsAlignedPow2(reinterpret_cast<size_t>(current), 4));
|
||||
Assert(Common::IsAlignedPow2(reinterpret_cast<size_t>(target), 4));
|
||||
return static_cast<s32>((reinterpret_cast<ptrdiff_t>(target) - reinterpret_cast<ptrdiff_t>(current)));
|
||||
}
|
||||
|
||||
bool CPU::Recompiler::armIsPCDisplacementInImmediateRange(s32 displacement)
|
||||
bool armIsPCDisplacementInImmediateRange(s32 displacement)
|
||||
{
|
||||
return (displacement >= -33554432 && displacement <= 33554428);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::armEmitMov(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& rd, u32 imm)
|
||||
void armEmitMov(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& rd, u32 imm)
|
||||
{
|
||||
if (vixl::IsUintN(16, imm))
|
||||
{
|
||||
@ -78,13 +100,12 @@ void CPU::Recompiler::armEmitMov(vixl::aarch32::Assembler* armAsm, const vixl::a
|
||||
armAsm->movt(al, rd, imm >> 16);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::armMoveAddressToReg(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg,
|
||||
const void* addr)
|
||||
void armMoveAddressToReg(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg, const void* addr)
|
||||
{
|
||||
armEmitMov(armAsm, reg, static_cast<u32>(reinterpret_cast<uintptr_t>(addr)));
|
||||
}
|
||||
|
||||
void CPU::Recompiler::armEmitJmp(vixl::aarch32::Assembler* armAsm, const void* ptr, bool force_inline)
|
||||
void armEmitJmp(vixl::aarch32::Assembler* armAsm, const void* ptr, bool force_inline)
|
||||
{
|
||||
const void* cur = armAsm->GetCursorAddress<const void*>();
|
||||
s32 displacement = armGetPCDisplacement(cur, ptr);
|
||||
@ -110,7 +131,7 @@ void CPU::Recompiler::armEmitJmp(vixl::aarch32::Assembler* armAsm, const void* p
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::armEmitCall(vixl::aarch32::Assembler* armAsm, const void* ptr, bool force_inline)
|
||||
void armEmitCall(vixl::aarch32::Assembler* armAsm, const void* ptr, bool force_inline)
|
||||
{
|
||||
const void* cur = armAsm->GetCursorAddress<const void*>();
|
||||
s32 displacement = armGetPCDisplacement(cur, ptr);
|
||||
@ -136,8 +157,7 @@ void CPU::Recompiler::armEmitCall(vixl::aarch32::Assembler* armAsm, const void*
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::armEmitCondBranch(vixl::aarch32::Assembler* armAsm, vixl::aarch32::Condition cond,
|
||||
const void* ptr)
|
||||
void armEmitCondBranch(vixl::aarch32::Assembler* armAsm, vixl::aarch32::Condition cond, const void* ptr)
|
||||
{
|
||||
const s32 displacement = armGetPCDisplacement(armAsm->GetCursorAddress<const void*>(), ptr);
|
||||
if (!armIsPCDisplacementInImmediateRange(displacement))
|
||||
@ -152,15 +172,14 @@ void CPU::Recompiler::armEmitCondBranch(vixl::aarch32::Assembler* armAsm, vixl::
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::armEmitFarLoad(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg,
|
||||
const void* addr)
|
||||
void armEmitFarLoad(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg, const void* addr)
|
||||
{
|
||||
armMoveAddressToReg(armAsm, reg, addr);
|
||||
armAsm->ldr(reg, MemOperand(reg));
|
||||
}
|
||||
|
||||
void CPU::Recompiler::armEmitFarStore(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg,
|
||||
const void* addr, const vixl::aarch32::Register& tempreg)
|
||||
void armEmitFarStore(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg, const void* addr,
|
||||
const vixl::aarch32::Register& tempreg)
|
||||
{
|
||||
armMoveAddressToReg(armAsm, tempreg, addr);
|
||||
armAsm->str(reg, MemOperand(tempreg));
|
||||
@ -319,19 +338,19 @@ u32 CPU::CodeCache::EmitASMFunctions(void* code, u32 code_size)
|
||||
return static_cast<u32>(armAsm->GetCursorOffset()) /* + TRAMPOLINE_AREA_SIZE*/;
|
||||
}
|
||||
|
||||
CPU::Recompiler::ARM32Recompiler::ARM32Recompiler() : m_emitter(A32), m_far_emitter(A32)
|
||||
CPU::ARM32Recompiler::ARM32Recompiler() : m_emitter(A32), m_far_emitter(A32)
|
||||
{
|
||||
}
|
||||
|
||||
CPU::Recompiler::ARM32Recompiler::~ARM32Recompiler() = default;
|
||||
CPU::ARM32Recompiler::~ARM32Recompiler() = default;
|
||||
|
||||
const void* CPU::Recompiler::ARM32Recompiler::GetCurrentCodePointer()
|
||||
const void* CPU::ARM32Recompiler::GetCurrentCodePointer()
|
||||
{
|
||||
return armAsm->GetCursorAddress<const void*>();
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Reset(CodeCache::Block* block, u8* code_buffer, u32 code_buffer_space,
|
||||
u8* far_code_buffer, u32 far_code_space)
|
||||
void CPU::ARM32Recompiler::Reset(CodeCache::Block* block, u8* code_buffer, u32 code_buffer_space, u8* far_code_buffer,
|
||||
u32 far_code_space)
|
||||
{
|
||||
Recompiler::Reset(block, code_buffer, code_buffer_space, far_code_buffer, far_code_space);
|
||||
|
||||
@ -369,7 +388,7 @@ void CPU::Recompiler::ARM32Recompiler::Reset(CodeCache::Block* block, u8* code_b
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::SwitchToFarCode(bool emit_jump, vixl::aarch32::ConditionType cond)
|
||||
void CPU::ARM32Recompiler::SwitchToFarCode(bool emit_jump, vixl::aarch32::ConditionType cond)
|
||||
{
|
||||
DebugAssert(armAsm == &m_emitter);
|
||||
if (emit_jump)
|
||||
@ -395,7 +414,7 @@ void CPU::Recompiler::ARM32Recompiler::SwitchToFarCode(bool emit_jump, vixl::aar
|
||||
armAsm = &m_far_emitter;
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::SwitchToFarCodeIfBitSet(const vixl::aarch32::Register& reg, u32 bit)
|
||||
void CPU::ARM32Recompiler::SwitchToFarCodeIfBitSet(const vixl::aarch32::Register& reg, u32 bit)
|
||||
{
|
||||
armAsm->tst(reg, 1u << bit);
|
||||
|
||||
@ -416,8 +435,7 @@ void CPU::Recompiler::ARM32Recompiler::SwitchToFarCodeIfBitSet(const vixl::aarch
|
||||
armAsm = &m_far_emitter;
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::SwitchToFarCodeIfRegZeroOrNonZero(const vixl::aarch32::Register& reg,
|
||||
bool nonzero)
|
||||
void CPU::ARM32Recompiler::SwitchToFarCodeIfRegZeroOrNonZero(const vixl::aarch32::Register& reg, bool nonzero)
|
||||
{
|
||||
armAsm->cmp(reg, 0);
|
||||
|
||||
@ -438,7 +456,7 @@ void CPU::Recompiler::ARM32Recompiler::SwitchToFarCodeIfRegZeroOrNonZero(const v
|
||||
armAsm = &m_far_emitter;
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::SwitchToNearCode(bool emit_jump, vixl::aarch32::ConditionType cond)
|
||||
void CPU::ARM32Recompiler::SwitchToNearCode(bool emit_jump, vixl::aarch32::ConditionType cond)
|
||||
{
|
||||
DebugAssert(armAsm == &m_far_emitter);
|
||||
if (emit_jump)
|
||||
@ -464,17 +482,17 @@ void CPU::Recompiler::ARM32Recompiler::SwitchToNearCode(bool emit_jump, vixl::aa
|
||||
armAsm = &m_emitter;
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::EmitMov(const vixl::aarch32::Register& dst, u32 val)
|
||||
void CPU::ARM32Recompiler::EmitMov(const vixl::aarch32::Register& dst, u32 val)
|
||||
{
|
||||
armEmitMov(armAsm, dst, val);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::EmitCall(const void* ptr, bool force_inline /*= false*/)
|
||||
void CPU::ARM32Recompiler::EmitCall(const void* ptr, bool force_inline /*= false*/)
|
||||
{
|
||||
armEmitCall(armAsm, ptr, force_inline);
|
||||
}
|
||||
|
||||
vixl::aarch32::Operand CPU::Recompiler::ARM32Recompiler::armCheckAddSubConstant(s32 val)
|
||||
vixl::aarch32::Operand CPU::ARM32Recompiler::armCheckAddSubConstant(s32 val)
|
||||
{
|
||||
if (ImmediateA32::IsImmediateA32(static_cast<u32>(val)))
|
||||
return vixl::aarch32::Operand(static_cast<int32_t>(val));
|
||||
@ -483,27 +501,27 @@ vixl::aarch32::Operand CPU::Recompiler::ARM32Recompiler::armCheckAddSubConstant(
|
||||
return vixl::aarch32::Operand(RSCRATCH);
|
||||
}
|
||||
|
||||
vixl::aarch32::Operand CPU::Recompiler::ARM32Recompiler::armCheckAddSubConstant(u32 val)
|
||||
vixl::aarch32::Operand CPU::ARM32Recompiler::armCheckAddSubConstant(u32 val)
|
||||
{
|
||||
return armCheckAddSubConstant(static_cast<s32>(val));
|
||||
}
|
||||
|
||||
vixl::aarch32::Operand CPU::Recompiler::ARM32Recompiler::armCheckCompareConstant(s32 val)
|
||||
vixl::aarch32::Operand CPU::ARM32Recompiler::armCheckCompareConstant(s32 val)
|
||||
{
|
||||
return armCheckAddSubConstant(val);
|
||||
}
|
||||
|
||||
vixl::aarch32::Operand CPU::Recompiler::ARM32Recompiler::armCheckLogicalConstant(u32 val)
|
||||
vixl::aarch32::Operand CPU::ARM32Recompiler::armCheckLogicalConstant(u32 val)
|
||||
{
|
||||
return armCheckAddSubConstant(val);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::BeginBlock()
|
||||
void CPU::ARM32Recompiler::BeginBlock()
|
||||
{
|
||||
Recompiler::BeginBlock();
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::GenerateBlockProtectCheck(const u8* ram_ptr, const u8* shadow_ptr, u32 size)
|
||||
void CPU::ARM32Recompiler::GenerateBlockProtectCheck(const u8* ram_ptr, const u8* shadow_ptr, u32 size)
|
||||
{
|
||||
// store it first to reduce code size, because we can offset
|
||||
armMoveAddressToReg(armAsm, RARG1, ram_ptr);
|
||||
@ -579,7 +597,7 @@ bool foo(const void* a, const void* b)
|
||||
armAsm->bind(&block_unchanged);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::GenerateICacheCheckAndUpdate()
|
||||
void CPU::ARM32Recompiler::GenerateICacheCheckAndUpdate()
|
||||
{
|
||||
if (!m_block->HasFlag(CodeCache::BlockFlags::IsUsingICache))
|
||||
{
|
||||
@ -635,8 +653,8 @@ void CPU::Recompiler::ARM32Recompiler::GenerateICacheCheckAndUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::GenerateCall(const void* func, s32 arg1reg /*= -1*/, s32 arg2reg /*= -1*/,
|
||||
s32 arg3reg /*= -1*/)
|
||||
void CPU::ARM32Recompiler::GenerateCall(const void* func, s32 arg1reg /*= -1*/, s32 arg2reg /*= -1*/,
|
||||
s32 arg3reg /*= -1*/)
|
||||
{
|
||||
if (arg1reg >= 0 && arg1reg != static_cast<s32>(RARG1.GetCode()))
|
||||
armAsm->mov(RARG1, Register(arg1reg));
|
||||
@ -647,7 +665,7 @@ void CPU::Recompiler::ARM32Recompiler::GenerateCall(const void* func, s32 arg1re
|
||||
EmitCall(func);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::EndBlock(const std::optional<u32>& newpc, bool do_event_test)
|
||||
void CPU::ARM32Recompiler::EndBlock(const std::optional<u32>& newpc, bool do_event_test)
|
||||
{
|
||||
if (newpc.has_value())
|
||||
{
|
||||
@ -664,7 +682,7 @@ void CPU::Recompiler::ARM32Recompiler::EndBlock(const std::optional<u32>& newpc,
|
||||
EndAndLinkBlock(newpc, do_event_test, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::EndBlockWithException(Exception excode)
|
||||
void CPU::ARM32Recompiler::EndBlockWithException(Exception excode)
|
||||
{
|
||||
// flush regs, but not pc, it's going to get overwritten
|
||||
// flush cycles because of the GTE instruction stuff...
|
||||
@ -682,8 +700,7 @@ void CPU::Recompiler::ARM32Recompiler::EndBlockWithException(Exception excode)
|
||||
EndAndLinkBlock(std::nullopt, true, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::EndAndLinkBlock(const std::optional<u32>& newpc, bool do_event_test,
|
||||
bool force_run_events)
|
||||
void CPU::ARM32Recompiler::EndAndLinkBlock(const std::optional<u32>& newpc, bool do_event_test, bool force_run_events)
|
||||
{
|
||||
// event test
|
||||
// pc should've been flushed
|
||||
@ -740,7 +757,7 @@ void CPU::Recompiler::ARM32Recompiler::EndAndLinkBlock(const std::optional<u32>&
|
||||
}
|
||||
}
|
||||
|
||||
const void* CPU::Recompiler::ARM32Recompiler::EndCompile(u32* code_size, u32* far_code_size)
|
||||
const void* CPU::ARM32Recompiler::EndCompile(u32* code_size, u32* far_code_size)
|
||||
{
|
||||
#ifdef VIXL_DEBUG
|
||||
m_emitter_check.reset();
|
||||
@ -757,7 +774,7 @@ const void* CPU::Recompiler::ARM32Recompiler::EndCompile(u32* code_size, u32* fa
|
||||
return code;
|
||||
}
|
||||
|
||||
const char* CPU::Recompiler::ARM32Recompiler::GetHostRegName(u32 reg) const
|
||||
const char* CPU::ARM32Recompiler::GetHostRegName(u32 reg) const
|
||||
{
|
||||
static constexpr std::array<const char*, 32> reg64_names = {
|
||||
{"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
|
||||
@ -765,80 +782,80 @@ const char* CPU::Recompiler::ARM32Recompiler::GetHostRegName(u32 reg) const
|
||||
return (reg < reg64_names.size()) ? reg64_names[reg] : "UNKNOWN";
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::LoadHostRegWithConstant(u32 reg, u32 val)
|
||||
void CPU::ARM32Recompiler::LoadHostRegWithConstant(u32 reg, u32 val)
|
||||
{
|
||||
EmitMov(Register(reg), val);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::LoadHostRegFromCPUPointer(u32 reg, const void* ptr)
|
||||
void CPU::ARM32Recompiler::LoadHostRegFromCPUPointer(u32 reg, const void* ptr)
|
||||
{
|
||||
armAsm->ldr(Register(reg), PTR(ptr));
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::StoreHostRegToCPUPointer(u32 reg, const void* ptr)
|
||||
void CPU::ARM32Recompiler::StoreHostRegToCPUPointer(u32 reg, const void* ptr)
|
||||
{
|
||||
armAsm->str(Register(reg), PTR(ptr));
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::StoreConstantToCPUPointer(u32 val, const void* ptr)
|
||||
void CPU::ARM32Recompiler::StoreConstantToCPUPointer(u32 val, const void* ptr)
|
||||
{
|
||||
EmitMov(RSCRATCH, val);
|
||||
armAsm->str(RSCRATCH, PTR(ptr));
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::CopyHostReg(u32 dst, u32 src)
|
||||
void CPU::ARM32Recompiler::CopyHostReg(u32 dst, u32 src)
|
||||
{
|
||||
if (src != dst)
|
||||
armAsm->mov(Register(dst), Register(src));
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::AssertRegOrConstS(CompileFlags cf) const
|
||||
void CPU::ARM32Recompiler::AssertRegOrConstS(CompileFlags cf) const
|
||||
{
|
||||
DebugAssert(cf.valid_host_s || cf.const_s);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::AssertRegOrConstT(CompileFlags cf) const
|
||||
void CPU::ARM32Recompiler::AssertRegOrConstT(CompileFlags cf) const
|
||||
{
|
||||
DebugAssert(cf.valid_host_t || cf.const_t);
|
||||
}
|
||||
|
||||
vixl::aarch32::MemOperand CPU::Recompiler::ARM32Recompiler::MipsPtr(Reg r) const
|
||||
vixl::aarch32::MemOperand CPU::ARM32Recompiler::MipsPtr(Reg r) const
|
||||
{
|
||||
DebugAssert(r < Reg::count);
|
||||
return PTR(&g_state.regs.r[static_cast<u32>(r)]);
|
||||
}
|
||||
|
||||
vixl::aarch32::Register CPU::Recompiler::ARM32Recompiler::CFGetRegD(CompileFlags cf) const
|
||||
vixl::aarch32::Register CPU::ARM32Recompiler::CFGetRegD(CompileFlags cf) const
|
||||
{
|
||||
DebugAssert(cf.valid_host_d);
|
||||
return Register(cf.host_d);
|
||||
}
|
||||
|
||||
vixl::aarch32::Register CPU::Recompiler::ARM32Recompiler::CFGetRegS(CompileFlags cf) const
|
||||
vixl::aarch32::Register CPU::ARM32Recompiler::CFGetRegS(CompileFlags cf) const
|
||||
{
|
||||
DebugAssert(cf.valid_host_s);
|
||||
return Register(cf.host_s);
|
||||
}
|
||||
|
||||
vixl::aarch32::Register CPU::Recompiler::ARM32Recompiler::CFGetRegT(CompileFlags cf) const
|
||||
vixl::aarch32::Register CPU::ARM32Recompiler::CFGetRegT(CompileFlags cf) const
|
||||
{
|
||||
DebugAssert(cf.valid_host_t);
|
||||
return Register(cf.host_t);
|
||||
}
|
||||
|
||||
vixl::aarch32::Register CPU::Recompiler::ARM32Recompiler::CFGetRegLO(CompileFlags cf) const
|
||||
vixl::aarch32::Register CPU::ARM32Recompiler::CFGetRegLO(CompileFlags cf) const
|
||||
{
|
||||
DebugAssert(cf.valid_host_lo);
|
||||
return Register(cf.host_lo);
|
||||
}
|
||||
|
||||
vixl::aarch32::Register CPU::Recompiler::ARM32Recompiler::CFGetRegHI(CompileFlags cf) const
|
||||
vixl::aarch32::Register CPU::ARM32Recompiler::CFGetRegHI(CompileFlags cf) const
|
||||
{
|
||||
DebugAssert(cf.valid_host_hi);
|
||||
return Register(cf.host_hi);
|
||||
}
|
||||
|
||||
vixl::aarch32::Register CPU::Recompiler::ARM32Recompiler::GetMembaseReg()
|
||||
vixl::aarch32::Register CPU::ARM32Recompiler::GetMembaseReg()
|
||||
{
|
||||
const u32 code = RMEMBASE.GetCode();
|
||||
if (!IsHostRegAllocated(code))
|
||||
@ -852,7 +869,7 @@ vixl::aarch32::Register CPU::Recompiler::ARM32Recompiler::GetMembaseReg()
|
||||
return RMEMBASE;
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::MoveSToReg(const vixl::aarch32::Register& dst, CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::MoveSToReg(const vixl::aarch32::Register& dst, CompileFlags cf)
|
||||
{
|
||||
if (cf.valid_host_s)
|
||||
{
|
||||
@ -871,7 +888,7 @@ void CPU::Recompiler::ARM32Recompiler::MoveSToReg(const vixl::aarch32::Register&
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::MoveTToReg(const vixl::aarch32::Register& dst, CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::MoveTToReg(const vixl::aarch32::Register& dst, CompileFlags cf)
|
||||
{
|
||||
if (cf.valid_host_t)
|
||||
{
|
||||
@ -890,7 +907,7 @@ void CPU::Recompiler::ARM32Recompiler::MoveTToReg(const vixl::aarch32::Register&
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::MoveMIPSRegToReg(const vixl::aarch32::Register& dst, Reg reg)
|
||||
void CPU::ARM32Recompiler::MoveMIPSRegToReg(const vixl::aarch32::Register& dst, Reg reg)
|
||||
{
|
||||
DebugAssert(reg < Reg::count);
|
||||
if (const std::optional<u32> hreg = CheckHostReg(0, Recompiler::HR_TYPE_CPU_REG, reg))
|
||||
@ -901,9 +918,8 @@ void CPU::Recompiler::ARM32Recompiler::MoveMIPSRegToReg(const vixl::aarch32::Reg
|
||||
armAsm->ldr(dst, MipsPtr(reg));
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::GeneratePGXPCallWithMIPSRegs(const void* func, u32 arg1val,
|
||||
Reg arg2reg /* = Reg::count */,
|
||||
Reg arg3reg /* = Reg::count */)
|
||||
void CPU::ARM32Recompiler::GeneratePGXPCallWithMIPSRegs(const void* func, u32 arg1val, Reg arg2reg /* = Reg::count */,
|
||||
Reg arg3reg /* = Reg::count */)
|
||||
{
|
||||
DebugAssert(g_settings.gpu_pgxp_enable);
|
||||
|
||||
@ -918,7 +934,7 @@ void CPU::Recompiler::ARM32Recompiler::GeneratePGXPCallWithMIPSRegs(const void*
|
||||
EmitCall(func);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Flush(u32 flags)
|
||||
void CPU::ARM32Recompiler::Flush(u32 flags)
|
||||
{
|
||||
Recompiler::Flush(flags);
|
||||
|
||||
@ -1010,13 +1026,13 @@ void CPU::Recompiler::ARM32Recompiler::Flush(u32 flags)
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_Fallback()
|
||||
void CPU::ARM32Recompiler::Compile_Fallback()
|
||||
{
|
||||
WARNING_LOG("Compiling instruction fallback at PC=0x{:08X}, instruction=0x{:08X}", iinfo->pc, inst->bits);
|
||||
|
||||
Flush(FLUSH_FOR_INTERPRETER);
|
||||
|
||||
EmitCall(reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::InterpretInstruction));
|
||||
EmitCall(reinterpret_cast<const void*>(&CPU::RecompilerThunks::InterpretInstruction));
|
||||
|
||||
// TODO: make me less garbage
|
||||
// TODO: this is wrong, it flushes the load delay on the same cycle when we return.
|
||||
@ -1035,7 +1051,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_Fallback()
|
||||
m_load_delay_dirty = EMULATE_LOAD_DELAYS;
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::CheckBranchTarget(const vixl::aarch32::Register& pcreg)
|
||||
void CPU::ARM32Recompiler::CheckBranchTarget(const vixl::aarch32::Register& pcreg)
|
||||
{
|
||||
if (!g_settings.cpu_recompiler_memory_exceptions)
|
||||
return;
|
||||
@ -1050,7 +1066,7 @@ void CPU::Recompiler::ARM32Recompiler::CheckBranchTarget(const vixl::aarch32::Re
|
||||
SwitchToNearCode(false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_jr(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_jr(CompileFlags cf)
|
||||
{
|
||||
const Register pcreg = CFGetRegS(cf);
|
||||
CheckBranchTarget(pcreg);
|
||||
@ -1061,7 +1077,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_jr(CompileFlags cf)
|
||||
EndBlock(std::nullopt, true);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_jalr(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_jalr(CompileFlags cf)
|
||||
{
|
||||
const Register pcreg = CFGetRegS(cf);
|
||||
if (MipsD() != Reg::zero)
|
||||
@ -1074,7 +1090,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_jalr(CompileFlags cf)
|
||||
EndBlock(std::nullopt, true);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_bxx(CompileFlags cf, BranchCondition cond)
|
||||
void CPU::ARM32Recompiler::Compile_bxx(CompileFlags cf, BranchCondition cond)
|
||||
{
|
||||
AssertRegOrConstS(cf);
|
||||
|
||||
@ -1148,7 +1164,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_bxx(CompileFlags cf, BranchCondit
|
||||
EndBlock(taken_pc, true);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_addi(CompileFlags cf, bool overflow)
|
||||
void CPU::ARM32Recompiler::Compile_addi(CompileFlags cf, bool overflow)
|
||||
{
|
||||
const Register rs = CFGetRegS(cf);
|
||||
const Register rt = CFGetRegT(cf);
|
||||
@ -1170,27 +1186,27 @@ void CPU::Recompiler::ARM32Recompiler::Compile_addi(CompileFlags cf, bool overfl
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_addi(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_addi(CompileFlags cf)
|
||||
{
|
||||
Compile_addi(cf, g_settings.cpu_recompiler_memory_exceptions);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_addiu(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_addiu(CompileFlags cf)
|
||||
{
|
||||
Compile_addi(cf, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_slti(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_slti(CompileFlags cf)
|
||||
{
|
||||
Compile_slti(cf, true);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_sltiu(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_sltiu(CompileFlags cf)
|
||||
{
|
||||
Compile_slti(cf, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_slti(CompileFlags cf, bool sign)
|
||||
void CPU::ARM32Recompiler::Compile_slti(CompileFlags cf, bool sign)
|
||||
{
|
||||
const Register rs = CFGetRegS(cf);
|
||||
const Register rt = CFGetRegT(cf);
|
||||
@ -1199,7 +1215,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_slti(CompileFlags cf, bool sign)
|
||||
armAsm->mov(sign ? lt : lo, rt, 1);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_andi(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_andi(CompileFlags cf)
|
||||
{
|
||||
const Register rt = CFGetRegT(cf);
|
||||
if (const u32 imm = inst->i.imm_zext32(); imm != 0)
|
||||
@ -1208,7 +1224,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_andi(CompileFlags cf)
|
||||
EmitMov(rt, 0);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_ori(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_ori(CompileFlags cf)
|
||||
{
|
||||
const Register rt = CFGetRegT(cf);
|
||||
const Register rs = CFGetRegS(cf);
|
||||
@ -1218,7 +1234,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_ori(CompileFlags cf)
|
||||
armAsm->mov(rt, rs);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_xori(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_xori(CompileFlags cf)
|
||||
{
|
||||
const Register rt = CFGetRegT(cf);
|
||||
const Register rs = CFGetRegS(cf);
|
||||
@ -1228,10 +1244,9 @@ void CPU::Recompiler::ARM32Recompiler::Compile_xori(CompileFlags cf)
|
||||
armAsm->mov(rt, rs);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_shift(CompileFlags cf,
|
||||
void (vixl::aarch32::Assembler::*op)(vixl::aarch32::Register,
|
||||
vixl::aarch32::Register,
|
||||
const Operand&))
|
||||
void CPU::ARM32Recompiler::Compile_shift(CompileFlags cf,
|
||||
void (vixl::aarch32::Assembler::*op)(vixl::aarch32::Register,
|
||||
vixl::aarch32::Register, const Operand&))
|
||||
{
|
||||
const Register rd = CFGetRegD(cf);
|
||||
const Register rt = CFGetRegT(cf);
|
||||
@ -1241,24 +1256,25 @@ void CPU::Recompiler::ARM32Recompiler::Compile_shift(CompileFlags cf,
|
||||
armAsm->mov(rd, rt);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_sll(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_sll(CompileFlags cf)
|
||||
{
|
||||
Compile_shift(cf, &Assembler::lsl);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_srl(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_srl(CompileFlags cf)
|
||||
{
|
||||
Compile_shift(cf, &Assembler::lsr);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_sra(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_sra(CompileFlags cf)
|
||||
{
|
||||
Compile_shift(cf, &Assembler::asr);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_variable_shift(
|
||||
CompileFlags cf,
|
||||
void (vixl::aarch32::Assembler::*op)(vixl::aarch32::Register, vixl::aarch32::Register, const Operand&))
|
||||
void CPU::ARM32Recompiler::Compile_variable_shift(CompileFlags cf,
|
||||
void (vixl::aarch32::Assembler::*op)(vixl::aarch32::Register,
|
||||
vixl::aarch32::Register,
|
||||
const Operand&))
|
||||
{
|
||||
const Register rd = CFGetRegD(cf);
|
||||
|
||||
@ -1283,22 +1299,22 @@ void CPU::Recompiler::ARM32Recompiler::Compile_variable_shift(
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_sllv(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_sllv(CompileFlags cf)
|
||||
{
|
||||
Compile_variable_shift(cf, &Assembler::lsl);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_srlv(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_srlv(CompileFlags cf)
|
||||
{
|
||||
Compile_variable_shift(cf, &Assembler::lsr);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_srav(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_srav(CompileFlags cf)
|
||||
{
|
||||
Compile_variable_shift(cf, &Assembler::asr);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_mult(CompileFlags cf, bool sign)
|
||||
void CPU::ARM32Recompiler::Compile_mult(CompileFlags cf, bool sign)
|
||||
{
|
||||
const Register rs = cf.valid_host_s ? CFGetRegS(cf) : RARG1;
|
||||
if (!cf.valid_host_s)
|
||||
@ -1315,17 +1331,17 @@ void CPU::Recompiler::ARM32Recompiler::Compile_mult(CompileFlags cf, bool sign)
|
||||
(sign) ? armAsm->smull(lo, hi, rs, rt) : armAsm->umull(lo, hi, rs, rt);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_mult(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_mult(CompileFlags cf)
|
||||
{
|
||||
Compile_mult(cf, true);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_multu(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_multu(CompileFlags cf)
|
||||
{
|
||||
Compile_mult(cf, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_div(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_div(CompileFlags cf)
|
||||
{
|
||||
const Register rs = cf.valid_host_s ? CFGetRegS(cf) : RARG1;
|
||||
if (!cf.valid_host_s)
|
||||
@ -1371,7 +1387,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_div(CompileFlags cf)
|
||||
armAsm->bind(&done);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_divu(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_divu(CompileFlags cf)
|
||||
{
|
||||
const Register rs = cf.valid_host_s ? CFGetRegS(cf) : RARG1;
|
||||
if (!cf.valid_host_s)
|
||||
@ -1402,7 +1418,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_divu(CompileFlags cf)
|
||||
armAsm->bind(&done);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::TestOverflow(const vixl::aarch32::Register& result)
|
||||
void CPU::ARM32Recompiler::TestOverflow(const vixl::aarch32::Register& result)
|
||||
{
|
||||
SwitchToFarCode(true, vs);
|
||||
|
||||
@ -1418,11 +1434,10 @@ void CPU::Recompiler::ARM32Recompiler::TestOverflow(const vixl::aarch32::Registe
|
||||
SwitchToNearCode(false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_dst_op(CompileFlags cf,
|
||||
void (vixl::aarch32::Assembler::*op)(vixl::aarch32::Register,
|
||||
vixl::aarch32::Register,
|
||||
const Operand&),
|
||||
bool commutative, bool logical, bool overflow)
|
||||
void CPU::ARM32Recompiler::Compile_dst_op(CompileFlags cf,
|
||||
void (vixl::aarch32::Assembler::*op)(vixl::aarch32::Register,
|
||||
vixl::aarch32::Register, const Operand&),
|
||||
bool commutative, bool logical, bool overflow)
|
||||
{
|
||||
AssertRegOrConstS(cf);
|
||||
AssertRegOrConstT(cf);
|
||||
@ -1470,7 +1485,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_dst_op(CompileFlags cf,
|
||||
TestOverflow(rd);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_add(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_add(CompileFlags cf)
|
||||
{
|
||||
if (g_settings.cpu_recompiler_memory_exceptions)
|
||||
Compile_dst_op(cf, &Assembler::adds, true, false, true);
|
||||
@ -1478,12 +1493,12 @@ void CPU::Recompiler::ARM32Recompiler::Compile_add(CompileFlags cf)
|
||||
Compile_dst_op(cf, &Assembler::add, true, false, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_addu(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_addu(CompileFlags cf)
|
||||
{
|
||||
Compile_dst_op(cf, &Assembler::add, true, false, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_sub(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_sub(CompileFlags cf)
|
||||
{
|
||||
if (g_settings.cpu_recompiler_memory_exceptions)
|
||||
Compile_dst_op(cf, &Assembler::subs, false, false, true);
|
||||
@ -1491,12 +1506,12 @@ void CPU::Recompiler::ARM32Recompiler::Compile_sub(CompileFlags cf)
|
||||
Compile_dst_op(cf, &Assembler::sub, false, false, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_subu(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_subu(CompileFlags cf)
|
||||
{
|
||||
Compile_dst_op(cf, &Assembler::sub, false, false, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_and(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_and(CompileFlags cf)
|
||||
{
|
||||
AssertRegOrConstS(cf);
|
||||
AssertRegOrConstT(cf);
|
||||
@ -1517,7 +1532,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_and(CompileFlags cf)
|
||||
Compile_dst_op(cf, &Assembler::and_, true, true, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_or(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_or(CompileFlags cf)
|
||||
{
|
||||
AssertRegOrConstS(cf);
|
||||
AssertRegOrConstT(cf);
|
||||
@ -1533,7 +1548,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_or(CompileFlags cf)
|
||||
Compile_dst_op(cf, &Assembler::orr, true, true, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_xor(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_xor(CompileFlags cf)
|
||||
{
|
||||
AssertRegOrConstS(cf);
|
||||
AssertRegOrConstT(cf);
|
||||
@ -1555,23 +1570,23 @@ void CPU::Recompiler::ARM32Recompiler::Compile_xor(CompileFlags cf)
|
||||
Compile_dst_op(cf, &Assembler::eor, true, true, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_nor(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_nor(CompileFlags cf)
|
||||
{
|
||||
Compile_or(cf);
|
||||
armAsm->mvn(CFGetRegD(cf), CFGetRegD(cf));
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_slt(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_slt(CompileFlags cf)
|
||||
{
|
||||
Compile_slt(cf, true);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_sltu(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_sltu(CompileFlags cf)
|
||||
{
|
||||
Compile_slt(cf, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_slt(CompileFlags cf, bool sign)
|
||||
void CPU::ARM32Recompiler::Compile_slt(CompileFlags cf, bool sign)
|
||||
{
|
||||
AssertRegOrConstS(cf);
|
||||
AssertRegOrConstT(cf);
|
||||
@ -1597,9 +1612,8 @@ void CPU::Recompiler::ARM32Recompiler::Compile_slt(CompileFlags cf, bool sign)
|
||||
}
|
||||
|
||||
vixl::aarch32::Register
|
||||
CPU::Recompiler::ARM32Recompiler::ComputeLoadStoreAddressArg(CompileFlags cf,
|
||||
const std::optional<VirtualMemoryAddress>& address,
|
||||
const std::optional<const vixl::aarch32::Register>& reg)
|
||||
CPU::ARM32Recompiler::ComputeLoadStoreAddressArg(CompileFlags cf, const std::optional<VirtualMemoryAddress>& address,
|
||||
const std::optional<const vixl::aarch32::Register>& reg)
|
||||
{
|
||||
const u32 imm = inst->i.imm_sext32();
|
||||
if (cf.valid_host_s && imm == 0 && !reg.has_value())
|
||||
@ -1639,9 +1653,9 @@ CPU::Recompiler::ARM32Recompiler::ComputeLoadStoreAddressArg(CompileFlags cf,
|
||||
}
|
||||
|
||||
template<typename RegAllocFn>
|
||||
vixl::aarch32::Register
|
||||
CPU::Recompiler::ARM32Recompiler::GenerateLoad(const vixl::aarch32::Register& addr_reg, MemoryAccessSize size,
|
||||
bool sign, bool use_fastmem, const RegAllocFn& dst_reg_alloc)
|
||||
vixl::aarch32::Register CPU::ARM32Recompiler::GenerateLoad(const vixl::aarch32::Register& addr_reg,
|
||||
MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const RegAllocFn& dst_reg_alloc)
|
||||
{
|
||||
if (use_fastmem)
|
||||
{
|
||||
@ -1683,20 +1697,20 @@ CPU::Recompiler::ARM32Recompiler::GenerateLoad(const vixl::aarch32::Register& ad
|
||||
{
|
||||
case MemoryAccessSize::Byte:
|
||||
{
|
||||
EmitCall(checked ? reinterpret_cast<const void*>(&Recompiler::Thunks::ReadMemoryByte) :
|
||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedReadMemoryByte));
|
||||
EmitCall(checked ? reinterpret_cast<const void*>(&RecompilerThunks::ReadMemoryByte) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryByte));
|
||||
}
|
||||
break;
|
||||
case MemoryAccessSize::HalfWord:
|
||||
{
|
||||
EmitCall(checked ? reinterpret_cast<const void*>(&Recompiler::Thunks::ReadMemoryHalfWord) :
|
||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedReadMemoryHalfWord));
|
||||
EmitCall(checked ? reinterpret_cast<const void*>(&RecompilerThunks::ReadMemoryHalfWord) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryHalfWord));
|
||||
}
|
||||
break;
|
||||
case MemoryAccessSize::Word:
|
||||
{
|
||||
EmitCall(checked ? reinterpret_cast<const void*>(&Recompiler::Thunks::ReadMemoryWord) :
|
||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedReadMemoryWord));
|
||||
EmitCall(checked ? reinterpret_cast<const void*>(&RecompilerThunks::ReadMemoryWord) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryWord));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1751,9 +1765,9 @@ CPU::Recompiler::ARM32Recompiler::GenerateLoad(const vixl::aarch32::Register& ad
|
||||
return dst_reg;
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::GenerateStore(const vixl::aarch32::Register& addr_reg,
|
||||
const vixl::aarch32::Register& value_reg, MemoryAccessSize size,
|
||||
bool use_fastmem)
|
||||
void CPU::ARM32Recompiler::GenerateStore(const vixl::aarch32::Register& addr_reg,
|
||||
const vixl::aarch32::Register& value_reg, MemoryAccessSize size,
|
||||
bool use_fastmem)
|
||||
{
|
||||
if (use_fastmem)
|
||||
{
|
||||
@ -1793,20 +1807,20 @@ void CPU::Recompiler::ARM32Recompiler::GenerateStore(const vixl::aarch32::Regist
|
||||
{
|
||||
case MemoryAccessSize::Byte:
|
||||
{
|
||||
EmitCall(checked ? reinterpret_cast<const void*>(&Recompiler::Thunks::WriteMemoryByte) :
|
||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedWriteMemoryByte));
|
||||
EmitCall(checked ? reinterpret_cast<const void*>(&RecompilerThunks::WriteMemoryByte) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryByte));
|
||||
}
|
||||
break;
|
||||
case MemoryAccessSize::HalfWord:
|
||||
{
|
||||
EmitCall(checked ? reinterpret_cast<const void*>(&Recompiler::Thunks::WriteMemoryHalfWord) :
|
||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedWriteMemoryHalfWord));
|
||||
EmitCall(checked ? reinterpret_cast<const void*>(&RecompilerThunks::WriteMemoryHalfWord) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryHalfWord));
|
||||
}
|
||||
break;
|
||||
case MemoryAccessSize::Word:
|
||||
{
|
||||
EmitCall(checked ? reinterpret_cast<const void*>(&Recompiler::Thunks::WriteMemoryWord) :
|
||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedWriteMemoryWord));
|
||||
EmitCall(checked ? reinterpret_cast<const void*>(&RecompilerThunks::WriteMemoryWord) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryWord));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1837,8 +1851,8 @@ void CPU::Recompiler::ARM32Recompiler::GenerateStore(const vixl::aarch32::Regist
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_lxx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
void CPU::ARM32Recompiler::Compile_lxx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
{
|
||||
const std::optional<Register> addr_reg = g_settings.gpu_pgxp_enable ?
|
||||
std::optional<Register>(Register(AllocateTempHostReg(HR_CALLEE_SAVED))) :
|
||||
@ -1865,8 +1879,8 @@ void CPU::Recompiler::ARM32Recompiler::Compile_lxx(CompileFlags cf, MemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_lwx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
void CPU::ARM32Recompiler::Compile_lwx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
{
|
||||
DebugAssert(size == MemoryAccessSize::Word && !sign);
|
||||
|
||||
@ -1959,8 +1973,8 @@ void CPU::Recompiler::ARM32Recompiler::Compile_lwx(CompileFlags cf, MemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_lwc2(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
void CPU::ARM32Recompiler::Compile_lwc2(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
{
|
||||
const u32 index = static_cast<u32>(inst->r.rt.GetValue());
|
||||
const auto [ptr, action] = GetGTERegisterPointer(index, true);
|
||||
@ -2045,8 +2059,8 @@ void CPU::Recompiler::ARM32Recompiler::Compile_lwc2(CompileFlags cf, MemoryAcces
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_sxx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
void CPU::ARM32Recompiler::Compile_sxx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
{
|
||||
AssertRegOrConstS(cf);
|
||||
AssertRegOrConstT(cf);
|
||||
@ -2073,8 +2087,8 @@ void CPU::Recompiler::ARM32Recompiler::Compile_sxx(CompileFlags cf, MemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_swx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
void CPU::ARM32Recompiler::Compile_swx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
{
|
||||
DebugAssert(size == MemoryAccessSize::Word && !sign);
|
||||
|
||||
@ -2147,8 +2161,8 @@ void CPU::Recompiler::ARM32Recompiler::Compile_swx(CompileFlags cf, MemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_swc2(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
void CPU::ARM32Recompiler::Compile_swc2(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
{
|
||||
const u32 index = static_cast<u32>(inst->r.rt.GetValue());
|
||||
const auto [ptr, action] = GetGTERegisterPointer(index, false);
|
||||
@ -2203,7 +2217,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_swc2(CompileFlags cf, MemoryAcces
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_mtc0(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_mtc0(CompileFlags cf)
|
||||
{
|
||||
// TODO: we need better constant setting here.. which will need backprop
|
||||
AssertRegOrConstT(cf);
|
||||
@ -2281,7 +2295,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_mtc0(CompileFlags cf)
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_rfe(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_rfe(CompileFlags cf)
|
||||
{
|
||||
// shift mode bits right two, preserving upper bits
|
||||
armAsm->ldr(RARG1, PTR(&g_state.cop0_regs.sr.bits));
|
||||
@ -2293,7 +2307,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_rfe(CompileFlags cf)
|
||||
TestInterrupts(RARG1);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::TestInterrupts(const vixl::aarch32::Register& sr)
|
||||
void CPU::ARM32Recompiler::TestInterrupts(const vixl::aarch32::Register& sr)
|
||||
{
|
||||
// if Iec == 0 then goto no_interrupt
|
||||
Label no_interrupt;
|
||||
@ -2344,7 +2358,7 @@ void CPU::Recompiler::ARM32Recompiler::TestInterrupts(const vixl::aarch32::Regis
|
||||
armAsm->bind(&no_interrupt);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_mfc2(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_mfc2(CompileFlags cf)
|
||||
{
|
||||
const u32 index = inst->cop.Cop2Index();
|
||||
const Reg rt = inst->r.rt;
|
||||
@ -2385,7 +2399,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_mfc2(CompileFlags cf)
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_mtc2(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_mtc2(CompileFlags cf)
|
||||
{
|
||||
const u32 index = inst->cop.Cop2Index();
|
||||
const auto [ptr, action] = GetGTERegisterPointer(index, true);
|
||||
@ -2447,7 +2461,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_mtc2(CompileFlags cf)
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::ARM32Recompiler::Compile_cop2(CompileFlags cf)
|
||||
void CPU::ARM32Recompiler::Compile_cop2(CompileFlags cf)
|
||||
{
|
||||
TickCount func_ticks;
|
||||
GTE::InstructionImpl func = GTE::GetInstructionImpl(inst->bits, &func_ticks);
|
||||
@ -2514,24 +2528,24 @@ u32 CPU::Recompiler::CompileLoadStoreThunk(void* thunk_code, u32 thunk_space, vo
|
||||
case MemoryAccessSize::Byte:
|
||||
{
|
||||
armEmitCall(armAsm,
|
||||
is_load ? reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedReadMemoryByte) :
|
||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedWriteMemoryByte),
|
||||
is_load ? reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryByte) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryByte),
|
||||
false);
|
||||
}
|
||||
break;
|
||||
case MemoryAccessSize::HalfWord:
|
||||
{
|
||||
armEmitCall(armAsm,
|
||||
is_load ? reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedReadMemoryHalfWord) :
|
||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedWriteMemoryHalfWord),
|
||||
is_load ? reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryHalfWord) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryHalfWord),
|
||||
false);
|
||||
}
|
||||
break;
|
||||
case MemoryAccessSize::Word:
|
||||
{
|
||||
armEmitCall(armAsm,
|
||||
is_load ? reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedReadMemoryWord) :
|
||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedWriteMemoryWord),
|
||||
is_load ? reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryWord) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryWord),
|
||||
false);
|
||||
}
|
||||
break;
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "vixl/aarch32/assembler-aarch32.h"
|
||||
#include "vixl/aarch32/operands-aarch32.h"
|
||||
|
||||
namespace CPU::Recompiler {
|
||||
namespace CPU {
|
||||
|
||||
class ARM32Recompiler final : public Recompiler
|
||||
{
|
||||
@ -165,6 +165,6 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace CPU::Recompiler
|
||||
} // namespace CPU
|
||||
|
||||
#endif // CPU_ARCH_ARM32
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@
|
||||
|
||||
#include "vixl/aarch64/assembler-aarch64.h"
|
||||
|
||||
namespace CPU::Recompiler {
|
||||
namespace CPU {
|
||||
|
||||
class ARM64Recompiler final : public Recompiler
|
||||
{
|
||||
@ -166,6 +166,6 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace CPU::Recompiler
|
||||
} // namespace CPU
|
||||
|
||||
#endif // CPU_ARCH_ARM64
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,9 @@
|
||||
|
||||
#ifdef CPU_ARCH_RISCV64
|
||||
|
||||
namespace CPU::Recompiler {
|
||||
#include "biscuit/assembler.hpp"
|
||||
|
||||
namespace CPU {
|
||||
|
||||
class RISCV64Recompiler final : public Recompiler
|
||||
{
|
||||
@ -171,6 +173,6 @@ private:
|
||||
biscuit::Assembler* rvAsm;
|
||||
};
|
||||
|
||||
} // namespace CPU::Recompiler
|
||||
} // namespace CPU
|
||||
|
||||
#endif // CPU_ARCH_RISCV64
|
||||
|
@ -1,35 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpu_code_cache.h"
|
||||
#include "cpu_types.h"
|
||||
|
||||
namespace CPU::Recompiler::Thunks {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Trampolines for calling back from the JIT
|
||||
// Needed because we can't cast member functions to void*...
|
||||
// TODO: Abuse carry flag or something else for exception
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool InterpretInstruction();
|
||||
bool InterpretInstructionPGXP();
|
||||
|
||||
// Memory access functions for the JIT - MSB is set on exception.
|
||||
u64 ReadMemoryByte(u32 address);
|
||||
u64 ReadMemoryHalfWord(u32 address);
|
||||
u64 ReadMemoryWord(u32 address);
|
||||
u32 WriteMemoryByte(u32 address, u32 value);
|
||||
u32 WriteMemoryHalfWord(u32 address, u32 value);
|
||||
u32 WriteMemoryWord(u32 address, u32 value);
|
||||
|
||||
// Unchecked memory access variants. No alignment or bus exceptions.
|
||||
u32 UncheckedReadMemoryByte(u32 address);
|
||||
u32 UncheckedReadMemoryHalfWord(u32 address);
|
||||
u32 UncheckedReadMemoryWord(u32 address);
|
||||
void UncheckedWriteMemoryByte(u32 address, u32 value);
|
||||
void UncheckedWriteMemoryHalfWord(u32 address, u32 value);
|
||||
void UncheckedWriteMemoryWord(u32 address, u32 value);
|
||||
|
||||
} // namespace CPU::Recompiler::Thunks
|
@ -1,182 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
// Shared code between recompiler backends.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpu_types.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#if defined(CPU_ARCH_X64)
|
||||
|
||||
// We need to include windows.h before xbyak does..
|
||||
#ifdef _WIN32
|
||||
#include "common/windows_headers.h"
|
||||
#endif
|
||||
|
||||
#define XBYAK_NO_OP_NAMES 1
|
||||
#include "xbyak.h"
|
||||
|
||||
namespace CPU::Recompiler {
|
||||
|
||||
// A reasonable "maximum" number of bytes per instruction.
|
||||
constexpr u32 MAX_NEAR_HOST_BYTES_PER_INSTRUCTION = 64;
|
||||
constexpr u32 MAX_FAR_HOST_BYTES_PER_INSTRUCTION = 128;
|
||||
|
||||
// ABI selection
|
||||
#if defined(_WIN32)
|
||||
#define ABI_WIN64 1
|
||||
|
||||
#define RWRET Xbyak::Reg32(Xbyak::Operand::EAX)
|
||||
#define RWARG1 Xbyak::Reg32(Xbyak::Operand::RCX)
|
||||
#define RWARG2 Xbyak::Reg32(Xbyak::Operand::RDX)
|
||||
#define RWARG3 Xbyak::Reg32(Xbyak::Operand::R8D)
|
||||
#define RWARG4 Xbyak::Reg32(Xbyak::Operand::R9D)
|
||||
#define RXRET Xbyak::Reg64(Xbyak::Operand::RAX)
|
||||
#define RXARG1 Xbyak::Reg64(Xbyak::Operand::RCX)
|
||||
#define RXARG2 Xbyak::Reg64(Xbyak::Operand::RDX)
|
||||
#define RXARG3 Xbyak::Reg64(Xbyak::Operand::R8)
|
||||
#define RXARG4 Xbyak::Reg64(Xbyak::Operand::R9)
|
||||
|
||||
static constexpr u32 FUNCTION_CALL_SHADOW_SPACE = 32;
|
||||
|
||||
#elif defined(__linux__) || defined(__ANDROID__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#define ABI_SYSV 1
|
||||
|
||||
#define RWRET Xbyak::Reg32(Xbyak::Operand::EAX)
|
||||
#define RWARG1 Xbyak::Reg32(Xbyak::Operand::EDI)
|
||||
#define RWARG2 Xbyak::Reg32(Xbyak::Operand::ESI)
|
||||
#define RWARG3 Xbyak::Reg32(Xbyak::Operand::EDX)
|
||||
#define RWARG4 Xbyak::Reg32(Xbyak::Operand::ECX)
|
||||
#define RXRET Xbyak::Reg64(Xbyak::Operand::RAX)
|
||||
#define RXARG1 Xbyak::Reg64(Xbyak::Operand::RDI)
|
||||
#define RXARG2 Xbyak::Reg64(Xbyak::Operand::RSI)
|
||||
#define RXARG3 Xbyak::Reg64(Xbyak::Operand::RDX)
|
||||
#define RXARG4 Xbyak::Reg64(Xbyak::Operand::RCX)
|
||||
|
||||
static constexpr u32 FUNCTION_CALL_SHADOW_SPACE = 0;
|
||||
|
||||
#else
|
||||
#error Unknown ABI.
|
||||
#endif
|
||||
|
||||
bool IsCallerSavedRegister(u32 id);
|
||||
|
||||
} // namespace CPU::Recompiler
|
||||
|
||||
#elif defined(CPU_ARCH_ARM32)
|
||||
|
||||
#include "vixl/aarch32/assembler-aarch32.h"
|
||||
#include "vixl/aarch32/constants-aarch32.h"
|
||||
#include "vixl/aarch32/instructions-aarch32.h"
|
||||
|
||||
namespace CPU::Recompiler {
|
||||
|
||||
// A reasonable "maximum" number of bytes per instruction.
|
||||
constexpr u32 MAX_NEAR_HOST_BYTES_PER_INSTRUCTION = 64;
|
||||
constexpr u32 MAX_FAR_HOST_BYTES_PER_INSTRUCTION = 128;
|
||||
|
||||
#define RRET vixl::aarch32::r0
|
||||
#define RRETHI vixl::aarch32::r1
|
||||
#define RARG1 vixl::aarch32::r0
|
||||
#define RARG2 vixl::aarch32::r1
|
||||
#define RARG3 vixl::aarch32::r2
|
||||
#define RSCRATCH vixl::aarch32::r12
|
||||
#define RSTATE vixl::aarch32::r4
|
||||
|
||||
bool armIsCallerSavedRegister(u32 id);
|
||||
s32 armGetPCDisplacement(const void* current, const void* target);
|
||||
bool armIsPCDisplacementInImmediateRange(s32 displacement);
|
||||
void armMoveAddressToReg(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg, const void* addr);
|
||||
void armEmitMov(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& rd, u32 imm);
|
||||
void armEmitJmp(vixl::aarch32::Assembler* armAsm, const void* ptr, bool force_inline);
|
||||
void armEmitCall(vixl::aarch32::Assembler* armAsm, const void* ptr, bool force_inline);
|
||||
void armEmitCondBranch(vixl::aarch32::Assembler* armAsm, vixl::aarch32::Condition cond, const void* ptr);
|
||||
void armEmitFarLoad(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg, const void* addr);
|
||||
void armEmitFarStore(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg, const void* addr,
|
||||
const vixl::aarch32::Register& tempreg = RSCRATCH);
|
||||
u8* armGetJumpTrampoline(const void* target);
|
||||
|
||||
} // namespace CPU::Recompiler
|
||||
|
||||
#elif defined(CPU_ARCH_ARM64)
|
||||
|
||||
#include "vixl/aarch64/assembler-aarch64.h"
|
||||
#include "vixl/aarch64/constants-aarch64.h"
|
||||
|
||||
namespace CPU::Recompiler {
|
||||
|
||||
// A reasonable "maximum" number of bytes per instruction.
|
||||
constexpr u32 MAX_NEAR_HOST_BYTES_PER_INSTRUCTION = 64;
|
||||
constexpr u32 MAX_FAR_HOST_BYTES_PER_INSTRUCTION = 128;
|
||||
|
||||
#define RWRET vixl::aarch64::w0
|
||||
#define RXRET vixl::aarch64::x0
|
||||
#define RWARG1 vixl::aarch64::w0
|
||||
#define RXARG1 vixl::aarch64::x0
|
||||
#define RWARG2 vixl::aarch64::w1
|
||||
#define RXARG2 vixl::aarch64::x1
|
||||
#define RWARG3 vixl::aarch64::w2
|
||||
#define RXARG3 vixl::aarch64::x2
|
||||
#define RWSCRATCH vixl::aarch64::w16
|
||||
#define RXSCRATCH vixl::aarch64::x16
|
||||
#define RSTATE vixl::aarch64::x19
|
||||
#define RMEMBASE vixl::aarch64::x20
|
||||
|
||||
bool armIsCallerSavedRegister(u32 id);
|
||||
s64 armGetPCDisplacement(const void* current, const void* target);
|
||||
bool armIsInAdrpRange(vixl::aarch64::Assembler* armAsm, const void* addr);
|
||||
void armMoveAddressToReg(vixl::aarch64::Assembler* armAsm, const vixl::aarch64::Register& reg, const void* addr);
|
||||
void armEmitMov(vixl::aarch64::Assembler* armAsm, const vixl::aarch64::Register& rd, u64 imm);
|
||||
void armEmitJmp(vixl::aarch64::Assembler* armAsm, const void* ptr, bool force_inline);
|
||||
void armEmitCall(vixl::aarch64::Assembler* armAsm, const void* ptr, bool force_inline);
|
||||
void armEmitCondBranch(vixl::aarch64::Assembler* armAsm, vixl::aarch64::Condition cond, const void* ptr);
|
||||
void armEmitFarLoad(vixl::aarch64::Assembler* armAsm, const vixl::aarch64::Register& reg, const void* addr,
|
||||
bool sign_extend_word = false);
|
||||
void armEmitFarStore(vixl::aarch64::Assembler* armAsm, const vixl::aarch64::Register& reg, const void* addr,
|
||||
const vixl::aarch64::Register& tempreg = RXSCRATCH);
|
||||
u8* armGetJumpTrampoline(const void* target);
|
||||
|
||||
} // namespace CPU::Recompiler
|
||||
|
||||
#elif defined(CPU_ARCH_RISCV64)
|
||||
|
||||
#include "biscuit/assembler.hpp"
|
||||
|
||||
namespace CPU::Recompiler {
|
||||
|
||||
// A reasonable "maximum" number of bytes per instruction.
|
||||
constexpr u32 MAX_NEAR_HOST_BYTES_PER_INSTRUCTION = 64;
|
||||
constexpr u32 MAX_FAR_HOST_BYTES_PER_INSTRUCTION = 128;
|
||||
|
||||
#define RRET biscuit::a0
|
||||
#define RARG1 biscuit::a0
|
||||
#define RARG2 biscuit::a1
|
||||
#define RARG3 biscuit::a2
|
||||
#define RSCRATCH biscuit::t6
|
||||
#define RSTATE biscuit::s10
|
||||
#define RMEMBASE biscuit::s11
|
||||
|
||||
bool rvIsCallerSavedRegister(u32 id);
|
||||
bool rvIsValidSExtITypeImm(u32 imm);
|
||||
std::pair<s32, s32> rvGetAddressImmediates(const void* cur, const void* target);
|
||||
void rvMoveAddressToReg(biscuit::Assembler* armAsm, const biscuit::GPR& reg, const void* addr);
|
||||
void rvEmitMov(biscuit::Assembler* rvAsm, const biscuit::GPR& rd, u32 imm);
|
||||
void rvEmitMov64(biscuit::Assembler* rvAsm, const biscuit::GPR& rd, const biscuit::GPR& scratch, u64 imm);
|
||||
u32 rvEmitJmp(biscuit::Assembler* rvAsm, const void* ptr, const biscuit::GPR& link_reg = biscuit::zero);
|
||||
u32 rvEmitCall(biscuit::Assembler* rvAsm, const void* ptr);
|
||||
void rvEmitFarLoad(biscuit::Assembler* rvAsm, const biscuit::GPR& reg, const void* addr, bool sign_extend_word = false);
|
||||
void rvEmitFarStore(biscuit::Assembler* rvAsm, const biscuit::GPR& reg, const void* addr,
|
||||
const biscuit::GPR& tempreg = RSCRATCH);
|
||||
void rvEmitSExtB(biscuit::Assembler* rvAsm, const biscuit::GPR& rd, const biscuit::GPR& rs); // -> word
|
||||
void rvEmitUExtB(biscuit::Assembler* rvAsm, const biscuit::GPR& rd, const biscuit::GPR& rs); // -> word
|
||||
void rvEmitSExtH(biscuit::Assembler* rvAsm, const biscuit::GPR& rd, const biscuit::GPR& rs); // -> word
|
||||
void rvEmitUExtH(biscuit::Assembler* rvAsm, const biscuit::GPR& rd, const biscuit::GPR& rs); // -> word
|
||||
void rvEmitDSExtW(biscuit::Assembler* rvAsm, const biscuit::GPR& rd, const biscuit::GPR& rs); // -> doubleword
|
||||
void rvEmitDUExtW(biscuit::Assembler* rvAsm, const biscuit::GPR& rd, const biscuit::GPR& rs); // -> doubleword
|
||||
|
||||
} // namespace CPU::Recompiler
|
||||
|
||||
#endif
|
@ -5,8 +5,6 @@
|
||||
#include "cpu_code_cache_private.h"
|
||||
#include "cpu_core_private.h"
|
||||
#include "cpu_pgxp.h"
|
||||
#include "cpu_recompiler_thunks.h"
|
||||
#include "cpu_recompiler_types.h"
|
||||
#include "gte.h"
|
||||
#include "settings.h"
|
||||
#include "timing_event.h"
|
||||
@ -37,25 +35,58 @@ LOG_CHANNEL(Recompiler);
|
||||
// PGXP TODO: LWL etc, MFC0
|
||||
// PGXP TODO: Spyro 1 level gates have issues.
|
||||
|
||||
namespace CPU::Recompiler {
|
||||
|
||||
using namespace Xbyak;
|
||||
|
||||
static constexpr u32 BACKPATCH_JMP_SIZE = 5;
|
||||
|
||||
static bool IsCallerSavedRegister(u32 id);
|
||||
|
||||
// ABI selection
|
||||
#if defined(_WIN32)
|
||||
|
||||
#define RWRET Xbyak::Reg32(Xbyak::Operand::EAX)
|
||||
#define RWARG1 Xbyak::Reg32(Xbyak::Operand::RCX)
|
||||
#define RWARG2 Xbyak::Reg32(Xbyak::Operand::RDX)
|
||||
#define RWARG3 Xbyak::Reg32(Xbyak::Operand::R8D)
|
||||
#define RWARG4 Xbyak::Reg32(Xbyak::Operand::R9D)
|
||||
#define RXRET Xbyak::Reg64(Xbyak::Operand::RAX)
|
||||
#define RXARG1 Xbyak::Reg64(Xbyak::Operand::RCX)
|
||||
#define RXARG2 Xbyak::Reg64(Xbyak::Operand::RDX)
|
||||
#define RXARG3 Xbyak::Reg64(Xbyak::Operand::R8)
|
||||
#define RXARG4 Xbyak::Reg64(Xbyak::Operand::R9)
|
||||
|
||||
// on win32, we need to reserve an additional 32 bytes shadow space when calling out to C
|
||||
#ifdef _WIN32
|
||||
static constexpr u32 STACK_SHADOW_SIZE = 32;
|
||||
#else
|
||||
|
||||
#elif defined(__linux__) || defined(__ANDROID__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
|
||||
#define RWRET Xbyak::Reg32(Xbyak::Operand::EAX)
|
||||
#define RWARG1 Xbyak::Reg32(Xbyak::Operand::EDI)
|
||||
#define RWARG2 Xbyak::Reg32(Xbyak::Operand::ESI)
|
||||
#define RWARG3 Xbyak::Reg32(Xbyak::Operand::EDX)
|
||||
#define RWARG4 Xbyak::Reg32(Xbyak::Operand::ECX)
|
||||
#define RXRET Xbyak::Reg64(Xbyak::Operand::RAX)
|
||||
#define RXARG1 Xbyak::Reg64(Xbyak::Operand::RDI)
|
||||
#define RXARG2 Xbyak::Reg64(Xbyak::Operand::RSI)
|
||||
#define RXARG3 Xbyak::Reg64(Xbyak::Operand::RDX)
|
||||
#define RXARG4 Xbyak::Reg64(Xbyak::Operand::RCX)
|
||||
|
||||
static constexpr u32 STACK_SHADOW_SIZE = 0;
|
||||
|
||||
#else
|
||||
|
||||
#error Unknown ABI.
|
||||
|
||||
#endif
|
||||
|
||||
namespace CPU {
|
||||
|
||||
using namespace Xbyak;
|
||||
|
||||
static X64Recompiler s_instance;
|
||||
Recompiler* g_compiler = &s_instance;
|
||||
|
||||
} // namespace CPU::Recompiler
|
||||
} // namespace CPU
|
||||
|
||||
bool CPU::Recompiler::IsCallerSavedRegister(u32 id)
|
||||
bool IsCallerSavedRegister(u32 id)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// The x64 ABI considers the registers RAX, RCX, RDX, R8, R9, R10, R11, and XMM0-XMM5 volatile.
|
||||
@ -330,12 +361,12 @@ u32 CPU::CodeCache::GetHostInstructionCount(const void* start, u32 size)
|
||||
|
||||
#endif // ENABLE_HOST_DISASSEMBLY
|
||||
|
||||
CPU::Recompiler::X64Recompiler::X64Recompiler() = default;
|
||||
CPU::X64Recompiler::X64Recompiler() = default;
|
||||
|
||||
CPU::Recompiler::X64Recompiler::~X64Recompiler() = default;
|
||||
CPU::X64Recompiler::~X64Recompiler() = default;
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Reset(CodeCache::Block* block, u8* code_buffer, u32 code_buffer_space,
|
||||
u8* far_code_buffer, u32 far_code_space)
|
||||
void CPU::X64Recompiler::Reset(CodeCache::Block* block, u8* code_buffer, u32 code_buffer_space, u8* far_code_buffer,
|
||||
u32 far_code_space)
|
||||
{
|
||||
Recompiler::Reset(block, code_buffer, code_buffer_space, far_code_buffer, far_code_space);
|
||||
|
||||
@ -366,7 +397,7 @@ void CPU::Recompiler::X64Recompiler::Reset(CodeCache::Block* block, u8* code_buf
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::SwitchToFarCode(bool emit_jump, void (Xbyak::CodeGenerator::*jump_op)(const void*))
|
||||
void CPU::X64Recompiler::SwitchToFarCode(bool emit_jump, void (Xbyak::CodeGenerator::*jump_op)(const void*))
|
||||
{
|
||||
DebugAssert(cg == m_emitter.get());
|
||||
if (emit_jump)
|
||||
@ -377,8 +408,7 @@ void CPU::Recompiler::X64Recompiler::SwitchToFarCode(bool emit_jump, void (Xbyak
|
||||
cg = m_far_emitter.get();
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::SwitchToNearCode(bool emit_jump,
|
||||
void (Xbyak::CodeGenerator::*jump_op)(const void*))
|
||||
void CPU::X64Recompiler::SwitchToNearCode(bool emit_jump, void (Xbyak::CodeGenerator::*jump_op)(const void*))
|
||||
{
|
||||
DebugAssert(cg == m_far_emitter.get());
|
||||
if (emit_jump)
|
||||
@ -389,7 +419,7 @@ void CPU::Recompiler::X64Recompiler::SwitchToNearCode(bool emit_jump,
|
||||
cg = m_emitter.get();
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::BeginBlock()
|
||||
void CPU::X64Recompiler::BeginBlock()
|
||||
{
|
||||
Recompiler::BeginBlock();
|
||||
|
||||
@ -408,7 +438,7 @@ void CPU::Recompiler::X64Recompiler::BeginBlock()
|
||||
#endif
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::GenerateBlockProtectCheck(const u8* ram_ptr, const u8* shadow_ptr, u32 size)
|
||||
void CPU::X64Recompiler::GenerateBlockProtectCheck(const u8* ram_ptr, const u8* shadow_ptr, u32 size)
|
||||
{
|
||||
// store it first to reduce code size, because we can offset
|
||||
cg->mov(RXARG1, static_cast<size_t>(reinterpret_cast<uintptr_t>(ram_ptr)));
|
||||
@ -459,7 +489,7 @@ void CPU::Recompiler::X64Recompiler::GenerateBlockProtectCheck(const u8* ram_ptr
|
||||
DebugAssert(size == 0);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::GenerateICacheCheckAndUpdate()
|
||||
void CPU::X64Recompiler::GenerateICacheCheckAndUpdate()
|
||||
{
|
||||
if (!m_block->HasFlag(CodeCache::BlockFlags::IsUsingICache))
|
||||
{
|
||||
@ -500,8 +530,8 @@ void CPU::Recompiler::X64Recompiler::GenerateICacheCheckAndUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::GenerateCall(const void* func, s32 arg1reg /*= -1*/, s32 arg2reg /*= -1*/,
|
||||
s32 arg3reg /*= -1*/)
|
||||
void CPU::X64Recompiler::GenerateCall(const void* func, s32 arg1reg /*= -1*/, s32 arg2reg /*= -1*/,
|
||||
s32 arg3reg /*= -1*/)
|
||||
{
|
||||
if (arg1reg >= 0 && arg1reg != static_cast<s32>(RXARG1.getIdx()))
|
||||
cg->mov(RXARG1, Reg64(arg1reg));
|
||||
@ -512,7 +542,7 @@ void CPU::Recompiler::X64Recompiler::GenerateCall(const void* func, s32 arg1reg
|
||||
cg->call(func);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::EndBlock(const std::optional<u32>& newpc, bool do_event_test)
|
||||
void CPU::X64Recompiler::EndBlock(const std::optional<u32>& newpc, bool do_event_test)
|
||||
{
|
||||
if (newpc.has_value())
|
||||
{
|
||||
@ -526,7 +556,7 @@ void CPU::Recompiler::X64Recompiler::EndBlock(const std::optional<u32>& newpc, b
|
||||
EndAndLinkBlock(newpc, do_event_test, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::EndBlockWithException(Exception excode)
|
||||
void CPU::X64Recompiler::EndBlockWithException(Exception excode)
|
||||
{
|
||||
// flush regs, but not pc, it's going to get overwritten
|
||||
// flush cycles because of the GTE instruction stuff...
|
||||
@ -544,8 +574,7 @@ void CPU::Recompiler::X64Recompiler::EndBlockWithException(Exception excode)
|
||||
EndAndLinkBlock(std::nullopt, true, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::EndAndLinkBlock(const std::optional<u32>& newpc, bool do_event_test,
|
||||
bool force_run_events)
|
||||
void CPU::X64Recompiler::EndAndLinkBlock(const std::optional<u32>& newpc, bool do_event_test, bool force_run_events)
|
||||
{
|
||||
// event test
|
||||
// pc should've been flushed
|
||||
@ -614,7 +643,7 @@ void CPU::Recompiler::X64Recompiler::EndAndLinkBlock(const std::optional<u32>& n
|
||||
}
|
||||
}
|
||||
|
||||
const void* CPU::Recompiler::X64Recompiler::EndCompile(u32* code_size, u32* far_code_size)
|
||||
const void* CPU::X64Recompiler::EndCompile(u32* code_size, u32* far_code_size)
|
||||
{
|
||||
const void* code = m_emitter->getCode();
|
||||
*code_size = static_cast<u32>(m_emitter->getSize());
|
||||
@ -625,81 +654,81 @@ const void* CPU::Recompiler::X64Recompiler::EndCompile(u32* code_size, u32* far_
|
||||
return code;
|
||||
}
|
||||
|
||||
const void* CPU::Recompiler::X64Recompiler::GetCurrentCodePointer()
|
||||
const void* CPU::X64Recompiler::GetCurrentCodePointer()
|
||||
{
|
||||
return cg->getCurr();
|
||||
}
|
||||
|
||||
const char* CPU::Recompiler::X64Recompiler::GetHostRegName(u32 reg) const
|
||||
const char* CPU::X64Recompiler::GetHostRegName(u32 reg) const
|
||||
{
|
||||
static constexpr std::array<const char*, 16> reg64_names = {
|
||||
{"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}};
|
||||
return (reg < reg64_names.size()) ? reg64_names[reg] : "UNKNOWN";
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::LoadHostRegWithConstant(u32 reg, u32 val)
|
||||
void CPU::X64Recompiler::LoadHostRegWithConstant(u32 reg, u32 val)
|
||||
{
|
||||
cg->mov(Reg32(reg), val);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::LoadHostRegFromCPUPointer(u32 reg, const void* ptr)
|
||||
void CPU::X64Recompiler::LoadHostRegFromCPUPointer(u32 reg, const void* ptr)
|
||||
{
|
||||
cg->mov(Reg32(reg), cg->dword[PTR(ptr)]);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::StoreHostRegToCPUPointer(u32 reg, const void* ptr)
|
||||
void CPU::X64Recompiler::StoreHostRegToCPUPointer(u32 reg, const void* ptr)
|
||||
{
|
||||
cg->mov(cg->dword[PTR(ptr)], Reg32(reg));
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::StoreConstantToCPUPointer(u32 val, const void* ptr)
|
||||
void CPU::X64Recompiler::StoreConstantToCPUPointer(u32 val, const void* ptr)
|
||||
{
|
||||
cg->mov(cg->dword[PTR(ptr)], val);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::CopyHostReg(u32 dst, u32 src)
|
||||
void CPU::X64Recompiler::CopyHostReg(u32 dst, u32 src)
|
||||
{
|
||||
if (src != dst)
|
||||
cg->mov(Reg32(dst), Reg32(src));
|
||||
}
|
||||
|
||||
Xbyak::Address CPU::Recompiler::X64Recompiler::MipsPtr(Reg r) const
|
||||
Xbyak::Address CPU::X64Recompiler::MipsPtr(Reg r) const
|
||||
{
|
||||
DebugAssert(r < Reg::count);
|
||||
return cg->dword[PTR(&g_state.regs.r[static_cast<u32>(r)])];
|
||||
}
|
||||
|
||||
Xbyak::Reg32 CPU::Recompiler::X64Recompiler::CFGetRegD(CompileFlags cf) const
|
||||
Xbyak::Reg32 CPU::X64Recompiler::CFGetRegD(CompileFlags cf) const
|
||||
{
|
||||
DebugAssert(cf.valid_host_d);
|
||||
return Reg32(cf.host_d);
|
||||
}
|
||||
|
||||
Xbyak::Reg32 CPU::Recompiler::X64Recompiler::CFGetRegS(CompileFlags cf) const
|
||||
Xbyak::Reg32 CPU::X64Recompiler::CFGetRegS(CompileFlags cf) const
|
||||
{
|
||||
DebugAssert(cf.valid_host_s);
|
||||
return Reg32(cf.host_s);
|
||||
}
|
||||
|
||||
Xbyak::Reg32 CPU::Recompiler::X64Recompiler::CFGetRegT(CompileFlags cf) const
|
||||
Xbyak::Reg32 CPU::X64Recompiler::CFGetRegT(CompileFlags cf) const
|
||||
{
|
||||
DebugAssert(cf.valid_host_t);
|
||||
return Reg32(cf.host_t);
|
||||
}
|
||||
|
||||
Xbyak::Reg32 CPU::Recompiler::X64Recompiler::CFGetRegLO(CompileFlags cf) const
|
||||
Xbyak::Reg32 CPU::X64Recompiler::CFGetRegLO(CompileFlags cf) const
|
||||
{
|
||||
DebugAssert(cf.valid_host_lo);
|
||||
return Reg32(cf.host_lo);
|
||||
}
|
||||
|
||||
Xbyak::Reg32 CPU::Recompiler::X64Recompiler::CFGetRegHI(CompileFlags cf) const
|
||||
Xbyak::Reg32 CPU::X64Recompiler::CFGetRegHI(CompileFlags cf) const
|
||||
{
|
||||
DebugAssert(cf.valid_host_hi);
|
||||
return Reg32(cf.host_hi);
|
||||
}
|
||||
|
||||
Xbyak::Reg32 CPU::Recompiler::X64Recompiler::MoveSToD(CompileFlags cf)
|
||||
Xbyak::Reg32 CPU::X64Recompiler::MoveSToD(CompileFlags cf)
|
||||
{
|
||||
DebugAssert(cf.valid_host_d);
|
||||
DebugAssert(!cf.valid_host_t || cf.host_t != cf.host_d);
|
||||
@ -710,7 +739,7 @@ Xbyak::Reg32 CPU::Recompiler::X64Recompiler::MoveSToD(CompileFlags cf)
|
||||
return rd;
|
||||
}
|
||||
|
||||
Xbyak::Reg32 CPU::Recompiler::X64Recompiler::MoveSToT(CompileFlags cf)
|
||||
Xbyak::Reg32 CPU::X64Recompiler::MoveSToT(CompileFlags cf)
|
||||
{
|
||||
DebugAssert(cf.valid_host_t);
|
||||
|
||||
@ -736,7 +765,7 @@ Xbyak::Reg32 CPU::Recompiler::X64Recompiler::MoveSToT(CompileFlags cf)
|
||||
return rt;
|
||||
}
|
||||
|
||||
Xbyak::Reg32 CPU::Recompiler::X64Recompiler::MoveTToD(CompileFlags cf)
|
||||
Xbyak::Reg32 CPU::X64Recompiler::MoveTToD(CompileFlags cf)
|
||||
{
|
||||
DebugAssert(cf.valid_host_d);
|
||||
DebugAssert(!cf.valid_host_s || cf.host_s != cf.host_d);
|
||||
@ -746,7 +775,7 @@ Xbyak::Reg32 CPU::Recompiler::X64Recompiler::MoveTToD(CompileFlags cf)
|
||||
return rd;
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::MoveSToReg(const Xbyak::Reg32& dst, CompileFlags cf)
|
||||
void CPU::X64Recompiler::MoveSToReg(const Xbyak::Reg32& dst, CompileFlags cf)
|
||||
{
|
||||
if (cf.valid_host_s)
|
||||
{
|
||||
@ -767,7 +796,7 @@ void CPU::Recompiler::X64Recompiler::MoveSToReg(const Xbyak::Reg32& dst, Compile
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::MoveTToReg(const Xbyak::Reg32& dst, CompileFlags cf)
|
||||
void CPU::X64Recompiler::MoveTToReg(const Xbyak::Reg32& dst, CompileFlags cf)
|
||||
{
|
||||
if (cf.valid_host_t)
|
||||
{
|
||||
@ -788,7 +817,7 @@ void CPU::Recompiler::X64Recompiler::MoveTToReg(const Xbyak::Reg32& dst, Compile
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::MoveMIPSRegToReg(const Xbyak::Reg32& dst, Reg reg)
|
||||
void CPU::X64Recompiler::MoveMIPSRegToReg(const Xbyak::Reg32& dst, Reg reg)
|
||||
{
|
||||
DebugAssert(reg < Reg::count);
|
||||
if (const std::optional<u32> hreg = CheckHostReg(0, Recompiler::HR_TYPE_CPU_REG, reg))
|
||||
@ -799,9 +828,8 @@ void CPU::Recompiler::X64Recompiler::MoveMIPSRegToReg(const Xbyak::Reg32& dst, R
|
||||
cg->mov(dst, MipsPtr(reg));
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::GeneratePGXPCallWithMIPSRegs(const void* func, u32 arg1val,
|
||||
Reg arg2reg /* = Reg::count */,
|
||||
Reg arg3reg /* = Reg::count */)
|
||||
void CPU::X64Recompiler::GeneratePGXPCallWithMIPSRegs(const void* func, u32 arg1val, Reg arg2reg /* = Reg::count */,
|
||||
Reg arg3reg /* = Reg::count */)
|
||||
{
|
||||
DebugAssert(g_settings.gpu_pgxp_enable);
|
||||
|
||||
@ -816,7 +844,7 @@ void CPU::Recompiler::X64Recompiler::GeneratePGXPCallWithMIPSRegs(const void* fu
|
||||
cg->call(func);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Flush(u32 flags)
|
||||
void CPU::X64Recompiler::Flush(u32 flags)
|
||||
{
|
||||
Recompiler::Flush(flags);
|
||||
|
||||
@ -899,13 +927,13 @@ void CPU::Recompiler::X64Recompiler::Flush(u32 flags)
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_Fallback()
|
||||
void CPU::X64Recompiler::Compile_Fallback()
|
||||
{
|
||||
WARNING_LOG("Compiling instruction fallback at PC=0x{:08X}, instruction=0x{:08X}", iinfo->pc, inst->bits);
|
||||
|
||||
Flush(FLUSH_FOR_INTERPRETER);
|
||||
|
||||
cg->call(&CPU::Recompiler::Thunks::InterpretInstruction);
|
||||
cg->call(&CPU::RecompilerThunks::InterpretInstruction);
|
||||
|
||||
// TODO: make me less garbage
|
||||
// TODO: this is wrong, it flushes the load delay on the same cycle when we return.
|
||||
@ -923,7 +951,7 @@ void CPU::Recompiler::X64Recompiler::Compile_Fallback()
|
||||
m_load_delay_dirty = EMULATE_LOAD_DELAYS;
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::CheckBranchTarget(const Xbyak::Reg32& pcreg)
|
||||
void CPU::X64Recompiler::CheckBranchTarget(const Xbyak::Reg32& pcreg)
|
||||
{
|
||||
if (!g_settings.cpu_recompiler_memory_exceptions)
|
||||
return;
|
||||
@ -938,7 +966,7 @@ void CPU::Recompiler::X64Recompiler::CheckBranchTarget(const Xbyak::Reg32& pcreg
|
||||
SwitchToNearCode(false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_jr(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_jr(CompileFlags cf)
|
||||
{
|
||||
if (!cf.valid_host_s)
|
||||
cg->mov(RWARG1, MipsPtr(cf.MipsS()));
|
||||
@ -952,7 +980,7 @@ void CPU::Recompiler::X64Recompiler::Compile_jr(CompileFlags cf)
|
||||
EndBlock(std::nullopt, true);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_jalr(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_jalr(CompileFlags cf)
|
||||
{
|
||||
if (!cf.valid_host_s)
|
||||
cg->mov(RWARG1, MipsPtr(cf.MipsS()));
|
||||
@ -969,7 +997,7 @@ void CPU::Recompiler::X64Recompiler::Compile_jalr(CompileFlags cf)
|
||||
EndBlock(std::nullopt, true);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_bxx(CompileFlags cf, BranchCondition cond)
|
||||
void CPU::X64Recompiler::Compile_bxx(CompileFlags cf, BranchCondition cond)
|
||||
{
|
||||
const u32 taken_pc = GetConditionalBranchTarget(cf);
|
||||
|
||||
@ -1045,7 +1073,7 @@ void CPU::Recompiler::X64Recompiler::Compile_bxx(CompileFlags cf, BranchConditio
|
||||
EndBlock(taken_pc, true);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_addi(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_addi(CompileFlags cf)
|
||||
{
|
||||
const Reg32 rt = MoveSToT(cf);
|
||||
if (const u32 imm = inst->i.imm_sext32(); imm != 0)
|
||||
@ -1059,24 +1087,24 @@ void CPU::Recompiler::X64Recompiler::Compile_addi(CompileFlags cf)
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_addiu(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_addiu(CompileFlags cf)
|
||||
{
|
||||
const Reg32 rt = MoveSToT(cf);
|
||||
if (const u32 imm = inst->i.imm_sext32(); imm != 0)
|
||||
cg->add(rt, imm);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_slti(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_slti(CompileFlags cf)
|
||||
{
|
||||
Compile_slti(cf, true);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_sltiu(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_sltiu(CompileFlags cf)
|
||||
{
|
||||
Compile_slti(cf, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_slti(CompileFlags cf, bool sign)
|
||||
void CPU::X64Recompiler::Compile_slti(CompileFlags cf, bool sign)
|
||||
{
|
||||
const Reg32 rt = cf.valid_host_t ? CFGetRegT(cf) : RWARG1;
|
||||
|
||||
@ -1098,7 +1126,7 @@ void CPU::Recompiler::X64Recompiler::Compile_slti(CompileFlags cf, bool sign)
|
||||
cg->mov(MipsPtr(cf.MipsT()), rt);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_andi(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_andi(CompileFlags cf)
|
||||
{
|
||||
if (const u32 imm = inst->i.imm_zext32(); imm != 0)
|
||||
{
|
||||
@ -1112,44 +1140,45 @@ void CPU::Recompiler::X64Recompiler::Compile_andi(CompileFlags cf)
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_ori(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_ori(CompileFlags cf)
|
||||
{
|
||||
const Reg32 rt = MoveSToT(cf);
|
||||
if (const u32 imm = inst->i.imm_zext32(); imm != 0)
|
||||
cg->or_(rt, imm);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_xori(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_xori(CompileFlags cf)
|
||||
{
|
||||
const Reg32 rt = MoveSToT(cf);
|
||||
if (const u32 imm = inst->i.imm_zext32(); imm != 0)
|
||||
cg->xor_(rt, imm);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_sll(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_sll(CompileFlags cf)
|
||||
{
|
||||
const Reg32 rd = MoveTToD(cf);
|
||||
if (inst->r.shamt > 0)
|
||||
cg->shl(rd, inst->r.shamt);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_srl(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_srl(CompileFlags cf)
|
||||
{
|
||||
const Reg32 rd = MoveTToD(cf);
|
||||
if (inst->r.shamt > 0)
|
||||
cg->shr(rd, inst->r.shamt);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_sra(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_sra(CompileFlags cf)
|
||||
{
|
||||
const Reg32 rd = MoveTToD(cf);
|
||||
if (inst->r.shamt > 0)
|
||||
cg->sar(rd, inst->r.shamt);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_variable_shift(
|
||||
CompileFlags cf, void (Xbyak::CodeGenerator::*op)(const Xbyak::Operand&, const Xbyak::Reg8&),
|
||||
void (Xbyak::CodeGenerator::*op_const)(const Xbyak::Operand&, int))
|
||||
void CPU::X64Recompiler::Compile_variable_shift(CompileFlags cf,
|
||||
void (Xbyak::CodeGenerator::*op)(const Xbyak::Operand&,
|
||||
const Xbyak::Reg8&),
|
||||
void (Xbyak::CodeGenerator::*op_const)(const Xbyak::Operand&, int))
|
||||
{
|
||||
const Reg32 rd = CFGetRegD(cf);
|
||||
if (!cf.const_s)
|
||||
@ -1165,22 +1194,22 @@ void CPU::Recompiler::X64Recompiler::Compile_variable_shift(
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_sllv(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_sllv(CompileFlags cf)
|
||||
{
|
||||
Compile_variable_shift(cf, &CodeGenerator::shl, &CodeGenerator::shl);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_srlv(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_srlv(CompileFlags cf)
|
||||
{
|
||||
Compile_variable_shift(cf, &CodeGenerator::shr, &CodeGenerator::shr);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_srav(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_srav(CompileFlags cf)
|
||||
{
|
||||
Compile_variable_shift(cf, &CodeGenerator::sar, &CodeGenerator::sar);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_mult(CompileFlags cf, bool sign)
|
||||
void CPU::X64Recompiler::Compile_mult(CompileFlags cf, bool sign)
|
||||
{
|
||||
// RAX/RDX shouldn't be allocatable..
|
||||
DebugAssert(!(m_host_regs[Xbyak::Operand::RAX].flags & HR_USABLE) &&
|
||||
@ -1212,17 +1241,17 @@ void CPU::Recompiler::X64Recompiler::Compile_mult(CompileFlags cf, bool sign)
|
||||
cg->mov(MipsPtr(Reg::hi), cg->edx);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_mult(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_mult(CompileFlags cf)
|
||||
{
|
||||
Compile_mult(cf, true);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_multu(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_multu(CompileFlags cf)
|
||||
{
|
||||
Compile_mult(cf, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_div(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_div(CompileFlags cf)
|
||||
{
|
||||
// not supported without registers for now..
|
||||
DebugAssert(cf.valid_host_lo && cf.valid_host_hi);
|
||||
@ -1268,7 +1297,7 @@ void CPU::Recompiler::X64Recompiler::Compile_div(CompileFlags cf)
|
||||
cg->L(done);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_divu(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_divu(CompileFlags cf)
|
||||
{
|
||||
// not supported without registers for now..
|
||||
DebugAssert(cf.valid_host_lo && cf.valid_host_hi);
|
||||
@ -1299,7 +1328,7 @@ void CPU::Recompiler::X64Recompiler::Compile_divu(CompileFlags cf)
|
||||
cg->L(done);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::TestOverflow(const Xbyak::Reg32& result)
|
||||
void CPU::X64Recompiler::TestOverflow(const Xbyak::Reg32& result)
|
||||
{
|
||||
SwitchToFarCode(true, &Xbyak::CodeGenerator::jo);
|
||||
|
||||
@ -1315,9 +1344,10 @@ void CPU::Recompiler::X64Recompiler::TestOverflow(const Xbyak::Reg32& result)
|
||||
SwitchToNearCode(false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_dst_op(
|
||||
CompileFlags cf, void (Xbyak::CodeGenerator::*op)(const Xbyak::Operand&, const Xbyak::Operand&),
|
||||
void (Xbyak::CodeGenerator::*op_const)(const Xbyak::Operand&, u32), bool commutative, bool overflow)
|
||||
void CPU::X64Recompiler::Compile_dst_op(CompileFlags cf,
|
||||
void (Xbyak::CodeGenerator::*op)(const Xbyak::Operand&, const Xbyak::Operand&),
|
||||
void (Xbyak::CodeGenerator::*op_const)(const Xbyak::Operand&, u32),
|
||||
bool commutative, bool overflow)
|
||||
{
|
||||
if (cf.valid_host_s && cf.valid_host_t)
|
||||
{
|
||||
@ -1401,27 +1431,27 @@ void CPU::Recompiler::X64Recompiler::Compile_dst_op(
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_add(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_add(CompileFlags cf)
|
||||
{
|
||||
Compile_dst_op(cf, &CodeGenerator::add, &CodeGenerator::add, true, g_settings.cpu_recompiler_memory_exceptions);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_addu(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_addu(CompileFlags cf)
|
||||
{
|
||||
Compile_dst_op(cf, &CodeGenerator::add, &CodeGenerator::add, true, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_sub(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_sub(CompileFlags cf)
|
||||
{
|
||||
Compile_dst_op(cf, &CodeGenerator::sub, &CodeGenerator::sub, false, g_settings.cpu_recompiler_memory_exceptions);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_subu(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_subu(CompileFlags cf)
|
||||
{
|
||||
Compile_dst_op(cf, &CodeGenerator::sub, &CodeGenerator::sub, false, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_and(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_and(CompileFlags cf)
|
||||
{
|
||||
// special cases - and with self -> self, and with 0 -> 0
|
||||
const Reg32 regd = CFGetRegD(cf);
|
||||
@ -1439,7 +1469,7 @@ void CPU::Recompiler::X64Recompiler::Compile_and(CompileFlags cf)
|
||||
Compile_dst_op(cf, &CodeGenerator::and_, &CodeGenerator::and_, true, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_or(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_or(CompileFlags cf)
|
||||
{
|
||||
// or/nor with 0 -> no effect
|
||||
const Reg32 regd = CFGetRegD(cf);
|
||||
@ -1452,7 +1482,7 @@ void CPU::Recompiler::X64Recompiler::Compile_or(CompileFlags cf)
|
||||
Compile_dst_op(cf, &CodeGenerator::or_, &CodeGenerator::or_, true, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_xor(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_xor(CompileFlags cf)
|
||||
{
|
||||
const Reg32 regd = CFGetRegD(cf);
|
||||
if (cf.MipsS() == cf.MipsT())
|
||||
@ -1471,23 +1501,23 @@ void CPU::Recompiler::X64Recompiler::Compile_xor(CompileFlags cf)
|
||||
Compile_dst_op(cf, &CodeGenerator::xor_, &CodeGenerator::xor_, true, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_nor(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_nor(CompileFlags cf)
|
||||
{
|
||||
Compile_or(cf);
|
||||
cg->not_(CFGetRegD(cf));
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_slt(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_slt(CompileFlags cf)
|
||||
{
|
||||
Compile_slt(cf, true);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_sltu(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_sltu(CompileFlags cf)
|
||||
{
|
||||
Compile_slt(cf, false);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_slt(CompileFlags cf, bool sign)
|
||||
void CPU::X64Recompiler::Compile_slt(CompileFlags cf, bool sign)
|
||||
{
|
||||
const Reg32 rd = CFGetRegD(cf);
|
||||
const Reg32 rs = cf.valid_host_s ? CFGetRegS(cf) : RWARG1;
|
||||
@ -1513,9 +1543,9 @@ void CPU::Recompiler::X64Recompiler::Compile_slt(CompileFlags cf, bool sign)
|
||||
sign ? cg->setl(rd.cvt8()) : cg->setb(rd.cvt8());
|
||||
}
|
||||
|
||||
Xbyak::Reg32 CPU::Recompiler::X64Recompiler::ComputeLoadStoreAddressArg(
|
||||
CompileFlags cf, const std::optional<VirtualMemoryAddress>& address,
|
||||
const std::optional<const Xbyak::Reg32>& reg /* = std::nullopt */)
|
||||
Xbyak::Reg32
|
||||
CPU::X64Recompiler::ComputeLoadStoreAddressArg(CompileFlags cf, const std::optional<VirtualMemoryAddress>& address,
|
||||
const std::optional<const Xbyak::Reg32>& reg /* = std::nullopt */)
|
||||
{
|
||||
const u32 imm = inst->i.imm_sext32();
|
||||
if (cf.valid_host_s && imm == 0 && !reg.has_value())
|
||||
@ -1546,8 +1576,8 @@ Xbyak::Reg32 CPU::Recompiler::X64Recompiler::ComputeLoadStoreAddressArg(
|
||||
}
|
||||
|
||||
template<typename RegAllocFn>
|
||||
Xbyak::Reg32 CPU::Recompiler::X64Recompiler::GenerateLoad(const Xbyak::Reg32& addr_reg, MemoryAccessSize size,
|
||||
bool sign, bool use_fastmem, const RegAllocFn& dst_reg_alloc)
|
||||
Xbyak::Reg32 CPU::X64Recompiler::GenerateLoad(const Xbyak::Reg32& addr_reg, MemoryAccessSize size, bool sign,
|
||||
bool use_fastmem, const RegAllocFn& dst_reg_alloc)
|
||||
{
|
||||
if (use_fastmem)
|
||||
{
|
||||
@ -1608,20 +1638,20 @@ Xbyak::Reg32 CPU::Recompiler::X64Recompiler::GenerateLoad(const Xbyak::Reg32& ad
|
||||
{
|
||||
case MemoryAccessSize::Byte:
|
||||
{
|
||||
cg->call(checked ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::ReadMemoryByte) :
|
||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedReadMemoryByte));
|
||||
cg->call(checked ? reinterpret_cast<const void*>(&RecompilerThunks::ReadMemoryByte) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryByte));
|
||||
}
|
||||
break;
|
||||
case MemoryAccessSize::HalfWord:
|
||||
{
|
||||
cg->call(checked ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::ReadMemoryHalfWord) :
|
||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedReadMemoryHalfWord));
|
||||
cg->call(checked ? reinterpret_cast<const void*>(&RecompilerThunks::ReadMemoryHalfWord) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryHalfWord));
|
||||
}
|
||||
break;
|
||||
case MemoryAccessSize::Word:
|
||||
{
|
||||
cg->call(checked ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::ReadMemoryWord) :
|
||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedReadMemoryWord));
|
||||
cg->call(checked ? reinterpret_cast<const void*>(&RecompilerThunks::ReadMemoryWord) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryWord));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1677,8 +1707,8 @@ Xbyak::Reg32 CPU::Recompiler::X64Recompiler::GenerateLoad(const Xbyak::Reg32& ad
|
||||
return dst_reg;
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::GenerateStore(const Xbyak::Reg32& addr_reg, const Xbyak::Reg32& value_reg,
|
||||
MemoryAccessSize size, bool use_fastmem)
|
||||
void CPU::X64Recompiler::GenerateStore(const Xbyak::Reg32& addr_reg, const Xbyak::Reg32& value_reg,
|
||||
MemoryAccessSize size, bool use_fastmem)
|
||||
{
|
||||
if (use_fastmem)
|
||||
{
|
||||
@ -1729,20 +1759,20 @@ void CPU::Recompiler::X64Recompiler::GenerateStore(const Xbyak::Reg32& addr_reg,
|
||||
{
|
||||
case MemoryAccessSize::Byte:
|
||||
{
|
||||
cg->call(checked ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::WriteMemoryByte) :
|
||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedWriteMemoryByte));
|
||||
cg->call(checked ? reinterpret_cast<const void*>(&RecompilerThunks::WriteMemoryByte) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryByte));
|
||||
}
|
||||
break;
|
||||
case MemoryAccessSize::HalfWord:
|
||||
{
|
||||
cg->call(checked ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::WriteMemoryHalfWord) :
|
||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedWriteMemoryHalfWord));
|
||||
cg->call(checked ? reinterpret_cast<const void*>(&RecompilerThunks::WriteMemoryHalfWord) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryHalfWord));
|
||||
}
|
||||
break;
|
||||
case MemoryAccessSize::Word:
|
||||
{
|
||||
cg->call(checked ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::WriteMemoryWord) :
|
||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedWriteMemoryWord));
|
||||
cg->call(checked ? reinterpret_cast<const void*>(&RecompilerThunks::WriteMemoryWord) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryWord));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1774,8 +1804,8 @@ void CPU::Recompiler::X64Recompiler::GenerateStore(const Xbyak::Reg32& addr_reg,
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_lxx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
void CPU::X64Recompiler::Compile_lxx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
{
|
||||
const std::optional<Reg32> addr_reg = g_settings.gpu_pgxp_enable ?
|
||||
std::optional<Reg32>(Reg32(AllocateTempHostReg(HR_CALLEE_SAVED))) :
|
||||
@ -1803,8 +1833,8 @@ void CPU::Recompiler::X64Recompiler::Compile_lxx(CompileFlags cf, MemoryAccessSi
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_lwx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
void CPU::X64Recompiler::Compile_lwx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
{
|
||||
DebugAssert(size == MemoryAccessSize::Word && !sign);
|
||||
|
||||
@ -1907,8 +1937,8 @@ void CPU::Recompiler::X64Recompiler::Compile_lwx(CompileFlags cf, MemoryAccessSi
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_lwc2(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
void CPU::X64Recompiler::Compile_lwc2(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
{
|
||||
const u32 index = static_cast<u32>(inst->r.rt.GetValue());
|
||||
const auto [ptr, action] = GetGTERegisterPointer(index, true);
|
||||
@ -1993,8 +2023,8 @@ void CPU::Recompiler::X64Recompiler::Compile_lwc2(CompileFlags cf, MemoryAccessS
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_sxx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
void CPU::X64Recompiler::Compile_sxx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
{
|
||||
const std::optional<Reg32> addr_reg = g_settings.gpu_pgxp_enable ?
|
||||
std::optional<Reg32>(Reg32(AllocateTempHostReg(HR_CALLEE_SAVED))) :
|
||||
@ -2018,8 +2048,8 @@ void CPU::Recompiler::X64Recompiler::Compile_sxx(CompileFlags cf, MemoryAccessSi
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_swx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
void CPU::X64Recompiler::Compile_swx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
{
|
||||
DebugAssert(size == MemoryAccessSize::Word && !sign);
|
||||
|
||||
@ -2098,8 +2128,8 @@ void CPU::Recompiler::X64Recompiler::Compile_swx(CompileFlags cf, MemoryAccessSi
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_swc2(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
void CPU::X64Recompiler::Compile_swc2(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||
const std::optional<VirtualMemoryAddress>& address)
|
||||
{
|
||||
const u32 index = static_cast<u32>(inst->r.rt.GetValue());
|
||||
const auto [ptr, action] = GetGTERegisterPointer(index, false);
|
||||
@ -2154,7 +2184,7 @@ void CPU::Recompiler::X64Recompiler::Compile_swc2(CompileFlags cf, MemoryAccessS
|
||||
FreeHostReg(data_backup.getIdx());
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_mtc0(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_mtc0(CompileFlags cf)
|
||||
{
|
||||
const Cop0Reg reg = static_cast<Cop0Reg>(MipsD());
|
||||
const u32* ptr = GetCop0RegPtr(reg);
|
||||
@ -2238,7 +2268,7 @@ void CPU::Recompiler::X64Recompiler::Compile_mtc0(CompileFlags cf)
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_rfe(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_rfe(CompileFlags cf)
|
||||
{
|
||||
// shift mode bits right two, preserving upper bits
|
||||
static constexpr u32 mode_bits_mask = UINT32_C(0b1111);
|
||||
@ -2253,7 +2283,7 @@ void CPU::Recompiler::X64Recompiler::Compile_rfe(CompileFlags cf)
|
||||
TestInterrupts(RWARG1);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::TestInterrupts(const Xbyak::Reg32& sr)
|
||||
void CPU::X64Recompiler::TestInterrupts(const Xbyak::Reg32& sr)
|
||||
{
|
||||
// if Iec == 0 then goto no_interrupt
|
||||
Label no_interrupt;
|
||||
@ -2301,7 +2331,7 @@ void CPU::Recompiler::X64Recompiler::TestInterrupts(const Xbyak::Reg32& sr)
|
||||
cg->L(no_interrupt);
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_mfc2(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_mfc2(CompileFlags cf)
|
||||
{
|
||||
const u32 index = inst->cop.Cop2Index();
|
||||
const Reg rt = inst->r.rt;
|
||||
@ -2342,7 +2372,7 @@ void CPU::Recompiler::X64Recompiler::Compile_mfc2(CompileFlags cf)
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_mtc2(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_mtc2(CompileFlags cf)
|
||||
{
|
||||
const u32 index = inst->cop.Cop2Index();
|
||||
const auto [ptr, action] = GetGTERegisterPointer(index, true);
|
||||
@ -2416,7 +2446,7 @@ void CPU::Recompiler::X64Recompiler::Compile_mtc2(CompileFlags cf)
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Recompiler::X64Recompiler::Compile_cop2(CompileFlags cf)
|
||||
void CPU::X64Recompiler::Compile_cop2(CompileFlags cf)
|
||||
{
|
||||
TickCount func_ticks;
|
||||
GTE::InstructionImpl func = GTE::GetInstructionImpl(inst->bits, &func_ticks);
|
||||
@ -2480,20 +2510,20 @@ u32 CPU::Recompiler::CompileLoadStoreThunk(void* thunk_code, u32 thunk_space, vo
|
||||
{
|
||||
case MemoryAccessSize::Byte:
|
||||
{
|
||||
cg->call(is_load ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedReadMemoryByte) :
|
||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedWriteMemoryByte));
|
||||
cg->call(is_load ? reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryByte) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryByte));
|
||||
}
|
||||
break;
|
||||
case MemoryAccessSize::HalfWord:
|
||||
{
|
||||
cg->call(is_load ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedReadMemoryHalfWord) :
|
||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedWriteMemoryHalfWord));
|
||||
cg->call(is_load ? reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryHalfWord) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryHalfWord));
|
||||
}
|
||||
break;
|
||||
case MemoryAccessSize::Word:
|
||||
{
|
||||
cg->call(is_load ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedReadMemoryWord) :
|
||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedWriteMemoryWord));
|
||||
cg->call(is_load ? reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryWord) :
|
||||
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryWord));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -9,7 +9,15 @@
|
||||
|
||||
#ifdef CPU_ARCH_X64
|
||||
|
||||
namespace CPU::Recompiler {
|
||||
// We need to include windows.h before xbyak does..
|
||||
#ifdef _WIN32
|
||||
#include "common/windows_headers.h"
|
||||
#endif
|
||||
|
||||
#define XBYAK_NO_OP_NAMES 1
|
||||
#include "xbyak.h"
|
||||
|
||||
namespace CPU {
|
||||
|
||||
class X64Recompiler final : public Recompiler
|
||||
{
|
||||
@ -141,6 +149,6 @@ private:
|
||||
Xbyak::CodeGenerator* cg;
|
||||
};
|
||||
|
||||
} // namespace CPU::Recompiler
|
||||
} // namespace CPU
|
||||
|
||||
#endif // CPU_ARCH_X64
|
||||
|
Loading…
Reference in New Issue
Block a user