Add emit_arm64_a64

This commit is contained in:
Liam 2022-11-13 13:48:31 -05:00
parent a8cb2c33f6
commit 803743488a
6 changed files with 241 additions and 150 deletions

View file

@ -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,

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -4,8 +4,9 @@
*/
#include <oaknut/oaknut.hpp>
#include <mcl/bit_cast.hpp>
#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<IR::Opcode::A64SetCheckBit>(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<IR::Opcode::A64GetCFlag>(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<IR::Opcode::A64GetNZCVRaw>(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<IR::Opcode::A64SetNZCVRaw>(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<IR::Opcode::A64SetNZCV>(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<IR::Opcode::A64GetW>(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<size_t>(reg));
}
template<>
void EmitIR<IR::Opcode::A64GetX>(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<size_t>(reg));
}
template<>
void EmitIR<IR::Opcode::A64GetS>(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<size_t>(vec));
}
template<>
void EmitIR<IR::Opcode::A64GetD>(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<size_t>(vec));
}
template<>
void EmitIR<IR::Opcode::A64GetQ>(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<size_t>(vec));
}
template<>
void EmitIR<IR::Opcode::A64GetSP>(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<IR::Opcode::A64GetFPCR>(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<IR::Opcode::A64GetFPSR>(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<IR::Opcode::A64SetW>(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<size_t>(reg));
}
template<>
void EmitIR<IR::Opcode::A64SetX>(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<size_t>(reg));
}
template<>
void EmitIR<IR::Opcode::A64SetS>(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<size_t>(vec));
}
template<>
void EmitIR<IR::Opcode::A64SetD>(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<size_t>(vec));
}
template<>
void EmitIR<IR::Opcode::A64SetQ>(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<size_t>(vec));
}
template<>
void EmitIR<IR::Opcode::A64SetSP>(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<IR::Opcode::A64SetFPCR>(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<IR::Opcode::A64SetFPSR>(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<IR::Opcode::A64SetPC>(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<IR::Opcode::A64CallSupervisor>(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<IR::Opcode::A64ExceptionRaised>(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<IR::Opcode::A64DataCacheOperationRaised>(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<IR::Opcode::A64InstructionCacheOperationRaised>(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<IR::Opcode::A64DataSynchronizationBarrier>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
void EmitIR<IR::Opcode::A64DataSynchronizationBarrier>(oaknut::CodeGenerator& code, EmitContext&, IR::Inst*) {
code.DSB(oaknut::BarrierOp::SY);
}
template<>
void EmitIR<IR::Opcode::A64DataMemoryBarrier>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
void EmitIR<IR::Opcode::A64DataMemoryBarrier>(oaknut::CodeGenerator& code, EmitContext&, IR::Inst*) {
code.DMB(oaknut::BarrierOp::SY);
}
template<>
void EmitIR<IR::Opcode::A64InstructionSynchronizationBarrier>(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<IR::Opcode::A64GetCNTFRQ>(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<IR::Opcode::A64GetCNTPCT>(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<IR::Opcode::A64GetCTR>(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<IR::Opcode::A64GetDCZID>(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<IR::Opcode::A64GetTPIDR>(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<u64>(ctx.conf.tpidr_el0));
code.LDR(Xvalue, Xscratch0);
}
template<>
void EmitIR<IR::Opcode::A64GetTPIDRRO>(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<u64>(ctx.conf.tpidrro_el0));
code.LDR(Xvalue, Xscratch0);
}
template<>
void EmitIR<IR::Opcode::A64SetTPIDR>(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<u64>(ctx.conf.tpidrro_el0));
code.STR(Xvalue, Xscratch0);
}
} // namespace Dynarmic::Backend::Arm64

View file

@ -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.