backend/arm64: Implement A32BXWritePC

This commit is contained in:
Merry 2022-07-22 14:54:28 +01:00 committed by merry
parent 67dc7f2e4e
commit 52a46d841b
2 changed files with 33 additions and 0 deletions

View file

@ -34,6 +34,8 @@ void EmitIR<IR::Opcode::A32GetCFlag>(oaknut::CodeGenerator& code, EmitContext& c
template<>
void EmitIR<IR::Opcode::A32SetCpsrNZC>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template<>
void EmitIR<IR::Opcode::A32BXWritePC>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template<>
void EmitIR<IR::Opcode::A32UpdateUpperLocationDescriptor>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst*);
template<>
void EmitIR<IR::Opcode::LogicalShiftLeft32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);

View file

@ -4,6 +4,7 @@
*/
#include <fmt/ostream.h>
#include <mcl/bit/bit_field.hpp>
#include <oaknut/oaknut.hpp>
#include "dynarmic/backend/arm64/a32_jitstate.h"
@ -175,6 +176,36 @@ void EmitIR<IR::Opcode::A32SetCpsrNZC>(oaknut::CodeGenerator& code, EmitContext&
code.STR(Wscratch0, Xstate, offsetof(A32JitState, cpsr_nzcv));
}
template<>
void EmitIR<IR::Opcode::A32BXWritePC>(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<IR::Opcode::A32UpdateUpperLocationDescriptor>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst*) {
for (auto& inst : ctx.block) {