From eaf87ec1e4dc34915aba3f879f2942fe70836482 Mon Sep 17 00:00:00 2001 From: Merry Date: Sun, 24 Jul 2022 13:13:03 +0100 Subject: [PATCH] backend/arm64: Simple implementation of memory read/write --- .../backend/arm64/a32_address_space.cpp | 57 ++++++++++++++- .../backend/arm64/a32_address_space.h | 9 +++ src/dynarmic/backend/arm64/emit_arm64.h | 8 +++ .../backend/arm64/emit_arm64_a32_memory.cpp | 72 ++++++++++--------- 4 files changed, 112 insertions(+), 34 deletions(-) diff --git a/src/dynarmic/backend/arm64/a32_address_space.cpp b/src/dynarmic/backend/arm64/a32_address_space.cpp index 3ce05922..dafb4f92 100644 --- a/src/dynarmic/backend/arm64/a32_address_space.cpp +++ b/src/dynarmic/backend/arm64/a32_address_space.cpp @@ -6,6 +6,7 @@ #include "dynarmic/backend/arm64/a32_address_space.h" #include "dynarmic/backend/arm64/abi.h" +#include "dynarmic/backend/arm64/devirtualize.h" #include "dynarmic/backend/arm64/emit_arm64.h" #include "dynarmic/backend/arm64/stack_layout.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h" @@ -14,6 +15,28 @@ namespace Dynarmic::Backend::Arm64 { +template +static void* EmitCallTrampoline(oaknut::CodeGenerator& code, T* this_) { + using namespace oaknut::util; + + const auto info = Devirtualize(this_); + + oaknut::Label l_addr, l_this; + + void* target = code.ptr(); + code.LDR(X0, l_this); + code.LDR(Xscratch0, l_addr); + code.BR(Xscratch0); + + code.align(8); + code.l(l_this); + code.dx(info.this_ptr); + code.l(l_addr); + code.dx(info.fn_ptr); + + return target; +} + A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf) : conf(conf) , mem(conf.code_cache_size) @@ -66,7 +89,6 @@ void A32AddressSpace::ClearCache() { } void A32AddressSpace::EmitPrelude() { - using namespace oaknut; using namespace oaknut::util; mem.unprotect(); @@ -81,7 +103,14 @@ void A32AddressSpace::EmitPrelude() { ABI_PopRegisters(code, ABI_CALLEE_SAVE | (1 << 30), sizeof(StackLayout)); code.RET(); - mem.protect(); + prelude_info.read_memory_8 = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead8>(code, conf.callbacks); + prelude_info.read_memory_16 = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead16>(code, conf.callbacks); + prelude_info.read_memory_32 = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead32>(code, conf.callbacks); + prelude_info.read_memory_64 = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead64>(code, conf.callbacks); + prelude_info.write_memory_8 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite8>(code, conf.callbacks); + prelude_info.write_memory_16 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite16>(code, conf.callbacks); + prelude_info.write_memory_32 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite32>(code, conf.callbacks); + prelude_info.write_memory_64 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite64>(code, conf.callbacks); prelude_info.end_of_prelude = code.ptr(); } @@ -119,6 +148,30 @@ void A32AddressSpace::Link(EmittedBlockInfo& block_info) { case LinkTarget::ReturnFromRunCode: c.B(prelude_info.return_from_run_code); break; + case LinkTarget::ReadMemory8: + c.BL(prelude_info.read_memory_8); + break; + case LinkTarget::ReadMemory16: + c.BL(prelude_info.read_memory_16); + break; + case LinkTarget::ReadMemory32: + c.BL(prelude_info.read_memory_32); + break; + case LinkTarget::ReadMemory64: + c.BL(prelude_info.read_memory_64); + break; + case LinkTarget::WriteMemory8: + c.BL(prelude_info.write_memory_8); + break; + case LinkTarget::WriteMemory16: + c.BL(prelude_info.write_memory_16); + break; + case LinkTarget::WriteMemory32: + c.BL(prelude_info.write_memory_32); + break; + case LinkTarget::WriteMemory64: + c.BL(prelude_info.write_memory_64); + break; default: ASSERT_FALSE("Invalid relocation target"); } diff --git a/src/dynarmic/backend/arm64/a32_address_space.h b/src/dynarmic/backend/arm64/a32_address_space.h index 2977ca31..d14ddfc7 100644 --- a/src/dynarmic/backend/arm64/a32_address_space.h +++ b/src/dynarmic/backend/arm64/a32_address_space.h @@ -55,6 +55,15 @@ private: using RunCodeFuncType = HaltReason (*)(CodePtr entry_point, A32JitState* context, volatile u32* halt_reason); RunCodeFuncType run_code; void* return_from_run_code; + + void* read_memory_8; + void* read_memory_16; + void* read_memory_32; + void* read_memory_64; + void* write_memory_8; + void* write_memory_16; + void* write_memory_32; + void* write_memory_64; } prelude_info; }; diff --git a/src/dynarmic/backend/arm64/emit_arm64.h b/src/dynarmic/backend/arm64/emit_arm64.h index f20f2aea..ddb7ac16 100644 --- a/src/dynarmic/backend/arm64/emit_arm64.h +++ b/src/dynarmic/backend/arm64/emit_arm64.h @@ -31,6 +31,14 @@ using CodePtr = std::byte*; enum class LinkTarget { ReturnFromRunCode, + ReadMemory8, + ReadMemory16, + ReadMemory32, + ReadMemory64, + WriteMemory8, + WriteMemory16, + WriteMemory32, + WriteMemory64, }; struct Relocation { diff --git a/src/dynarmic/backend/arm64/emit_arm64_a32_memory.cpp b/src/dynarmic/backend/arm64/emit_arm64_a32_memory.cpp index 61f9375f..83700e0f 100644 --- a/src/dynarmic/backend/arm64/emit_arm64_a32_memory.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64_a32_memory.cpp @@ -25,34 +25,38 @@ void EmitIR(oaknut::CodeGenerator& code, EmitCont template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + ctx.reg_alloc.PrepareForCall(inst, {}, args[1]); + + EmitRelocation(code, ctx, LinkTarget::ReadMemory8); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + ctx.reg_alloc.PrepareForCall(inst, {}, args[1]); + + EmitRelocation(code, ctx, LinkTarget::ReadMemory16); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + ctx.reg_alloc.PrepareForCall(inst, {}, args[1]); + + EmitRelocation(code, ctx, LinkTarget::ReadMemory32); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + ctx.reg_alloc.PrepareForCall(inst, {}, args[1]); + + EmitRelocation(code, ctx, LinkTarget::ReadMemory64); } template<> @@ -89,34 +93,38 @@ void EmitIR(oaknut::CodeGenerator& code, E template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + ctx.reg_alloc.PrepareForCall(nullptr, {}, args[1], args[2]); + + EmitRelocation(code, ctx, LinkTarget::WriteMemory8); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + ctx.reg_alloc.PrepareForCall(nullptr, {}, args[1], args[2]); + + EmitRelocation(code, ctx, LinkTarget::WriteMemory16); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + ctx.reg_alloc.PrepareForCall(nullptr, {}, args[1], args[2]); + + EmitRelocation(code, ctx, LinkTarget::WriteMemory32); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + ctx.reg_alloc.PrepareForCall(nullptr, {}, args[1], args[2]); + + EmitRelocation(code, ctx, LinkTarget::WriteMemory64); } template<>