diff --git a/src/dynarmic/backend/arm64/emit_arm64.cpp b/src/dynarmic/backend/arm64/emit_arm64.cpp index 1a282cc0..3424c28f 100644 --- a/src/dynarmic/backend/arm64/emit_arm64.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64.cpp @@ -34,6 +34,8 @@ void EmitIR(oaknut::CodeGenerator& code, EmitContext& c template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst); template<> +void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst); +template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst*); template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst); diff --git a/src/dynarmic/backend/arm64/emit_arm64_a32.cpp b/src/dynarmic/backend/arm64/emit_arm64_a32.cpp index 8f3c5ba0..b732caf6 100644 --- a/src/dynarmic/backend/arm64/emit_arm64_a32.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64_a32.cpp @@ -4,6 +4,7 @@ */ #include +#include #include #include "dynarmic/backend/arm64/a32_jitstate.h" @@ -175,6 +176,36 @@ void EmitIR(oaknut::CodeGenerator& code, EmitContext& code.STR(Wscratch0, Xstate, offsetof(A32JitState, cpsr_nzcv)); } +template<> +void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + const u32 upper_without_t = (A32::LocationDescriptor{ctx.block.EndLocation()}.SetSingleStepping(false).UniqueHash() >> 32) & 0xFFFFFFFE; + + static_assert(offsetof(A32JitState, regs) + 16 * sizeof(u32) == offsetof(A32JitState, upper_location_descriptor)); + + if (args[0].IsImmediate()) { + const u32 new_pc = args[0].GetImmediateU32(); + const u32 mask = mcl::bit::get_bit<0>(new_pc) ? 0xFFFFFFFE : 0xFFFFFFFC; + const u32 new_upper = upper_without_t | (mcl::bit::get_bit<0>(new_pc) ? 1 : 0); + + code.MOV(Xscratch0, (u64{new_upper} << 32) | (new_pc & mask)); + code.STUR(Xscratch0, Xstate, offsetof(A32JitState, regs) + 15 * sizeof(u32)); + } else { + auto Wpc = ctx.reg_alloc.ReadW(args[0]); + RegAlloc::Realize(Wpc); + ctx.reg_alloc.SpillFlags(); + + code.ANDS(Wscratch0, Wpc, 1); + code.MOV(Wscratch1, 3); + code.CSEL(Wscratch1, Wscratch0, Wscratch1, NE); + code.BIC(Wscratch1, Wpc, Wscratch1); + code.MOV(Wscratch0, upper_without_t); + code.CINC(Wscratch0, Wscratch0, NE); + code.STP(Wscratch1, Wscratch0, Xstate, offsetof(A32JitState, regs) + 15 * sizeof(u32)); + } +} + template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst*) { for (auto& inst : ctx.block) {