mirror of
https://github.com/stenzek/duckstation.git
synced 2024-11-23 05:49:43 +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
|
set(RECOMPILER_SRCS
|
||||||
cpu_recompiler.cpp
|
cpu_recompiler.cpp
|
||||||
cpu_recompiler.h
|
cpu_recompiler.h
|
||||||
cpu_recompiler_thunks.h
|
|
||||||
cpu_recompiler_types.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_precompile_headers(core PRIVATE "pch.h")
|
target_precompile_headers(core PRIVATE "pch.h")
|
||||||
|
@ -106,8 +106,6 @@
|
|||||||
<ClInclude Include="cpu_recompiler_x64.h">
|
<ClInclude Include="cpu_recompiler_x64.h">
|
||||||
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="cpu_recompiler_thunks.h" />
|
|
||||||
<ClInclude Include="cpu_recompiler_types.h" />
|
|
||||||
<ClInclude Include="digital_controller.h" />
|
<ClInclude Include="digital_controller.h" />
|
||||||
<ClInclude Include="fullscreen_ui.h" />
|
<ClInclude Include="fullscreen_ui.h" />
|
||||||
<ClInclude Include="game_database.h" />
|
<ClInclude Include="game_database.h" />
|
||||||
|
@ -90,9 +90,7 @@
|
|||||||
<ClInclude Include="gpu_sw.h" />
|
<ClInclude Include="gpu_sw.h" />
|
||||||
<ClInclude Include="gpu_hw_shadergen.h" />
|
<ClInclude Include="gpu_hw_shadergen.h" />
|
||||||
<ClInclude Include="bios.h" />
|
<ClInclude Include="bios.h" />
|
||||||
<ClInclude Include="cpu_recompiler_types.h" />
|
|
||||||
<ClInclude Include="cpu_code_cache.h" />
|
<ClInclude Include="cpu_code_cache.h" />
|
||||||
<ClInclude Include="cpu_recompiler_thunks.h" />
|
|
||||||
<ClInclude Include="sio.h" />
|
<ClInclude Include="sio.h" />
|
||||||
<ClInclude Include="controller.h" />
|
<ClInclude Include="controller.h" />
|
||||||
<ClInclude Include="analog_controller.h" />
|
<ClInclude Include="analog_controller.h" />
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#include "cpu_core.h"
|
#include "cpu_core.h"
|
||||||
#include "cpu_core_private.h"
|
#include "cpu_core_private.h"
|
||||||
#include "cpu_disasm.h"
|
#include "cpu_disasm.h"
|
||||||
#include "cpu_recompiler_types.h"
|
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
@ -1564,7 +1563,7 @@ bool CPU::CodeCache::CompileBlock(Block* block)
|
|||||||
|
|
||||||
#ifdef ENABLE_RECOMPILER
|
#ifdef ENABLE_RECOMPILER
|
||||||
if (g_settings.cpu_execution_mode == CPUExecutionMode::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
|
#endif
|
||||||
|
|
||||||
block->host_code = host_code;
|
block->host_code = host_code;
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include "cpu_core_private.h"
|
#include "cpu_core_private.h"
|
||||||
#include "cpu_disasm.h"
|
#include "cpu_disasm.h"
|
||||||
#include "cpu_pgxp.h"
|
#include "cpu_pgxp.h"
|
||||||
#include "cpu_recompiler_thunks.h"
|
|
||||||
#include "gte.h"
|
#include "gte.h"
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
#include "pcdrv.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::Memory>();
|
||||||
template void CPU::CodeCache::InterpretUncachedBlock<PGXPMode::CPU>();
|
template void CPU::CodeCache::InterpretUncachedBlock<PGXPMode::CPU>();
|
||||||
|
|
||||||
bool CPU::Recompiler::Thunks::InterpretInstruction()
|
bool CPU::RecompilerThunks::InterpretInstruction()
|
||||||
{
|
{
|
||||||
ExecuteInstruction<PGXPMode::Disabled, false>();
|
ExecuteInstruction<PGXPMode::Disabled, false>();
|
||||||
return g_state.exception_raised;
|
return g_state.exception_raised;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPU::Recompiler::Thunks::InterpretInstructionPGXP()
|
bool CPU::RecompilerThunks::InterpretInstructionPGXP()
|
||||||
{
|
{
|
||||||
ExecuteInstruction<PGXPMode::Memory, false>();
|
ExecuteInstruction<PGXPMode::Memory, false>();
|
||||||
return g_state.exception_raised;
|
return g_state.exception_raised;
|
||||||
@ -3477,7 +3476,7 @@ bool CPU::WriteMemoryWord(VirtualMemoryAddress addr, u32 value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 CPU::Recompiler::Thunks::ReadMemoryByte(u32 address)
|
u64 CPU::RecompilerThunks::ReadMemoryByte(u32 address)
|
||||||
{
|
{
|
||||||
const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::Byte)(address);
|
const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::Byte)(address);
|
||||||
if (g_state.bus_error) [[unlikely]]
|
if (g_state.bus_error) [[unlikely]]
|
||||||
@ -3490,7 +3489,7 @@ u64 CPU::Recompiler::Thunks::ReadMemoryByte(u32 address)
|
|||||||
return ZeroExtend64(value);
|
return ZeroExtend64(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 CPU::Recompiler::Thunks::ReadMemoryHalfWord(u32 address)
|
u64 CPU::RecompilerThunks::ReadMemoryHalfWord(u32 address)
|
||||||
{
|
{
|
||||||
if (!Common::IsAlignedPow2(address, 2)) [[unlikely]]
|
if (!Common::IsAlignedPow2(address, 2)) [[unlikely]]
|
||||||
{
|
{
|
||||||
@ -3509,7 +3508,7 @@ u64 CPU::Recompiler::Thunks::ReadMemoryHalfWord(u32 address)
|
|||||||
return ZeroExtend64(value);
|
return ZeroExtend64(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 CPU::Recompiler::Thunks::ReadMemoryWord(u32 address)
|
u64 CPU::RecompilerThunks::ReadMemoryWord(u32 address)
|
||||||
{
|
{
|
||||||
if (!Common::IsAlignedPow2(address, 4)) [[unlikely]]
|
if (!Common::IsAlignedPow2(address, 4)) [[unlikely]]
|
||||||
{
|
{
|
||||||
@ -3528,7 +3527,7 @@ u64 CPU::Recompiler::Thunks::ReadMemoryWord(u32 address)
|
|||||||
return ZeroExtend64(value);
|
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);
|
MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Byte, address, value);
|
||||||
|
|
||||||
@ -3542,7 +3541,7 @@ u32 CPU::Recompiler::Thunks::WriteMemoryByte(u32 address, u32 value)
|
|||||||
return 0;
|
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);
|
MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::HalfWord, address, value);
|
||||||
|
|
||||||
@ -3562,7 +3561,7 @@ u32 CPU::Recompiler::Thunks::WriteMemoryHalfWord(u32 address, u32 value)
|
|||||||
return 0;
|
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);
|
MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Word, address, value);
|
||||||
|
|
||||||
@ -3582,40 +3581,40 @@ u32 CPU::Recompiler::Thunks::WriteMemoryWord(u32 address, u32 value)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CPU::Recompiler::Thunks::UncheckedReadMemoryByte(u32 address)
|
u32 CPU::RecompilerThunks::UncheckedReadMemoryByte(u32 address)
|
||||||
{
|
{
|
||||||
const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::Byte)(address);
|
const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::Byte)(address);
|
||||||
MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::Byte, address, value);
|
MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::Byte, address, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CPU::Recompiler::Thunks::UncheckedReadMemoryHalfWord(u32 address)
|
u32 CPU::RecompilerThunks::UncheckedReadMemoryHalfWord(u32 address)
|
||||||
{
|
{
|
||||||
const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::HalfWord)(address);
|
const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::HalfWord)(address);
|
||||||
MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::HalfWord, address, value);
|
MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::HalfWord, address, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CPU::Recompiler::Thunks::UncheckedReadMemoryWord(u32 address)
|
u32 CPU::RecompilerThunks::UncheckedReadMemoryWord(u32 address)
|
||||||
{
|
{
|
||||||
const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::Word)(address);
|
const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::Word)(address);
|
||||||
MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::Word, address, value);
|
MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::Word, address, value);
|
||||||
return 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);
|
MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Byte, address, value);
|
||||||
GetMemoryWriteHandler(address, 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);
|
MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::HalfWord, address, value);
|
||||||
GetMemoryWriteHandler(address, 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);
|
MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Word, address, value);
|
||||||
GetMemoryWriteHandler(address, MemoryAccessSize::Word)(address, value);
|
GetMemoryWriteHandler(address, MemoryAccessSize::Word)(address, value);
|
||||||
|
@ -132,4 +132,36 @@ ALWAYS_INLINE static void StallUntilGTEComplete()
|
|||||||
void HandleA0Syscall();
|
void HandleA0Syscall();
|
||||||
void HandleB0Syscall();
|
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
|
} // namespace CPU
|
@ -4,7 +4,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "cpu_code_cache_private.h"
|
#include "cpu_code_cache_private.h"
|
||||||
#include "cpu_recompiler_types.h"
|
|
||||||
#include "cpu_types.h"
|
#include "cpu_types.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
@ -13,36 +12,72 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace CPU::Recompiler {
|
namespace CPU {
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// TODO: Get rid of the virtuals... somehow.
|
// TODO: Get rid of the virtuals... somehow.
|
||||||
class Recompiler
|
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:
|
public:
|
||||||
Recompiler();
|
Recompiler();
|
||||||
virtual ~Recompiler();
|
virtual ~Recompiler();
|
||||||
|
|
||||||
const void* CompileBlock(CodeCache::Block* block, u32* host_code_size, u32* host_far_code_size);
|
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:
|
protected:
|
||||||
enum FlushFlags : u32
|
enum FlushFlags : u32
|
||||||
{
|
{
|
||||||
@ -274,7 +309,7 @@ protected:
|
|||||||
void CompileTemplate(void (Recompiler::*const_func)(CompileFlags), void (Recompiler::*func)(CompileFlags),
|
void CompileTemplate(void (Recompiler::*const_func)(CompileFlags), void (Recompiler::*func)(CompileFlags),
|
||||||
const void* pgxp_cpu_func, u32 tflags);
|
const void* pgxp_cpu_func, u32 tflags);
|
||||||
void CompileLoadStoreTemplate(void (Recompiler::*func)(CompileFlags, MemoryAccessSize, bool, bool,
|
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);
|
MemoryAccessSize size, bool store, bool sign, u32 tflags);
|
||||||
void FlushForLoadStore(const std::optional<VirtualMemoryAddress>& address, bool store, bool use_fastmem);
|
void FlushForLoadStore(const std::optional<VirtualMemoryAddress>& address, bool store, bool use_fastmem);
|
||||||
void CompileMoveRegTemplate(Reg dst, Reg src, bool pgxp_move);
|
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;
|
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;
|
extern Recompiler* g_compiler;
|
||||||
} // namespace CPU::Recompiler
|
} // namespace CPU
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
#include "cpu_recompiler_arm32.h"
|
#include "cpu_recompiler_arm32.h"
|
||||||
#include "cpu_core_private.h"
|
#include "cpu_core_private.h"
|
||||||
#include "cpu_pgxp.h"
|
#include "cpu_pgxp.h"
|
||||||
#include "cpu_recompiler_thunks.h"
|
|
||||||
#include "cpu_recompiler_types.h"
|
|
||||||
#include "gte.h"
|
#include "gte.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "timing_event.h"
|
#include "timing_event.h"
|
||||||
@ -20,6 +18,9 @@
|
|||||||
|
|
||||||
#ifdef CPU_ARCH_ARM32
|
#ifdef CPU_ARCH_ARM32
|
||||||
|
|
||||||
|
#include "vixl/aarch32/constants-aarch32.h"
|
||||||
|
#include "vixl/aarch32/instructions-aarch32.h"
|
||||||
|
|
||||||
#ifdef ENABLE_HOST_DISASSEMBLY
|
#ifdef ENABLE_HOST_DISASSEMBLY
|
||||||
#include "vixl/aarch32/disasm-aarch32.h"
|
#include "vixl/aarch32/disasm-aarch32.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -30,43 +31,64 @@ LOG_CHANNEL(Recompiler);
|
|||||||
#define PTR(x) vixl::aarch32::MemOperand(RSTATE, (((u8*)(x)) - ((u8*)&g_state)))
|
#define PTR(x) vixl::aarch32::MemOperand(RSTATE, (((u8*)(x)) - ((u8*)&g_state)))
|
||||||
#define RMEMBASE vixl::aarch32::r3
|
#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
|
static bool armIsCallerSavedRegister(u32 id);
|
||||||
constexpr u32 FUNCTION_CALLER_SAVED_SPACE_RESERVE = 144; // 18 registers -> 224 bytes
|
static s32 armGetPCDisplacement(const void* current, const void* target);
|
||||||
constexpr u32 FUNCTION_STACK_SIZE = FUNCTION_CALLEE_SAVED_SPACE_RESERVE + FUNCTION_CALLER_SAVED_SPACE_RESERVE;
|
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 constexpr u32 TRAMPOLINE_AREA_SIZE = 4 * 1024;
|
||||||
static std::unordered_map<const void*, u32> s_trampoline_targets;
|
static std::unordered_map<const void*, u32> s_trampoline_targets;
|
||||||
static u8* s_trampoline_start_ptr = nullptr;
|
static u8* s_trampoline_start_ptr = nullptr;
|
||||||
static u32 s_trampoline_used = 0;
|
static u32 s_trampoline_used = 0;
|
||||||
|
|
||||||
|
namespace CPU {
|
||||||
|
|
||||||
|
using namespace vixl::aarch32;
|
||||||
|
|
||||||
static ARM32Recompiler s_instance;
|
static ARM32Recompiler s_instance;
|
||||||
Recompiler* g_compiler = &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
|
return ((id >= 0 && id <= 3) || // r0-r3
|
||||||
(id == 12 || id == 14)); // sp, pc
|
(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>(current), 4));
|
||||||
Assert(Common::IsAlignedPow2(reinterpret_cast<size_t>(target), 4));
|
Assert(Common::IsAlignedPow2(reinterpret_cast<size_t>(target), 4));
|
||||||
return static_cast<s32>((reinterpret_cast<ptrdiff_t>(target) - reinterpret_cast<ptrdiff_t>(current)));
|
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);
|
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))
|
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);
|
armAsm->movt(al, rd, imm >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::armMoveAddressToReg(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg,
|
void armMoveAddressToReg(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg, const void* addr)
|
||||||
const void* addr)
|
|
||||||
{
|
{
|
||||||
armEmitMov(armAsm, reg, static_cast<u32>(reinterpret_cast<uintptr_t>(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*>();
|
const void* cur = armAsm->GetCursorAddress<const void*>();
|
||||||
s32 displacement = armGetPCDisplacement(cur, ptr);
|
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*>();
|
const void* cur = armAsm->GetCursorAddress<const void*>();
|
||||||
s32 displacement = armGetPCDisplacement(cur, ptr);
|
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,
|
void armEmitCondBranch(vixl::aarch32::Assembler* armAsm, vixl::aarch32::Condition cond, const void* ptr)
|
||||||
const void* ptr)
|
|
||||||
{
|
{
|
||||||
const s32 displacement = armGetPCDisplacement(armAsm->GetCursorAddress<const void*>(), ptr);
|
const s32 displacement = armGetPCDisplacement(armAsm->GetCursorAddress<const void*>(), ptr);
|
||||||
if (!armIsPCDisplacementInImmediateRange(displacement))
|
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,
|
void armEmitFarLoad(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg, const void* addr)
|
||||||
const void* addr)
|
|
||||||
{
|
{
|
||||||
armMoveAddressToReg(armAsm, reg, addr);
|
armMoveAddressToReg(armAsm, reg, addr);
|
||||||
armAsm->ldr(reg, MemOperand(reg));
|
armAsm->ldr(reg, MemOperand(reg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::armEmitFarStore(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg,
|
void armEmitFarStore(vixl::aarch32::Assembler* armAsm, const vixl::aarch32::Register& reg, const void* addr,
|
||||||
const void* addr, const vixl::aarch32::Register& tempreg)
|
const vixl::aarch32::Register& tempreg)
|
||||||
{
|
{
|
||||||
armMoveAddressToReg(armAsm, tempreg, addr);
|
armMoveAddressToReg(armAsm, tempreg, addr);
|
||||||
armAsm->str(reg, MemOperand(tempreg));
|
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*/;
|
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*>();
|
return armAsm->GetCursorAddress<const void*>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::Reset(CodeCache::Block* block, u8* code_buffer, u32 code_buffer_space,
|
void CPU::ARM32Recompiler::Reset(CodeCache::Block* block, u8* code_buffer, u32 code_buffer_space, u8* far_code_buffer,
|
||||||
u8* far_code_buffer, u32 far_code_space)
|
u32 far_code_space)
|
||||||
{
|
{
|
||||||
Recompiler::Reset(block, code_buffer, code_buffer_space, far_code_buffer, 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);
|
DebugAssert(armAsm == &m_emitter);
|
||||||
if (emit_jump)
|
if (emit_jump)
|
||||||
@ -395,7 +414,7 @@ void CPU::Recompiler::ARM32Recompiler::SwitchToFarCode(bool emit_jump, vixl::aar
|
|||||||
armAsm = &m_far_emitter;
|
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);
|
armAsm->tst(reg, 1u << bit);
|
||||||
|
|
||||||
@ -416,8 +435,7 @@ void CPU::Recompiler::ARM32Recompiler::SwitchToFarCodeIfBitSet(const vixl::aarch
|
|||||||
armAsm = &m_far_emitter;
|
armAsm = &m_far_emitter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::SwitchToFarCodeIfRegZeroOrNonZero(const vixl::aarch32::Register& reg,
|
void CPU::ARM32Recompiler::SwitchToFarCodeIfRegZeroOrNonZero(const vixl::aarch32::Register& reg, bool nonzero)
|
||||||
bool nonzero)
|
|
||||||
{
|
{
|
||||||
armAsm->cmp(reg, 0);
|
armAsm->cmp(reg, 0);
|
||||||
|
|
||||||
@ -438,7 +456,7 @@ void CPU::Recompiler::ARM32Recompiler::SwitchToFarCodeIfRegZeroOrNonZero(const v
|
|||||||
armAsm = &m_far_emitter;
|
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);
|
DebugAssert(armAsm == &m_far_emitter);
|
||||||
if (emit_jump)
|
if (emit_jump)
|
||||||
@ -464,17 +482,17 @@ void CPU::Recompiler::ARM32Recompiler::SwitchToNearCode(bool emit_jump, vixl::aa
|
|||||||
armAsm = &m_emitter;
|
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);
|
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);
|
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)))
|
if (ImmediateA32::IsImmediateA32(static_cast<u32>(val)))
|
||||||
return vixl::aarch32::Operand(static_cast<int32_t>(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);
|
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));
|
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);
|
return armCheckAddSubConstant(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
vixl::aarch32::Operand CPU::Recompiler::ARM32Recompiler::armCheckLogicalConstant(u32 val)
|
vixl::aarch32::Operand CPU::ARM32Recompiler::armCheckLogicalConstant(u32 val)
|
||||||
{
|
{
|
||||||
return armCheckAddSubConstant(val);
|
return armCheckAddSubConstant(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::BeginBlock()
|
void CPU::ARM32Recompiler::BeginBlock()
|
||||||
{
|
{
|
||||||
Recompiler::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
|
// store it first to reduce code size, because we can offset
|
||||||
armMoveAddressToReg(armAsm, RARG1, ram_ptr);
|
armMoveAddressToReg(armAsm, RARG1, ram_ptr);
|
||||||
@ -579,7 +597,7 @@ bool foo(const void* a, const void* b)
|
|||||||
armAsm->bind(&block_unchanged);
|
armAsm->bind(&block_unchanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::GenerateICacheCheckAndUpdate()
|
void CPU::ARM32Recompiler::GenerateICacheCheckAndUpdate()
|
||||||
{
|
{
|
||||||
if (!m_block->HasFlag(CodeCache::BlockFlags::IsUsingICache))
|
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*/,
|
void CPU::ARM32Recompiler::GenerateCall(const void* func, s32 arg1reg /*= -1*/, s32 arg2reg /*= -1*/,
|
||||||
s32 arg3reg /*= -1*/)
|
s32 arg3reg /*= -1*/)
|
||||||
{
|
{
|
||||||
if (arg1reg >= 0 && arg1reg != static_cast<s32>(RARG1.GetCode()))
|
if (arg1reg >= 0 && arg1reg != static_cast<s32>(RARG1.GetCode()))
|
||||||
armAsm->mov(RARG1, Register(arg1reg));
|
armAsm->mov(RARG1, Register(arg1reg));
|
||||||
@ -647,7 +665,7 @@ void CPU::Recompiler::ARM32Recompiler::GenerateCall(const void* func, s32 arg1re
|
|||||||
EmitCall(func);
|
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())
|
if (newpc.has_value())
|
||||||
{
|
{
|
||||||
@ -664,7 +682,7 @@ void CPU::Recompiler::ARM32Recompiler::EndBlock(const std::optional<u32>& newpc,
|
|||||||
EndAndLinkBlock(newpc, do_event_test, false);
|
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 regs, but not pc, it's going to get overwritten
|
||||||
// flush cycles because of the GTE instruction stuff...
|
// flush cycles because of the GTE instruction stuff...
|
||||||
@ -682,8 +700,7 @@ void CPU::Recompiler::ARM32Recompiler::EndBlockWithException(Exception excode)
|
|||||||
EndAndLinkBlock(std::nullopt, true, false);
|
EndAndLinkBlock(std::nullopt, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::EndAndLinkBlock(const std::optional<u32>& newpc, bool do_event_test,
|
void CPU::ARM32Recompiler::EndAndLinkBlock(const std::optional<u32>& newpc, bool do_event_test, bool force_run_events)
|
||||||
bool force_run_events)
|
|
||||||
{
|
{
|
||||||
// event test
|
// event test
|
||||||
// pc should've been flushed
|
// 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
|
#ifdef VIXL_DEBUG
|
||||||
m_emitter_check.reset();
|
m_emitter_check.reset();
|
||||||
@ -757,7 +774,7 @@ const void* CPU::Recompiler::ARM32Recompiler::EndCompile(u32* code_size, u32* fa
|
|||||||
return code;
|
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 = {
|
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",
|
{"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";
|
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);
|
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));
|
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));
|
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);
|
EmitMov(RSCRATCH, val);
|
||||||
armAsm->str(RSCRATCH, PTR(ptr));
|
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)
|
if (src != dst)
|
||||||
armAsm->mov(Register(dst), Register(src));
|
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);
|
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);
|
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);
|
DebugAssert(r < Reg::count);
|
||||||
return PTR(&g_state.regs.r[static_cast<u32>(r)]);
|
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);
|
DebugAssert(cf.valid_host_d);
|
||||||
return Register(cf.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);
|
DebugAssert(cf.valid_host_s);
|
||||||
return Register(cf.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);
|
DebugAssert(cf.valid_host_t);
|
||||||
return Register(cf.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);
|
DebugAssert(cf.valid_host_lo);
|
||||||
return Register(cf.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);
|
DebugAssert(cf.valid_host_hi);
|
||||||
return Register(cf.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();
|
const u32 code = RMEMBASE.GetCode();
|
||||||
if (!IsHostRegAllocated(code))
|
if (!IsHostRegAllocated(code))
|
||||||
@ -852,7 +869,7 @@ vixl::aarch32::Register CPU::Recompiler::ARM32Recompiler::GetMembaseReg()
|
|||||||
return RMEMBASE;
|
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)
|
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)
|
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);
|
DebugAssert(reg < Reg::count);
|
||||||
if (const std::optional<u32> hreg = CheckHostReg(0, Recompiler::HR_TYPE_CPU_REG, reg))
|
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));
|
armAsm->ldr(dst, MipsPtr(reg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::GeneratePGXPCallWithMIPSRegs(const void* func, u32 arg1val,
|
void CPU::ARM32Recompiler::GeneratePGXPCallWithMIPSRegs(const void* func, u32 arg1val, Reg arg2reg /* = Reg::count */,
|
||||||
Reg arg2reg /* = Reg::count */,
|
Reg arg3reg /* = Reg::count */)
|
||||||
Reg arg3reg /* = Reg::count */)
|
|
||||||
{
|
{
|
||||||
DebugAssert(g_settings.gpu_pgxp_enable);
|
DebugAssert(g_settings.gpu_pgxp_enable);
|
||||||
|
|
||||||
@ -918,7 +934,7 @@ void CPU::Recompiler::ARM32Recompiler::GeneratePGXPCallWithMIPSRegs(const void*
|
|||||||
EmitCall(func);
|
EmitCall(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::Flush(u32 flags)
|
void CPU::ARM32Recompiler::Flush(u32 flags)
|
||||||
{
|
{
|
||||||
Recompiler::Flush(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);
|
WARNING_LOG("Compiling instruction fallback at PC=0x{:08X}, instruction=0x{:08X}", iinfo->pc, inst->bits);
|
||||||
|
|
||||||
Flush(FLUSH_FOR_INTERPRETER);
|
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: make me less garbage
|
||||||
// TODO: this is wrong, it flushes the load delay on the same cycle when we return.
|
// 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;
|
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)
|
if (!g_settings.cpu_recompiler_memory_exceptions)
|
||||||
return;
|
return;
|
||||||
@ -1050,7 +1066,7 @@ void CPU::Recompiler::ARM32Recompiler::CheckBranchTarget(const vixl::aarch32::Re
|
|||||||
SwitchToNearCode(false);
|
SwitchToNearCode(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::Compile_jr(CompileFlags cf)
|
void CPU::ARM32Recompiler::Compile_jr(CompileFlags cf)
|
||||||
{
|
{
|
||||||
const Register pcreg = CFGetRegS(cf);
|
const Register pcreg = CFGetRegS(cf);
|
||||||
CheckBranchTarget(pcreg);
|
CheckBranchTarget(pcreg);
|
||||||
@ -1061,7 +1077,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_jr(CompileFlags cf)
|
|||||||
EndBlock(std::nullopt, true);
|
EndBlock(std::nullopt, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::Compile_jalr(CompileFlags cf)
|
void CPU::ARM32Recompiler::Compile_jalr(CompileFlags cf)
|
||||||
{
|
{
|
||||||
const Register pcreg = CFGetRegS(cf);
|
const Register pcreg = CFGetRegS(cf);
|
||||||
if (MipsD() != Reg::zero)
|
if (MipsD() != Reg::zero)
|
||||||
@ -1074,7 +1090,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_jalr(CompileFlags cf)
|
|||||||
EndBlock(std::nullopt, true);
|
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);
|
AssertRegOrConstS(cf);
|
||||||
|
|
||||||
@ -1148,7 +1164,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_bxx(CompileFlags cf, BranchCondit
|
|||||||
EndBlock(taken_pc, true);
|
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 rs = CFGetRegS(cf);
|
||||||
const Register rt = CFGetRegT(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);
|
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);
|
Compile_addi(cf, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::Compile_slti(CompileFlags cf)
|
void CPU::ARM32Recompiler::Compile_slti(CompileFlags cf)
|
||||||
{
|
{
|
||||||
Compile_slti(cf, true);
|
Compile_slti(cf, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::Compile_sltiu(CompileFlags cf)
|
void CPU::ARM32Recompiler::Compile_sltiu(CompileFlags cf)
|
||||||
{
|
{
|
||||||
Compile_slti(cf, false);
|
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 rs = CFGetRegS(cf);
|
||||||
const Register rt = CFGetRegT(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);
|
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);
|
const Register rt = CFGetRegT(cf);
|
||||||
if (const u32 imm = inst->i.imm_zext32(); imm != 0)
|
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);
|
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 rt = CFGetRegT(cf);
|
||||||
const Register rs = CFGetRegS(cf);
|
const Register rs = CFGetRegS(cf);
|
||||||
@ -1218,7 +1234,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_ori(CompileFlags cf)
|
|||||||
armAsm->mov(rt, rs);
|
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 rt = CFGetRegT(cf);
|
||||||
const Register rs = CFGetRegS(cf);
|
const Register rs = CFGetRegS(cf);
|
||||||
@ -1228,10 +1244,9 @@ void CPU::Recompiler::ARM32Recompiler::Compile_xori(CompileFlags cf)
|
|||||||
armAsm->mov(rt, rs);
|
armAsm->mov(rt, rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::Compile_shift(CompileFlags cf,
|
void CPU::ARM32Recompiler::Compile_shift(CompileFlags cf,
|
||||||
void (vixl::aarch32::Assembler::*op)(vixl::aarch32::Register,
|
void (vixl::aarch32::Assembler::*op)(vixl::aarch32::Register,
|
||||||
vixl::aarch32::Register,
|
vixl::aarch32::Register, const Operand&))
|
||||||
const Operand&))
|
|
||||||
{
|
{
|
||||||
const Register rd = CFGetRegD(cf);
|
const Register rd = CFGetRegD(cf);
|
||||||
const Register rt = CFGetRegT(cf);
|
const Register rt = CFGetRegT(cf);
|
||||||
@ -1241,24 +1256,25 @@ void CPU::Recompiler::ARM32Recompiler::Compile_shift(CompileFlags cf,
|
|||||||
armAsm->mov(rd, rt);
|
armAsm->mov(rd, rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::Compile_sll(CompileFlags cf)
|
void CPU::ARM32Recompiler::Compile_sll(CompileFlags cf)
|
||||||
{
|
{
|
||||||
Compile_shift(cf, &Assembler::lsl);
|
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);
|
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);
|
Compile_shift(cf, &Assembler::asr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::Compile_variable_shift(
|
void CPU::ARM32Recompiler::Compile_variable_shift(CompileFlags cf,
|
||||||
CompileFlags cf,
|
void (vixl::aarch32::Assembler::*op)(vixl::aarch32::Register,
|
||||||
void (vixl::aarch32::Assembler::*op)(vixl::aarch32::Register, vixl::aarch32::Register, const Operand&))
|
vixl::aarch32::Register,
|
||||||
|
const Operand&))
|
||||||
{
|
{
|
||||||
const Register rd = CFGetRegD(cf);
|
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);
|
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);
|
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);
|
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;
|
const Register rs = cf.valid_host_s ? CFGetRegS(cf) : RARG1;
|
||||||
if (!cf.valid_host_s)
|
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);
|
(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);
|
Compile_mult(cf, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::Compile_multu(CompileFlags cf)
|
void CPU::ARM32Recompiler::Compile_multu(CompileFlags cf)
|
||||||
{
|
{
|
||||||
Compile_mult(cf, false);
|
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;
|
const Register rs = cf.valid_host_s ? CFGetRegS(cf) : RARG1;
|
||||||
if (!cf.valid_host_s)
|
if (!cf.valid_host_s)
|
||||||
@ -1371,7 +1387,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_div(CompileFlags cf)
|
|||||||
armAsm->bind(&done);
|
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;
|
const Register rs = cf.valid_host_s ? CFGetRegS(cf) : RARG1;
|
||||||
if (!cf.valid_host_s)
|
if (!cf.valid_host_s)
|
||||||
@ -1402,7 +1418,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_divu(CompileFlags cf)
|
|||||||
armAsm->bind(&done);
|
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);
|
SwitchToFarCode(true, vs);
|
||||||
|
|
||||||
@ -1418,11 +1434,10 @@ void CPU::Recompiler::ARM32Recompiler::TestOverflow(const vixl::aarch32::Registe
|
|||||||
SwitchToNearCode(false);
|
SwitchToNearCode(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::Compile_dst_op(CompileFlags cf,
|
void CPU::ARM32Recompiler::Compile_dst_op(CompileFlags cf,
|
||||||
void (vixl::aarch32::Assembler::*op)(vixl::aarch32::Register,
|
void (vixl::aarch32::Assembler::*op)(vixl::aarch32::Register,
|
||||||
vixl::aarch32::Register,
|
vixl::aarch32::Register, const Operand&),
|
||||||
const Operand&),
|
bool commutative, bool logical, bool overflow)
|
||||||
bool commutative, bool logical, bool overflow)
|
|
||||||
{
|
{
|
||||||
AssertRegOrConstS(cf);
|
AssertRegOrConstS(cf);
|
||||||
AssertRegOrConstT(cf);
|
AssertRegOrConstT(cf);
|
||||||
@ -1470,7 +1485,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_dst_op(CompileFlags cf,
|
|||||||
TestOverflow(rd);
|
TestOverflow(rd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::Compile_add(CompileFlags cf)
|
void CPU::ARM32Recompiler::Compile_add(CompileFlags cf)
|
||||||
{
|
{
|
||||||
if (g_settings.cpu_recompiler_memory_exceptions)
|
if (g_settings.cpu_recompiler_memory_exceptions)
|
||||||
Compile_dst_op(cf, &Assembler::adds, true, false, true);
|
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);
|
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);
|
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)
|
if (g_settings.cpu_recompiler_memory_exceptions)
|
||||||
Compile_dst_op(cf, &Assembler::subs, false, false, true);
|
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);
|
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);
|
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);
|
AssertRegOrConstS(cf);
|
||||||
AssertRegOrConstT(cf);
|
AssertRegOrConstT(cf);
|
||||||
@ -1517,7 +1532,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_and(CompileFlags cf)
|
|||||||
Compile_dst_op(cf, &Assembler::and_, true, true, false);
|
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);
|
AssertRegOrConstS(cf);
|
||||||
AssertRegOrConstT(cf);
|
AssertRegOrConstT(cf);
|
||||||
@ -1533,7 +1548,7 @@ void CPU::Recompiler::ARM32Recompiler::Compile_or(CompileFlags cf)
|
|||||||
Compile_dst_op(cf, &Assembler::orr, true, true, false);
|
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);
|
AssertRegOrConstS(cf);
|
||||||
AssertRegOrConstT(cf);
|
AssertRegOrConstT(cf);
|
||||||
@ -1555,23 +1570,23 @@ void CPU::Recompiler::ARM32Recompiler::Compile_xor(CompileFlags cf)
|
|||||||
Compile_dst_op(cf, &Assembler::eor, true, true, false);
|
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);
|
Compile_or(cf);
|
||||||
armAsm->mvn(CFGetRegD(cf), CFGetRegD(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);
|
Compile_slt(cf, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::Compile_sltu(CompileFlags cf)
|
void CPU::ARM32Recompiler::Compile_sltu(CompileFlags cf)
|
||||||
{
|
{
|
||||||
Compile_slt(cf, false);
|
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);
|
AssertRegOrConstS(cf);
|
||||||
AssertRegOrConstT(cf);
|
AssertRegOrConstT(cf);
|
||||||
@ -1597,9 +1612,8 @@ void CPU::Recompiler::ARM32Recompiler::Compile_slt(CompileFlags cf, bool sign)
|
|||||||
}
|
}
|
||||||
|
|
||||||
vixl::aarch32::Register
|
vixl::aarch32::Register
|
||||||
CPU::Recompiler::ARM32Recompiler::ComputeLoadStoreAddressArg(CompileFlags cf,
|
CPU::ARM32Recompiler::ComputeLoadStoreAddressArg(CompileFlags cf, const std::optional<VirtualMemoryAddress>& address,
|
||||||
const std::optional<VirtualMemoryAddress>& address,
|
const std::optional<const vixl::aarch32::Register>& reg)
|
||||||
const std::optional<const vixl::aarch32::Register>& reg)
|
|
||||||
{
|
{
|
||||||
const u32 imm = inst->i.imm_sext32();
|
const u32 imm = inst->i.imm_sext32();
|
||||||
if (cf.valid_host_s && imm == 0 && !reg.has_value())
|
if (cf.valid_host_s && imm == 0 && !reg.has_value())
|
||||||
@ -1639,9 +1653,9 @@ CPU::Recompiler::ARM32Recompiler::ComputeLoadStoreAddressArg(CompileFlags cf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename RegAllocFn>
|
template<typename RegAllocFn>
|
||||||
vixl::aarch32::Register
|
vixl::aarch32::Register CPU::ARM32Recompiler::GenerateLoad(const vixl::aarch32::Register& addr_reg,
|
||||||
CPU::Recompiler::ARM32Recompiler::GenerateLoad(const vixl::aarch32::Register& addr_reg, MemoryAccessSize size,
|
MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||||
bool sign, bool use_fastmem, const RegAllocFn& dst_reg_alloc)
|
const RegAllocFn& dst_reg_alloc)
|
||||||
{
|
{
|
||||||
if (use_fastmem)
|
if (use_fastmem)
|
||||||
{
|
{
|
||||||
@ -1683,20 +1697,20 @@ CPU::Recompiler::ARM32Recompiler::GenerateLoad(const vixl::aarch32::Register& ad
|
|||||||
{
|
{
|
||||||
case MemoryAccessSize::Byte:
|
case MemoryAccessSize::Byte:
|
||||||
{
|
{
|
||||||
EmitCall(checked ? reinterpret_cast<const void*>(&Recompiler::Thunks::ReadMemoryByte) :
|
EmitCall(checked ? reinterpret_cast<const void*>(&RecompilerThunks::ReadMemoryByte) :
|
||||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedReadMemoryByte));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryByte));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MemoryAccessSize::HalfWord:
|
case MemoryAccessSize::HalfWord:
|
||||||
{
|
{
|
||||||
EmitCall(checked ? reinterpret_cast<const void*>(&Recompiler::Thunks::ReadMemoryHalfWord) :
|
EmitCall(checked ? reinterpret_cast<const void*>(&RecompilerThunks::ReadMemoryHalfWord) :
|
||||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedReadMemoryHalfWord));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryHalfWord));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MemoryAccessSize::Word:
|
case MemoryAccessSize::Word:
|
||||||
{
|
{
|
||||||
EmitCall(checked ? reinterpret_cast<const void*>(&Recompiler::Thunks::ReadMemoryWord) :
|
EmitCall(checked ? reinterpret_cast<const void*>(&RecompilerThunks::ReadMemoryWord) :
|
||||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedReadMemoryWord));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryWord));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1751,9 +1765,9 @@ CPU::Recompiler::ARM32Recompiler::GenerateLoad(const vixl::aarch32::Register& ad
|
|||||||
return dst_reg;
|
return dst_reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::ARM32Recompiler::GenerateStore(const vixl::aarch32::Register& addr_reg,
|
void CPU::ARM32Recompiler::GenerateStore(const vixl::aarch32::Register& addr_reg,
|
||||||
const vixl::aarch32::Register& value_reg, MemoryAccessSize size,
|
const vixl::aarch32::Register& value_reg, MemoryAccessSize size,
|
||||||
bool use_fastmem)
|
bool use_fastmem)
|
||||||
{
|
{
|
||||||
if (use_fastmem)
|
if (use_fastmem)
|
||||||
{
|
{
|
||||||
@ -1793,20 +1807,20 @@ void CPU::Recompiler::ARM32Recompiler::GenerateStore(const vixl::aarch32::Regist
|
|||||||
{
|
{
|
||||||
case MemoryAccessSize::Byte:
|
case MemoryAccessSize::Byte:
|
||||||
{
|
{
|
||||||
EmitCall(checked ? reinterpret_cast<const void*>(&Recompiler::Thunks::WriteMemoryByte) :
|
EmitCall(checked ? reinterpret_cast<const void*>(&RecompilerThunks::WriteMemoryByte) :
|
||||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedWriteMemoryByte));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryByte));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MemoryAccessSize::HalfWord:
|
case MemoryAccessSize::HalfWord:
|
||||||
{
|
{
|
||||||
EmitCall(checked ? reinterpret_cast<const void*>(&Recompiler::Thunks::WriteMemoryHalfWord) :
|
EmitCall(checked ? reinterpret_cast<const void*>(&RecompilerThunks::WriteMemoryHalfWord) :
|
||||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedWriteMemoryHalfWord));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryHalfWord));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MemoryAccessSize::Word:
|
case MemoryAccessSize::Word:
|
||||||
{
|
{
|
||||||
EmitCall(checked ? reinterpret_cast<const void*>(&Recompiler::Thunks::WriteMemoryWord) :
|
EmitCall(checked ? reinterpret_cast<const void*>(&RecompilerThunks::WriteMemoryWord) :
|
||||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedWriteMemoryWord));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryWord));
|
||||||
}
|
}
|
||||||
break;
|
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,
|
void CPU::ARM32Recompiler::Compile_lxx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||||
const std::optional<VirtualMemoryAddress>& address)
|
const std::optional<VirtualMemoryAddress>& address)
|
||||||
{
|
{
|
||||||
const std::optional<Register> addr_reg = g_settings.gpu_pgxp_enable ?
|
const std::optional<Register> addr_reg = g_settings.gpu_pgxp_enable ?
|
||||||
std::optional<Register>(Register(AllocateTempHostReg(HR_CALLEE_SAVED))) :
|
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,
|
void CPU::ARM32Recompiler::Compile_lwx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||||
const std::optional<VirtualMemoryAddress>& address)
|
const std::optional<VirtualMemoryAddress>& address)
|
||||||
{
|
{
|
||||||
DebugAssert(size == MemoryAccessSize::Word && !sign);
|
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,
|
void CPU::ARM32Recompiler::Compile_lwc2(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||||
const std::optional<VirtualMemoryAddress>& address)
|
const std::optional<VirtualMemoryAddress>& address)
|
||||||
{
|
{
|
||||||
const u32 index = static_cast<u32>(inst->r.rt.GetValue());
|
const u32 index = static_cast<u32>(inst->r.rt.GetValue());
|
||||||
const auto [ptr, action] = GetGTERegisterPointer(index, true);
|
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,
|
void CPU::ARM32Recompiler::Compile_sxx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||||
const std::optional<VirtualMemoryAddress>& address)
|
const std::optional<VirtualMemoryAddress>& address)
|
||||||
{
|
{
|
||||||
AssertRegOrConstS(cf);
|
AssertRegOrConstS(cf);
|
||||||
AssertRegOrConstT(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,
|
void CPU::ARM32Recompiler::Compile_swx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||||
const std::optional<VirtualMemoryAddress>& address)
|
const std::optional<VirtualMemoryAddress>& address)
|
||||||
{
|
{
|
||||||
DebugAssert(size == MemoryAccessSize::Word && !sign);
|
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,
|
void CPU::ARM32Recompiler::Compile_swc2(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||||
const std::optional<VirtualMemoryAddress>& address)
|
const std::optional<VirtualMemoryAddress>& address)
|
||||||
{
|
{
|
||||||
const u32 index = static_cast<u32>(inst->r.rt.GetValue());
|
const u32 index = static_cast<u32>(inst->r.rt.GetValue());
|
||||||
const auto [ptr, action] = GetGTERegisterPointer(index, false);
|
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
|
// TODO: we need better constant setting here.. which will need backprop
|
||||||
AssertRegOrConstT(cf);
|
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
|
// shift mode bits right two, preserving upper bits
|
||||||
armAsm->ldr(RARG1, PTR(&g_state.cop0_regs.sr.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);
|
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
|
// if Iec == 0 then goto no_interrupt
|
||||||
Label no_interrupt;
|
Label no_interrupt;
|
||||||
@ -2344,7 +2358,7 @@ void CPU::Recompiler::ARM32Recompiler::TestInterrupts(const vixl::aarch32::Regis
|
|||||||
armAsm->bind(&no_interrupt);
|
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 u32 index = inst->cop.Cop2Index();
|
||||||
const Reg rt = inst->r.rt;
|
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 u32 index = inst->cop.Cop2Index();
|
||||||
const auto [ptr, action] = GetGTERegisterPointer(index, true);
|
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;
|
TickCount func_ticks;
|
||||||
GTE::InstructionImpl func = GTE::GetInstructionImpl(inst->bits, &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:
|
case MemoryAccessSize::Byte:
|
||||||
{
|
{
|
||||||
armEmitCall(armAsm,
|
armEmitCall(armAsm,
|
||||||
is_load ? reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedReadMemoryByte) :
|
is_load ? reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryByte) :
|
||||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedWriteMemoryByte),
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryByte),
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MemoryAccessSize::HalfWord:
|
case MemoryAccessSize::HalfWord:
|
||||||
{
|
{
|
||||||
armEmitCall(armAsm,
|
armEmitCall(armAsm,
|
||||||
is_load ? reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedReadMemoryHalfWord) :
|
is_load ? reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryHalfWord) :
|
||||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedWriteMemoryHalfWord),
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryHalfWord),
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MemoryAccessSize::Word:
|
case MemoryAccessSize::Word:
|
||||||
{
|
{
|
||||||
armEmitCall(armAsm,
|
armEmitCall(armAsm,
|
||||||
is_load ? reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedReadMemoryWord) :
|
is_load ? reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryWord) :
|
||||||
reinterpret_cast<const void*>(&Recompiler::Thunks::UncheckedWriteMemoryWord),
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryWord),
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include "vixl/aarch32/assembler-aarch32.h"
|
#include "vixl/aarch32/assembler-aarch32.h"
|
||||||
#include "vixl/aarch32/operands-aarch32.h"
|
#include "vixl/aarch32/operands-aarch32.h"
|
||||||
|
|
||||||
namespace CPU::Recompiler {
|
namespace CPU {
|
||||||
|
|
||||||
class ARM32Recompiler final : public Recompiler
|
class ARM32Recompiler final : public Recompiler
|
||||||
{
|
{
|
||||||
@ -165,6 +165,6 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CPU::Recompiler
|
} // namespace CPU
|
||||||
|
|
||||||
#endif // CPU_ARCH_ARM32
|
#endif // CPU_ARCH_ARM32
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#include "vixl/aarch64/assembler-aarch64.h"
|
#include "vixl/aarch64/assembler-aarch64.h"
|
||||||
|
|
||||||
namespace CPU::Recompiler {
|
namespace CPU {
|
||||||
|
|
||||||
class ARM64Recompiler final : public Recompiler
|
class ARM64Recompiler final : public Recompiler
|
||||||
{
|
{
|
||||||
@ -166,6 +166,6 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CPU::Recompiler
|
} // namespace CPU
|
||||||
|
|
||||||
#endif // CPU_ARCH_ARM64
|
#endif // CPU_ARCH_ARM64
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,9 @@
|
|||||||
|
|
||||||
#ifdef CPU_ARCH_RISCV64
|
#ifdef CPU_ARCH_RISCV64
|
||||||
|
|
||||||
namespace CPU::Recompiler {
|
#include "biscuit/assembler.hpp"
|
||||||
|
|
||||||
|
namespace CPU {
|
||||||
|
|
||||||
class RISCV64Recompiler final : public Recompiler
|
class RISCV64Recompiler final : public Recompiler
|
||||||
{
|
{
|
||||||
@ -171,6 +173,6 @@ private:
|
|||||||
biscuit::Assembler* rvAsm;
|
biscuit::Assembler* rvAsm;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CPU::Recompiler
|
} // namespace CPU
|
||||||
|
|
||||||
#endif // CPU_ARCH_RISCV64
|
#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_code_cache_private.h"
|
||||||
#include "cpu_core_private.h"
|
#include "cpu_core_private.h"
|
||||||
#include "cpu_pgxp.h"
|
#include "cpu_pgxp.h"
|
||||||
#include "cpu_recompiler_thunks.h"
|
|
||||||
#include "cpu_recompiler_types.h"
|
|
||||||
#include "gte.h"
|
#include "gte.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "timing_event.h"
|
#include "timing_event.h"
|
||||||
@ -37,25 +35,58 @@ LOG_CHANNEL(Recompiler);
|
|||||||
// PGXP TODO: LWL etc, MFC0
|
// PGXP TODO: LWL etc, MFC0
|
||||||
// PGXP TODO: Spyro 1 level gates have issues.
|
// PGXP TODO: Spyro 1 level gates have issues.
|
||||||
|
|
||||||
namespace CPU::Recompiler {
|
|
||||||
|
|
||||||
using namespace Xbyak;
|
|
||||||
|
|
||||||
static constexpr u32 BACKPATCH_JMP_SIZE = 5;
|
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
|
// 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;
|
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;
|
static constexpr u32 STACK_SHADOW_SIZE = 0;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error Unknown ABI.
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace CPU {
|
||||||
|
|
||||||
|
using namespace Xbyak;
|
||||||
|
|
||||||
static X64Recompiler s_instance;
|
static X64Recompiler s_instance;
|
||||||
Recompiler* g_compiler = &s_instance;
|
Recompiler* g_compiler = &s_instance;
|
||||||
|
|
||||||
} // namespace CPU::Recompiler
|
} // namespace CPU
|
||||||
|
|
||||||
bool CPU::Recompiler::IsCallerSavedRegister(u32 id)
|
bool IsCallerSavedRegister(u32 id)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// The x64 ABI considers the registers RAX, RCX, RDX, R8, R9, R10, R11, and XMM0-XMM5 volatile.
|
// 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
|
#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,
|
void CPU::X64Recompiler::Reset(CodeCache::Block* block, u8* code_buffer, u32 code_buffer_space, u8* far_code_buffer,
|
||||||
u8* far_code_buffer, u32 far_code_space)
|
u32 far_code_space)
|
||||||
{
|
{
|
||||||
Recompiler::Reset(block, code_buffer, code_buffer_space, far_code_buffer, 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());
|
DebugAssert(cg == m_emitter.get());
|
||||||
if (emit_jump)
|
if (emit_jump)
|
||||||
@ -377,8 +408,7 @@ void CPU::Recompiler::X64Recompiler::SwitchToFarCode(bool emit_jump, void (Xbyak
|
|||||||
cg = m_far_emitter.get();
|
cg = m_far_emitter.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::SwitchToNearCode(bool emit_jump,
|
void CPU::X64Recompiler::SwitchToNearCode(bool emit_jump, void (Xbyak::CodeGenerator::*jump_op)(const void*))
|
||||||
void (Xbyak::CodeGenerator::*jump_op)(const void*))
|
|
||||||
{
|
{
|
||||||
DebugAssert(cg == m_far_emitter.get());
|
DebugAssert(cg == m_far_emitter.get());
|
||||||
if (emit_jump)
|
if (emit_jump)
|
||||||
@ -389,7 +419,7 @@ void CPU::Recompiler::X64Recompiler::SwitchToNearCode(bool emit_jump,
|
|||||||
cg = m_emitter.get();
|
cg = m_emitter.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::BeginBlock()
|
void CPU::X64Recompiler::BeginBlock()
|
||||||
{
|
{
|
||||||
Recompiler::BeginBlock();
|
Recompiler::BeginBlock();
|
||||||
|
|
||||||
@ -408,7 +438,7 @@ void CPU::Recompiler::X64Recompiler::BeginBlock()
|
|||||||
#endif
|
#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
|
// store it first to reduce code size, because we can offset
|
||||||
cg->mov(RXARG1, static_cast<size_t>(reinterpret_cast<uintptr_t>(ram_ptr)));
|
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);
|
DebugAssert(size == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::GenerateICacheCheckAndUpdate()
|
void CPU::X64Recompiler::GenerateICacheCheckAndUpdate()
|
||||||
{
|
{
|
||||||
if (!m_block->HasFlag(CodeCache::BlockFlags::IsUsingICache))
|
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*/,
|
void CPU::X64Recompiler::GenerateCall(const void* func, s32 arg1reg /*= -1*/, s32 arg2reg /*= -1*/,
|
||||||
s32 arg3reg /*= -1*/)
|
s32 arg3reg /*= -1*/)
|
||||||
{
|
{
|
||||||
if (arg1reg >= 0 && arg1reg != static_cast<s32>(RXARG1.getIdx()))
|
if (arg1reg >= 0 && arg1reg != static_cast<s32>(RXARG1.getIdx()))
|
||||||
cg->mov(RXARG1, Reg64(arg1reg));
|
cg->mov(RXARG1, Reg64(arg1reg));
|
||||||
@ -512,7 +542,7 @@ void CPU::Recompiler::X64Recompiler::GenerateCall(const void* func, s32 arg1reg
|
|||||||
cg->call(func);
|
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())
|
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);
|
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 regs, but not pc, it's going to get overwritten
|
||||||
// flush cycles because of the GTE instruction stuff...
|
// flush cycles because of the GTE instruction stuff...
|
||||||
@ -544,8 +574,7 @@ void CPU::Recompiler::X64Recompiler::EndBlockWithException(Exception excode)
|
|||||||
EndAndLinkBlock(std::nullopt, true, false);
|
EndAndLinkBlock(std::nullopt, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::EndAndLinkBlock(const std::optional<u32>& newpc, bool do_event_test,
|
void CPU::X64Recompiler::EndAndLinkBlock(const std::optional<u32>& newpc, bool do_event_test, bool force_run_events)
|
||||||
bool force_run_events)
|
|
||||||
{
|
{
|
||||||
// event test
|
// event test
|
||||||
// pc should've been flushed
|
// 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();
|
const void* code = m_emitter->getCode();
|
||||||
*code_size = static_cast<u32>(m_emitter->getSize());
|
*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;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
const void* CPU::Recompiler::X64Recompiler::GetCurrentCodePointer()
|
const void* CPU::X64Recompiler::GetCurrentCodePointer()
|
||||||
{
|
{
|
||||||
return cg->getCurr();
|
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 = {
|
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"}};
|
{"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";
|
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);
|
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)]);
|
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));
|
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);
|
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)
|
if (src != dst)
|
||||||
cg->mov(Reg32(dst), Reg32(src));
|
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);
|
DebugAssert(r < Reg::count);
|
||||||
return cg->dword[PTR(&g_state.regs.r[static_cast<u32>(r)])];
|
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);
|
DebugAssert(cf.valid_host_d);
|
||||||
return Reg32(cf.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);
|
DebugAssert(cf.valid_host_s);
|
||||||
return Reg32(cf.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);
|
DebugAssert(cf.valid_host_t);
|
||||||
return Reg32(cf.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);
|
DebugAssert(cf.valid_host_lo);
|
||||||
return Reg32(cf.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);
|
DebugAssert(cf.valid_host_hi);
|
||||||
return Reg32(cf.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_d);
|
||||||
DebugAssert(!cf.valid_host_t || cf.host_t != cf.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;
|
return rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
Xbyak::Reg32 CPU::Recompiler::X64Recompiler::MoveSToT(CompileFlags cf)
|
Xbyak::Reg32 CPU::X64Recompiler::MoveSToT(CompileFlags cf)
|
||||||
{
|
{
|
||||||
DebugAssert(cf.valid_host_t);
|
DebugAssert(cf.valid_host_t);
|
||||||
|
|
||||||
@ -736,7 +765,7 @@ Xbyak::Reg32 CPU::Recompiler::X64Recompiler::MoveSToT(CompileFlags cf)
|
|||||||
return rt;
|
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_d);
|
||||||
DebugAssert(!cf.valid_host_s || cf.host_s != cf.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;
|
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)
|
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)
|
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);
|
DebugAssert(reg < Reg::count);
|
||||||
if (const std::optional<u32> hreg = CheckHostReg(0, Recompiler::HR_TYPE_CPU_REG, reg))
|
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));
|
cg->mov(dst, MipsPtr(reg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::GeneratePGXPCallWithMIPSRegs(const void* func, u32 arg1val,
|
void CPU::X64Recompiler::GeneratePGXPCallWithMIPSRegs(const void* func, u32 arg1val, Reg arg2reg /* = Reg::count */,
|
||||||
Reg arg2reg /* = Reg::count */,
|
Reg arg3reg /* = Reg::count */)
|
||||||
Reg arg3reg /* = Reg::count */)
|
|
||||||
{
|
{
|
||||||
DebugAssert(g_settings.gpu_pgxp_enable);
|
DebugAssert(g_settings.gpu_pgxp_enable);
|
||||||
|
|
||||||
@ -816,7 +844,7 @@ void CPU::Recompiler::X64Recompiler::GeneratePGXPCallWithMIPSRegs(const void* fu
|
|||||||
cg->call(func);
|
cg->call(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::Flush(u32 flags)
|
void CPU::X64Recompiler::Flush(u32 flags)
|
||||||
{
|
{
|
||||||
Recompiler::Flush(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);
|
WARNING_LOG("Compiling instruction fallback at PC=0x{:08X}, instruction=0x{:08X}", iinfo->pc, inst->bits);
|
||||||
|
|
||||||
Flush(FLUSH_FOR_INTERPRETER);
|
Flush(FLUSH_FOR_INTERPRETER);
|
||||||
|
|
||||||
cg->call(&CPU::Recompiler::Thunks::InterpretInstruction);
|
cg->call(&CPU::RecompilerThunks::InterpretInstruction);
|
||||||
|
|
||||||
// TODO: make me less garbage
|
// TODO: make me less garbage
|
||||||
// TODO: this is wrong, it flushes the load delay on the same cycle when we return.
|
// 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;
|
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)
|
if (!g_settings.cpu_recompiler_memory_exceptions)
|
||||||
return;
|
return;
|
||||||
@ -938,7 +966,7 @@ void CPU::Recompiler::X64Recompiler::CheckBranchTarget(const Xbyak::Reg32& pcreg
|
|||||||
SwitchToNearCode(false);
|
SwitchToNearCode(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::Compile_jr(CompileFlags cf)
|
void CPU::X64Recompiler::Compile_jr(CompileFlags cf)
|
||||||
{
|
{
|
||||||
if (!cf.valid_host_s)
|
if (!cf.valid_host_s)
|
||||||
cg->mov(RWARG1, MipsPtr(cf.MipsS()));
|
cg->mov(RWARG1, MipsPtr(cf.MipsS()));
|
||||||
@ -952,7 +980,7 @@ void CPU::Recompiler::X64Recompiler::Compile_jr(CompileFlags cf)
|
|||||||
EndBlock(std::nullopt, true);
|
EndBlock(std::nullopt, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::Compile_jalr(CompileFlags cf)
|
void CPU::X64Recompiler::Compile_jalr(CompileFlags cf)
|
||||||
{
|
{
|
||||||
if (!cf.valid_host_s)
|
if (!cf.valid_host_s)
|
||||||
cg->mov(RWARG1, MipsPtr(cf.MipsS()));
|
cg->mov(RWARG1, MipsPtr(cf.MipsS()));
|
||||||
@ -969,7 +997,7 @@ void CPU::Recompiler::X64Recompiler::Compile_jalr(CompileFlags cf)
|
|||||||
EndBlock(std::nullopt, true);
|
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);
|
const u32 taken_pc = GetConditionalBranchTarget(cf);
|
||||||
|
|
||||||
@ -1045,7 +1073,7 @@ void CPU::Recompiler::X64Recompiler::Compile_bxx(CompileFlags cf, BranchConditio
|
|||||||
EndBlock(taken_pc, true);
|
EndBlock(taken_pc, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::Compile_addi(CompileFlags cf)
|
void CPU::X64Recompiler::Compile_addi(CompileFlags cf)
|
||||||
{
|
{
|
||||||
const Reg32 rt = MoveSToT(cf);
|
const Reg32 rt = MoveSToT(cf);
|
||||||
if (const u32 imm = inst->i.imm_sext32(); imm != 0)
|
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);
|
const Reg32 rt = MoveSToT(cf);
|
||||||
if (const u32 imm = inst->i.imm_sext32(); imm != 0)
|
if (const u32 imm = inst->i.imm_sext32(); imm != 0)
|
||||||
cg->add(rt, imm);
|
cg->add(rt, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::Compile_slti(CompileFlags cf)
|
void CPU::X64Recompiler::Compile_slti(CompileFlags cf)
|
||||||
{
|
{
|
||||||
Compile_slti(cf, true);
|
Compile_slti(cf, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::Compile_sltiu(CompileFlags cf)
|
void CPU::X64Recompiler::Compile_sltiu(CompileFlags cf)
|
||||||
{
|
{
|
||||||
Compile_slti(cf, false);
|
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;
|
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);
|
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)
|
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);
|
const Reg32 rt = MoveSToT(cf);
|
||||||
if (const u32 imm = inst->i.imm_zext32(); imm != 0)
|
if (const u32 imm = inst->i.imm_zext32(); imm != 0)
|
||||||
cg->or_(rt, imm);
|
cg->or_(rt, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::Compile_xori(CompileFlags cf)
|
void CPU::X64Recompiler::Compile_xori(CompileFlags cf)
|
||||||
{
|
{
|
||||||
const Reg32 rt = MoveSToT(cf);
|
const Reg32 rt = MoveSToT(cf);
|
||||||
if (const u32 imm = inst->i.imm_zext32(); imm != 0)
|
if (const u32 imm = inst->i.imm_zext32(); imm != 0)
|
||||||
cg->xor_(rt, imm);
|
cg->xor_(rt, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::Compile_sll(CompileFlags cf)
|
void CPU::X64Recompiler::Compile_sll(CompileFlags cf)
|
||||||
{
|
{
|
||||||
const Reg32 rd = MoveTToD(cf);
|
const Reg32 rd = MoveTToD(cf);
|
||||||
if (inst->r.shamt > 0)
|
if (inst->r.shamt > 0)
|
||||||
cg->shl(rd, inst->r.shamt);
|
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);
|
const Reg32 rd = MoveTToD(cf);
|
||||||
if (inst->r.shamt > 0)
|
if (inst->r.shamt > 0)
|
||||||
cg->shr(rd, inst->r.shamt);
|
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);
|
const Reg32 rd = MoveTToD(cf);
|
||||||
if (inst->r.shamt > 0)
|
if (inst->r.shamt > 0)
|
||||||
cg->sar(rd, inst->r.shamt);
|
cg->sar(rd, inst->r.shamt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::Compile_variable_shift(
|
void CPU::X64Recompiler::Compile_variable_shift(CompileFlags cf,
|
||||||
CompileFlags cf, void (Xbyak::CodeGenerator::*op)(const Xbyak::Operand&, const Xbyak::Reg8&),
|
void (Xbyak::CodeGenerator::*op)(const Xbyak::Operand&,
|
||||||
void (Xbyak::CodeGenerator::*op_const)(const Xbyak::Operand&, int))
|
const Xbyak::Reg8&),
|
||||||
|
void (Xbyak::CodeGenerator::*op_const)(const Xbyak::Operand&, int))
|
||||||
{
|
{
|
||||||
const Reg32 rd = CFGetRegD(cf);
|
const Reg32 rd = CFGetRegD(cf);
|
||||||
if (!cf.const_s)
|
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);
|
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);
|
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);
|
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..
|
// RAX/RDX shouldn't be allocatable..
|
||||||
DebugAssert(!(m_host_regs[Xbyak::Operand::RAX].flags & HR_USABLE) &&
|
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);
|
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);
|
Compile_mult(cf, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::Compile_multu(CompileFlags cf)
|
void CPU::X64Recompiler::Compile_multu(CompileFlags cf)
|
||||||
{
|
{
|
||||||
Compile_mult(cf, false);
|
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..
|
// not supported without registers for now..
|
||||||
DebugAssert(cf.valid_host_lo && cf.valid_host_hi);
|
DebugAssert(cf.valid_host_lo && cf.valid_host_hi);
|
||||||
@ -1268,7 +1297,7 @@ void CPU::Recompiler::X64Recompiler::Compile_div(CompileFlags cf)
|
|||||||
cg->L(done);
|
cg->L(done);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::Compile_divu(CompileFlags cf)
|
void CPU::X64Recompiler::Compile_divu(CompileFlags cf)
|
||||||
{
|
{
|
||||||
// not supported without registers for now..
|
// not supported without registers for now..
|
||||||
DebugAssert(cf.valid_host_lo && cf.valid_host_hi);
|
DebugAssert(cf.valid_host_lo && cf.valid_host_hi);
|
||||||
@ -1299,7 +1328,7 @@ void CPU::Recompiler::X64Recompiler::Compile_divu(CompileFlags cf)
|
|||||||
cg->L(done);
|
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);
|
SwitchToFarCode(true, &Xbyak::CodeGenerator::jo);
|
||||||
|
|
||||||
@ -1315,9 +1344,10 @@ void CPU::Recompiler::X64Recompiler::TestOverflow(const Xbyak::Reg32& result)
|
|||||||
SwitchToNearCode(false);
|
SwitchToNearCode(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::Compile_dst_op(
|
void CPU::X64Recompiler::Compile_dst_op(CompileFlags cf,
|
||||||
CompileFlags cf, void (Xbyak::CodeGenerator::*op)(const Xbyak::Operand&, const Xbyak::Operand&),
|
void (Xbyak::CodeGenerator::*op)(const Xbyak::Operand&, const Xbyak::Operand&),
|
||||||
void (Xbyak::CodeGenerator::*op_const)(const Xbyak::Operand&, u32), bool commutative, bool overflow)
|
void (Xbyak::CodeGenerator::*op_const)(const Xbyak::Operand&, u32),
|
||||||
|
bool commutative, bool overflow)
|
||||||
{
|
{
|
||||||
if (cf.valid_host_s && cf.valid_host_t)
|
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);
|
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);
|
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);
|
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);
|
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
|
// special cases - and with self -> self, and with 0 -> 0
|
||||||
const Reg32 regd = CFGetRegD(cf);
|
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);
|
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
|
// or/nor with 0 -> no effect
|
||||||
const Reg32 regd = CFGetRegD(cf);
|
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);
|
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);
|
const Reg32 regd = CFGetRegD(cf);
|
||||||
if (cf.MipsS() == cf.MipsT())
|
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);
|
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);
|
Compile_or(cf);
|
||||||
cg->not_(CFGetRegD(cf));
|
cg->not_(CFGetRegD(cf));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::Compile_slt(CompileFlags cf)
|
void CPU::X64Recompiler::Compile_slt(CompileFlags cf)
|
||||||
{
|
{
|
||||||
Compile_slt(cf, true);
|
Compile_slt(cf, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::Compile_sltu(CompileFlags cf)
|
void CPU::X64Recompiler::Compile_sltu(CompileFlags cf)
|
||||||
{
|
{
|
||||||
Compile_slt(cf, false);
|
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 rd = CFGetRegD(cf);
|
||||||
const Reg32 rs = cf.valid_host_s ? CFGetRegS(cf) : RWARG1;
|
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());
|
sign ? cg->setl(rd.cvt8()) : cg->setb(rd.cvt8());
|
||||||
}
|
}
|
||||||
|
|
||||||
Xbyak::Reg32 CPU::Recompiler::X64Recompiler::ComputeLoadStoreAddressArg(
|
Xbyak::Reg32
|
||||||
CompileFlags cf, const std::optional<VirtualMemoryAddress>& address,
|
CPU::X64Recompiler::ComputeLoadStoreAddressArg(CompileFlags cf, const std::optional<VirtualMemoryAddress>& address,
|
||||||
const std::optional<const Xbyak::Reg32>& reg /* = std::nullopt */)
|
const std::optional<const Xbyak::Reg32>& reg /* = std::nullopt */)
|
||||||
{
|
{
|
||||||
const u32 imm = inst->i.imm_sext32();
|
const u32 imm = inst->i.imm_sext32();
|
||||||
if (cf.valid_host_s && imm == 0 && !reg.has_value())
|
if (cf.valid_host_s && imm == 0 && !reg.has_value())
|
||||||
@ -1546,8 +1576,8 @@ Xbyak::Reg32 CPU::Recompiler::X64Recompiler::ComputeLoadStoreAddressArg(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename RegAllocFn>
|
template<typename RegAllocFn>
|
||||||
Xbyak::Reg32 CPU::Recompiler::X64Recompiler::GenerateLoad(const Xbyak::Reg32& addr_reg, MemoryAccessSize size,
|
Xbyak::Reg32 CPU::X64Recompiler::GenerateLoad(const Xbyak::Reg32& addr_reg, MemoryAccessSize size, bool sign,
|
||||||
bool sign, bool use_fastmem, const RegAllocFn& dst_reg_alloc)
|
bool use_fastmem, const RegAllocFn& dst_reg_alloc)
|
||||||
{
|
{
|
||||||
if (use_fastmem)
|
if (use_fastmem)
|
||||||
{
|
{
|
||||||
@ -1608,20 +1638,20 @@ Xbyak::Reg32 CPU::Recompiler::X64Recompiler::GenerateLoad(const Xbyak::Reg32& ad
|
|||||||
{
|
{
|
||||||
case MemoryAccessSize::Byte:
|
case MemoryAccessSize::Byte:
|
||||||
{
|
{
|
||||||
cg->call(checked ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::ReadMemoryByte) :
|
cg->call(checked ? reinterpret_cast<const void*>(&RecompilerThunks::ReadMemoryByte) :
|
||||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedReadMemoryByte));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryByte));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MemoryAccessSize::HalfWord:
|
case MemoryAccessSize::HalfWord:
|
||||||
{
|
{
|
||||||
cg->call(checked ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::ReadMemoryHalfWord) :
|
cg->call(checked ? reinterpret_cast<const void*>(&RecompilerThunks::ReadMemoryHalfWord) :
|
||||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedReadMemoryHalfWord));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryHalfWord));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MemoryAccessSize::Word:
|
case MemoryAccessSize::Word:
|
||||||
{
|
{
|
||||||
cg->call(checked ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::ReadMemoryWord) :
|
cg->call(checked ? reinterpret_cast<const void*>(&RecompilerThunks::ReadMemoryWord) :
|
||||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedReadMemoryWord));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryWord));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1677,8 +1707,8 @@ Xbyak::Reg32 CPU::Recompiler::X64Recompiler::GenerateLoad(const Xbyak::Reg32& ad
|
|||||||
return dst_reg;
|
return dst_reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::X64Recompiler::GenerateStore(const Xbyak::Reg32& addr_reg, const Xbyak::Reg32& value_reg,
|
void CPU::X64Recompiler::GenerateStore(const Xbyak::Reg32& addr_reg, const Xbyak::Reg32& value_reg,
|
||||||
MemoryAccessSize size, bool use_fastmem)
|
MemoryAccessSize size, bool use_fastmem)
|
||||||
{
|
{
|
||||||
if (use_fastmem)
|
if (use_fastmem)
|
||||||
{
|
{
|
||||||
@ -1729,20 +1759,20 @@ void CPU::Recompiler::X64Recompiler::GenerateStore(const Xbyak::Reg32& addr_reg,
|
|||||||
{
|
{
|
||||||
case MemoryAccessSize::Byte:
|
case MemoryAccessSize::Byte:
|
||||||
{
|
{
|
||||||
cg->call(checked ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::WriteMemoryByte) :
|
cg->call(checked ? reinterpret_cast<const void*>(&RecompilerThunks::WriteMemoryByte) :
|
||||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedWriteMemoryByte));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryByte));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MemoryAccessSize::HalfWord:
|
case MemoryAccessSize::HalfWord:
|
||||||
{
|
{
|
||||||
cg->call(checked ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::WriteMemoryHalfWord) :
|
cg->call(checked ? reinterpret_cast<const void*>(&RecompilerThunks::WriteMemoryHalfWord) :
|
||||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedWriteMemoryHalfWord));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryHalfWord));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MemoryAccessSize::Word:
|
case MemoryAccessSize::Word:
|
||||||
{
|
{
|
||||||
cg->call(checked ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::WriteMemoryWord) :
|
cg->call(checked ? reinterpret_cast<const void*>(&RecompilerThunks::WriteMemoryWord) :
|
||||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedWriteMemoryWord));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryWord));
|
||||||
}
|
}
|
||||||
break;
|
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,
|
void CPU::X64Recompiler::Compile_lxx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||||
const std::optional<VirtualMemoryAddress>& address)
|
const std::optional<VirtualMemoryAddress>& address)
|
||||||
{
|
{
|
||||||
const std::optional<Reg32> addr_reg = g_settings.gpu_pgxp_enable ?
|
const std::optional<Reg32> addr_reg = g_settings.gpu_pgxp_enable ?
|
||||||
std::optional<Reg32>(Reg32(AllocateTempHostReg(HR_CALLEE_SAVED))) :
|
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,
|
void CPU::X64Recompiler::Compile_lwx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||||
const std::optional<VirtualMemoryAddress>& address)
|
const std::optional<VirtualMemoryAddress>& address)
|
||||||
{
|
{
|
||||||
DebugAssert(size == MemoryAccessSize::Word && !sign);
|
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,
|
void CPU::X64Recompiler::Compile_lwc2(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||||
const std::optional<VirtualMemoryAddress>& address)
|
const std::optional<VirtualMemoryAddress>& address)
|
||||||
{
|
{
|
||||||
const u32 index = static_cast<u32>(inst->r.rt.GetValue());
|
const u32 index = static_cast<u32>(inst->r.rt.GetValue());
|
||||||
const auto [ptr, action] = GetGTERegisterPointer(index, true);
|
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,
|
void CPU::X64Recompiler::Compile_sxx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||||
const std::optional<VirtualMemoryAddress>& address)
|
const std::optional<VirtualMemoryAddress>& address)
|
||||||
{
|
{
|
||||||
const std::optional<Reg32> addr_reg = g_settings.gpu_pgxp_enable ?
|
const std::optional<Reg32> addr_reg = g_settings.gpu_pgxp_enable ?
|
||||||
std::optional<Reg32>(Reg32(AllocateTempHostReg(HR_CALLEE_SAVED))) :
|
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,
|
void CPU::X64Recompiler::Compile_swx(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||||
const std::optional<VirtualMemoryAddress>& address)
|
const std::optional<VirtualMemoryAddress>& address)
|
||||||
{
|
{
|
||||||
DebugAssert(size == MemoryAccessSize::Word && !sign);
|
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,
|
void CPU::X64Recompiler::Compile_swc2(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem,
|
||||||
const std::optional<VirtualMemoryAddress>& address)
|
const std::optional<VirtualMemoryAddress>& address)
|
||||||
{
|
{
|
||||||
const u32 index = static_cast<u32>(inst->r.rt.GetValue());
|
const u32 index = static_cast<u32>(inst->r.rt.GetValue());
|
||||||
const auto [ptr, action] = GetGTERegisterPointer(index, false);
|
const auto [ptr, action] = GetGTERegisterPointer(index, false);
|
||||||
@ -2154,7 +2184,7 @@ void CPU::Recompiler::X64Recompiler::Compile_swc2(CompileFlags cf, MemoryAccessS
|
|||||||
FreeHostReg(data_backup.getIdx());
|
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 Cop0Reg reg = static_cast<Cop0Reg>(MipsD());
|
||||||
const u32* ptr = GetCop0RegPtr(reg);
|
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
|
// shift mode bits right two, preserving upper bits
|
||||||
static constexpr u32 mode_bits_mask = UINT32_C(0b1111);
|
static constexpr u32 mode_bits_mask = UINT32_C(0b1111);
|
||||||
@ -2253,7 +2283,7 @@ void CPU::Recompiler::X64Recompiler::Compile_rfe(CompileFlags cf)
|
|||||||
TestInterrupts(RWARG1);
|
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
|
// if Iec == 0 then goto no_interrupt
|
||||||
Label no_interrupt;
|
Label no_interrupt;
|
||||||
@ -2301,7 +2331,7 @@ void CPU::Recompiler::X64Recompiler::TestInterrupts(const Xbyak::Reg32& sr)
|
|||||||
cg->L(no_interrupt);
|
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 u32 index = inst->cop.Cop2Index();
|
||||||
const Reg rt = inst->r.rt;
|
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 u32 index = inst->cop.Cop2Index();
|
||||||
const auto [ptr, action] = GetGTERegisterPointer(index, true);
|
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;
|
TickCount func_ticks;
|
||||||
GTE::InstructionImpl func = GTE::GetInstructionImpl(inst->bits, &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:
|
case MemoryAccessSize::Byte:
|
||||||
{
|
{
|
||||||
cg->call(is_load ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedReadMemoryByte) :
|
cg->call(is_load ? reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryByte) :
|
||||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedWriteMemoryByte));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryByte));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MemoryAccessSize::HalfWord:
|
case MemoryAccessSize::HalfWord:
|
||||||
{
|
{
|
||||||
cg->call(is_load ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedReadMemoryHalfWord) :
|
cg->call(is_load ? reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryHalfWord) :
|
||||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedWriteMemoryHalfWord));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryHalfWord));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MemoryAccessSize::Word:
|
case MemoryAccessSize::Word:
|
||||||
{
|
{
|
||||||
cg->call(is_load ? reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedReadMemoryWord) :
|
cg->call(is_load ? reinterpret_cast<const void*>(&RecompilerThunks::UncheckedReadMemoryWord) :
|
||||||
reinterpret_cast<const void*>(&CPU::Recompiler::Thunks::UncheckedWriteMemoryWord));
|
reinterpret_cast<const void*>(&RecompilerThunks::UncheckedWriteMemoryWord));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,15 @@
|
|||||||
|
|
||||||
#ifdef CPU_ARCH_X64
|
#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
|
class X64Recompiler final : public Recompiler
|
||||||
{
|
{
|
||||||
@ -141,6 +149,6 @@ private:
|
|||||||
Xbyak::CodeGenerator* cg;
|
Xbyak::CodeGenerator* cg;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CPU::Recompiler
|
} // namespace CPU
|
||||||
|
|
||||||
#endif // CPU_ARCH_X64
|
#endif // CPU_ARCH_X64
|
||||||
|
Loading…
Reference in New Issue
Block a user