diff --git a/src/dynarmic/backend/arm64/a32_address_space.cpp b/src/dynarmic/backend/arm64/a32_address_space.cpp index 01b78938..306db097 100644 --- a/src/dynarmic/backend/arm64/a32_address_space.cpp +++ b/src/dynarmic/backend/arm64/a32_address_space.cpp @@ -303,6 +303,11 @@ EmittedBlockInfo A32AddressSpace::Emit(IR::Block block) { mem.unprotect(); const EmitConfig emit_conf{ + .tpidr_el0{}, + .tpidrro_el0{}, + .cntfreq_el0{}, + .dczid_el0{}, + .ctr_el0{}, .hook_isb = conf.hook_isb, .enable_cycle_counting = conf.enable_cycle_counting, .always_little_endian = conf.always_little_endian, diff --git a/src/dynarmic/backend/arm64/a64_address_space.cpp b/src/dynarmic/backend/arm64/a64_address_space.cpp index 576ad17e..f59e663d 100644 --- a/src/dynarmic/backend/arm64/a64_address_space.cpp +++ b/src/dynarmic/backend/arm64/a64_address_space.cpp @@ -182,6 +182,7 @@ void A64AddressSpace::EmitPrelude() { prelude_info.isb_raised = EmitCallTrampoline<&A64::UserCallbacks::InstructionSynchronizationBarrierRaised>(code, conf.callbacks); prelude_info.ic_raised = EmitCallTrampoline<&A64::UserCallbacks::InstructionCacheOperationRaised>(code, conf.callbacks); prelude_info.dc_raised = EmitCallTrampoline<&A64::UserCallbacks::DataCacheOperationRaised>(code, conf.callbacks); + prelude_info.get_cntpct = EmitCallTrampoline<&A64::UserCallbacks::GetCNTPCT>(code, conf.callbacks); prelude_info.add_ticks = EmitCallTrampoline<&A64::UserCallbacks::AddTicks>(code, conf.callbacks); prelude_info.get_ticks_remaining = EmitCallTrampoline<&A64::UserCallbacks::GetTicksRemaining>(code, conf.callbacks); @@ -201,10 +202,12 @@ void A64AddressSpace::EmitPrelude() { code.STR(Xticks, SP, offsetof(StackLayout, cycles_to_run)); } - code.LDR(Wscratch0, Xstate, offsetof(A64JitState, fpcr)); code.MRS(Xscratch1, oaknut::SystemReg::FPCR); code.STR(Wscratch1, SP, offsetof(StackLayout, save_host_fpcr)); + code.LDR(Wscratch0, Xstate, offsetof(A64JitState, fpcr)); + code.LDR(Wscratch1, Xstate, offsetof(A64JitState, fpsr)); code.MSR(oaknut::SystemReg::FPCR, Xscratch0); + code.MSR(oaknut::SystemReg::FPSR, Xscratch1); code.LDAR(Wscratch0, Xhalt); code.CBNZ(Wscratch0, return_from_run_code); @@ -225,10 +228,12 @@ void A64AddressSpace::EmitPrelude() { code.STR(Xticks, SP, offsetof(StackLayout, cycles_to_run)); } - code.LDR(Wscratch0, Xstate, offsetof(A64JitState, fpcr)); code.MRS(Xscratch1, oaknut::SystemReg::FPCR); code.STR(Wscratch1, SP, offsetof(StackLayout, save_host_fpcr)); + code.LDR(Wscratch0, Xstate, offsetof(A64JitState, fpcr)); + code.LDR(Wscratch1, Xstate, offsetof(A64JitState, fpsr)); code.MSR(oaknut::SystemReg::FPCR, Xscratch0); + code.MSR(oaknut::SystemReg::FPSR, Xscratch1); oaknut::Label step_hr_loop; code.l(step_hr_loop); @@ -311,6 +316,11 @@ EmittedBlockInfo A64AddressSpace::Emit(IR::Block block) { mem.unprotect(); const EmitConfig emit_conf{ + .tpidr_el0 = conf.tpidr_el0, + .tpidrro_el0 = conf.tpidrro_el0, + .cntfreq_el0 = conf.cntfrq_el0, + .dczid_el0 = conf.dczid_el0, + .ctr_el0 = conf.ctr_el0, .hook_isb = conf.hook_isb, .enable_cycle_counting = conf.enable_cycle_counting, .always_little_endian = true, @@ -437,6 +447,9 @@ void A64AddressSpace::Link(IR::LocationDescriptor block_descriptor, EmittedBlock case LinkTarget::DataCacheOperationRaised: c.BL(prelude_info.dc_raised); break; + case LinkTarget::GetCNTPCT: + c.BL(prelude_info.get_cntpct); + break; case LinkTarget::AddTicks: c.BL(prelude_info.add_ticks); break; diff --git a/src/dynarmic/backend/arm64/a64_address_space.h b/src/dynarmic/backend/arm64/a64_address_space.h index b810107c..9ae78ad8 100644 --- a/src/dynarmic/backend/arm64/a64_address_space.h +++ b/src/dynarmic/backend/arm64/a64_address_space.h @@ -86,6 +86,7 @@ private: void* dc_raised; void* ic_raised; void* isb_raised; + void* get_cntpct; void* add_ticks; void* get_ticks_remaining; } prelude_info; diff --git a/src/dynarmic/backend/arm64/emit_arm64.h b/src/dynarmic/backend/arm64/emit_arm64.h index 72124aa4..290230ac 100644 --- a/src/dynarmic/backend/arm64/emit_arm64.h +++ b/src/dynarmic/backend/arm64/emit_arm64.h @@ -68,6 +68,7 @@ enum class LinkTarget { InstructionSynchronizationBarrierRaised, InstructionCacheOperationRaised, DataCacheOperationRaised, + GetCNTPCT, AddTicks, GetTicksRemaining, }; @@ -89,6 +90,11 @@ struct EmittedBlockInfo { }; struct EmitConfig { + u64* tpidr_el0; + const u64* tpidrro_el0; + u64 cntfreq_el0; + u32 dczid_el0; + u32 ctr_el0; bool hook_isb; bool enable_cycle_counting; bool always_little_endian; diff --git a/src/dynarmic/backend/arm64/emit_arm64_a64.cpp b/src/dynarmic/backend/arm64/emit_arm64_a64.cpp index 4bd2e270..6da15076 100644 --- a/src/dynarmic/backend/arm64/emit_arm64_a64.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64_a64.cpp @@ -4,8 +4,9 @@ */ #include +#include -#include "dynarmic/backend/arm64/a32_jitstate.h" +#include "dynarmic/backend/arm64/a64_jitstate.h" #include "dynarmic/backend/arm64/abi.h" #include "dynarmic/backend/arm64/emit_arm64.h" #include "dynarmic/backend/arm64/emit_context.h" @@ -18,292 +19,357 @@ namespace Dynarmic::Backend::Arm64 { using namespace oaknut::util; +static constexpr int nzcv_c_flag_shift = 29; + 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); + + if (args[0].IsImmediate()) { + if (args[0].GetImmediateU1()) { + code.MOV(Wscratch0, 1); + code.STRB(Wscratch0, SP, offsetof(StackLayout, check_bit)); + } else { + code.STRB(WZR, SP, offsetof(StackLayout, check_bit)); + } + } else { + auto Wbit = ctx.reg_alloc.ReadW(args[0]); + RegAlloc::Realize(Wbit); + code.STRB(Wbit, SP, offsetof(StackLayout, check_bit)); + } } 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); + auto Wresult = ctx.reg_alloc.WriteW(inst); + RegAlloc::Realize(Wresult); + code.LDR(Wresult, Xstate, offsetof(A64JitState, cpsr_nzcv)); + code.UBFX(Wresult, Wresult, nzcv_c_flag_shift, 1); } 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); + auto Wnzcv = ctx.reg_alloc.WriteW(inst); + RegAlloc::Realize(Wnzcv); + + code.LDR(Wnzcv, Xstate, offsetof(A64JitState, cpsr_nzcv)); } 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); + auto Wnzcv = ctx.reg_alloc.ReadW(args[0]); + RegAlloc::Realize(Wnzcv); + + code.STR(Wnzcv, Xstate, offsetof(A64JitState, cpsr_nzcv)); } 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); + auto Wnzcv = ctx.reg_alloc.ReadW(args[0]); + RegAlloc::Realize(Wnzcv); + + code.STR(Wnzcv, Xstate, offsetof(A64JitState, cpsr_nzcv)); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + const A64::Reg reg = inst->GetArg(0).GetA64RegRef(); + + auto Wresult = ctx.reg_alloc.WriteW(inst); + RegAlloc::Realize(Wresult); + + // TODO: Detect if Gpr vs Fpr is more appropriate + + code.LDR(Wresult, Xstate, offsetof(A64JitState, reg) + sizeof(u64) * static_cast(reg)); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + const A64::Reg reg = inst->GetArg(0).GetA64RegRef(); + + auto Xresult = ctx.reg_alloc.WriteX(inst); + RegAlloc::Realize(Xresult); + + // TODO: Detect if Gpr vs Fpr is more appropriate + + code.LDR(Xresult, Xstate, offsetof(A64JitState, reg) + sizeof(u64) * static_cast(reg)); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + const A64::Vec vec = inst->GetArg(0).GetA64VecRef(); + auto Sresult = ctx.reg_alloc.WriteS(inst); + RegAlloc::Realize(Sresult); + code.LDR(Sresult, Xstate, offsetof(A64JitState, vec) + sizeof(u64)*2 * static_cast(vec)); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + const A64::Vec vec = inst->GetArg(0).GetA64VecRef(); + auto Dresult = ctx.reg_alloc.WriteD(inst); + RegAlloc::Realize(Dresult); + code.LDR(Dresult, Xstate, offsetof(A64JitState, vec) + sizeof(u64)*2 * static_cast(vec)); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + const A64::Vec vec = inst->GetArg(0).GetA64VecRef(); + auto Qresult = ctx.reg_alloc.WriteQ(inst); + RegAlloc::Realize(Qresult); + code.LDR(Qresult, Xstate, offsetof(A64JitState, vec) + sizeof(u64)*2 * static_cast(vec)); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + const A64::Reg reg = inst->GetArg(0).GetA64RegRef(); + + auto Xresult = ctx.reg_alloc.WriteX(inst); + RegAlloc::Realize(Xresult); + + code.LDR(Xresult, Xstate, offsetof(A64JitState, sp)); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + const A64::Reg reg = inst->GetArg(0).GetA64RegRef(); + + auto Wresult = ctx.reg_alloc.WriteW(inst); + RegAlloc::Realize(Wresult); + + code.LDR(Wresult, Xstate, offsetof(A64JitState, fpcr)); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + const A64::Reg reg = inst->GetArg(0).GetA64RegRef(); + + auto Wresult = ctx.reg_alloc.WriteW(inst); + RegAlloc::Realize(Wresult); + + code.LDR(Wresult, Xstate, offsetof(A64JitState, fpsr)); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + const A64::Reg reg = inst->GetArg(0).GetA64RegRef(); + + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + auto Wvalue = ctx.reg_alloc.ReadW(args[1]); + RegAlloc::Realize(Wvalue); + + // TODO: Detect if Gpr vs Fpr is more appropriate + + code.STR(Wvalue, Xstate, offsetof(A64JitState, reg) + sizeof(u64) * static_cast(reg)); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + const A64::Reg reg = inst->GetArg(0).GetA64RegRef(); + + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + auto Xvalue = ctx.reg_alloc.ReadX(args[1]); + RegAlloc::Realize(Xvalue); + + // TODO: Detect if Gpr vs Fpr is more appropriate + + code.STR(Xvalue, Xstate, offsetof(A64JitState, reg) + sizeof(u64) * static_cast(reg)); } 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); + const A64::Vec vec = inst->GetArg(0).GetA64VecRef(); + auto Svalue = ctx.reg_alloc.ReadS(args[1]); + RegAlloc::Realize(Svalue); + code.STR(Svalue, Xstate, offsetof(A64JitState, vec) + sizeof(u64)*2*static_cast(vec)); } 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); + const A64::Vec vec = inst->GetArg(0).GetA64VecRef(); + auto Dvalue = ctx.reg_alloc.ReadD(args[1]); + RegAlloc::Realize(Dvalue); + code.STR(Dvalue, Xstate, offsetof(A64JitState, vec) + sizeof(u64)*2*static_cast(vec)); } 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); + const A64::Vec vec = inst->GetArg(0).GetA64VecRef(); + auto Qvalue = ctx.reg_alloc.ReadQ(args[1]); + RegAlloc::Realize(Qvalue); + code.STR(Qvalue, Xstate, offsetof(A64JitState, vec) + sizeof(u64)*2*static_cast(vec)); } 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); + auto Xvalue = ctx.reg_alloc.ReadX(args[0]); + RegAlloc::Realize(Xvalue); + code.STR(Xvalue, Xstate, offsetof(A64JitState, sp)); } 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); + auto Wvalue = ctx.reg_alloc.ReadW(args[0]); + RegAlloc::Realize(Wvalue); + code.STR(Wvalue, Xstate, offsetof(A64JitState, fpcr)); + code.MSR(oaknut::SystemReg::FPCR, Wvalue->toX()); } 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); + auto Wvalue = ctx.reg_alloc.ReadW(args[0]); + RegAlloc::Realize(Wvalue); + code.STR(Wvalue, Xstate, offsetof(A64JitState, fpsr)); + code.MSR(oaknut::SystemReg::FPSR, Wvalue->toX()); } 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); + auto Xvalue = ctx.reg_alloc.ReadX(args[0]); + RegAlloc::Realize(Xvalue); + code.STR(Xvalue, Xstate, offsetof(A64JitState, pc)); } 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); + + if (ctx.conf.enable_cycle_counting) { + code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_to_run)); + code.SUB(Xscratch0, Xscratch0, Xticks); + EmitRelocation(code, ctx, LinkTarget::AddTicks); + } + + code.MOV(W1, args[0].GetImmediateU32()); + EmitRelocation(code, ctx, LinkTarget::CallSVC); + + if (ctx.conf.enable_cycle_counting) { + EmitRelocation(code, ctx, LinkTarget::GetTicksRemaining); + code.STR(X0, SP, offsetof(StackLayout, cycles_to_run)); + code.MOV(Xticks, X0); + } } 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); + + if (ctx.conf.enable_cycle_counting) { + code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_to_run)); + code.SUB(Xscratch0, Xscratch0, Xticks); + EmitRelocation(code, ctx, LinkTarget::AddTicks); + } + + code.MOV(X1, args[0].GetImmediateU64()); + code.MOV(X2, args[1].GetImmediateU64()); + EmitRelocation(code, ctx, LinkTarget::ExceptionRaised); + + if (ctx.conf.enable_cycle_counting) { + EmitRelocation(code, ctx, LinkTarget::GetTicksRemaining); + code.STR(X0, SP, offsetof(StackLayout, cycles_to_run)); + code.MOV(Xticks, X0); + } } 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::DataCacheOperationRaised); } 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::InstructionCacheOperationRaised); } template<> -void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); +void EmitIR(oaknut::CodeGenerator& code, EmitContext&, IR::Inst*) { + code.DSB(oaknut::BarrierOp::SY); } template<> -void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); +void EmitIR(oaknut::CodeGenerator& code, EmitContext&, IR::Inst*) { + code.DMB(oaknut::BarrierOp::SY); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + if (!ctx.conf.hook_isb) { + return; + } + + ctx.reg_alloc.PrepareForCall(nullptr); + EmitRelocation(code, ctx, LinkTarget::InstructionSynchronizationBarrierRaised); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + auto Xvalue = ctx.reg_alloc.WriteX(inst); + RegAlloc::Realize(Xvalue); + code.MOV(Xvalue, ctx.conf.cntfreq_el0); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + // FIXME: AddTicks / GetTicksRemaining + ctx.reg_alloc.PrepareForCall(inst); + EmitRelocation(code, ctx, LinkTarget::GetCNTPCT); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + auto Wvalue = ctx.reg_alloc.WriteW(inst); + RegAlloc::Realize(Wvalue); + code.MOV(Wvalue, ctx.conf.ctr_el0); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + auto Wvalue = ctx.reg_alloc.WriteW(inst); + RegAlloc::Realize(Wvalue); + code.MOV(Wvalue, ctx.conf.dczid_el0); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + auto Xvalue = ctx.reg_alloc.WriteX(inst); + RegAlloc::Realize(Xvalue); + code.MOV(Xscratch0, mcl::bit_cast(ctx.conf.tpidr_el0)); + code.LDR(Xvalue, Xscratch0); } template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - (void)code; - (void)ctx; - (void)inst; - ASSERT_FALSE("Unimplemented"); + auto Xvalue = ctx.reg_alloc.WriteX(inst); + RegAlloc::Realize(Xvalue); + code.MOV(Xscratch0, mcl::bit_cast(ctx.conf.tpidrro_el0)); + code.LDR(Xvalue, Xscratch0); } 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); + auto Xvalue = ctx.reg_alloc.ReadX(args[0]); + RegAlloc::Realize(Xvalue); + code.MOV(Xscratch0, mcl::bit_cast(ctx.conf.tpidrro_el0)); + code.STR(Xvalue, Xscratch0); } } // namespace Dynarmic::Backend::Arm64 diff --git a/src/dynarmic/interface/A64/config.h b/src/dynarmic/interface/A64/config.h index 0b016eab..409e0048 100644 --- a/src/dynarmic/interface/A64/config.h +++ b/src/dynarmic/interface/A64/config.h @@ -198,7 +198,7 @@ struct UserConfig { /// Pointer to where TPIDR_EL0 is stored. This pointer will be inserted into /// emitted code. - const std::uint64_t* tpidr_el0 = nullptr; + std::uint64_t* tpidr_el0 = nullptr; /// Pointer to the page table which we can use for direct page table access. /// If an entry in page_table is null, the relevant memory callback will be called.