[dynarmic,loongarch64] Add minimal toy implementation enough to execute LSLS

This commit is contained in:
Yang Liu 2026-05-26 17:29:01 +08:00 committed by crueter
parent 16ba4cb997
commit dab20371a2
5 changed files with 150 additions and 2 deletions

View file

@ -306,6 +306,8 @@ if ("loongarch64" IN_LIST ARCHITECTURE)
backend/loongarch64/emit_context.h
backend/loongarch64/emit_loongarch64.cpp
backend/loongarch64/emit_loongarch64.h
backend/loongarch64/emit_loongarch64_a32.cpp
backend/loongarch64/emit_loongarch64_data_processing.cpp
backend/loongarch64/a32_address_space.cpp
backend/loongarch64/a32_address_space.h
backend/loongarch64/a32_interface.cpp

View file

@ -6,6 +6,7 @@
#include "common/assert.h"
#include "dynarmic/backend/loongarch64/a32_jitstate.h"
#include "dynarmic/backend/loongarch64/abi.h"
#include "dynarmic/backend/loongarch64/emit_loongarch64.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/frontend/A32/translate/a32_translate.h"
@ -62,8 +63,10 @@ void A32AddressSpace::EmitPrelude() {
la_st_d(&cb.as, static_cast<la_gpr_t>(i), LA_SP, static_cast<int32_t>(i * 8));
}
// Jump to block entry (a0)
la_jr(&cb.as, LA_A0);
// Set up reserved registers and jump to block entry
la_move(&cb.as, Xstate, LA_A1); // Xstate = state ptr
la_move(&cb.as, Xhalt, LA_A2); // Xhalt = halt reason ptr
la_jr(&cb.as, LA_A0); // jump to block_entry
prelude_info.return_from_run_code = GetCursorPtr<CodePtr>();

View file

@ -18,11 +18,43 @@ void EmitIR(lagoon_assembler_t&, EmitContext&, IR::Inst*) {
ASSERT(false && "Unimplemented opcode");
}
template<>
void EmitIR<IR::Opcode::Void>(lagoon_assembler_t&, EmitContext&, IR::Inst*) {}
template<>
void EmitIR<IR::Opcode::A32GetRegister>(lagoon_assembler_t&, EmitContext& ctx, IR::Inst* inst);
template<>
void EmitIR<IR::Opcode::A32SetRegister>(lagoon_assembler_t&, EmitContext& ctx, IR::Inst* inst);
template<>
void EmitIR<IR::Opcode::A32SetCpsrNZC>(lagoon_assembler_t&, EmitContext& ctx, IR::Inst* inst);
template<>
void EmitIR<IR::Opcode::LogicalShiftLeft32>(lagoon_assembler_t&, EmitContext& ctx, IR::Inst* inst);
template<>
void EmitIR<IR::Opcode::GetCarryFromOp>(lagoon_assembler_t&, EmitContext& ctx, IR::Inst* inst) {
ASSERT(ctx.reg_alloc.IsValueLive(inst));
}
template<>
void EmitIR<IR::Opcode::GetNZFromOp>(lagoon_assembler_t& as, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto Xvalue = ctx.reg_alloc.ReadX(args[0]);
auto Xnz = ctx.reg_alloc.WriteX(inst);
RegAlloc::Realize(Xvalue, Xnz);
// Z flag (bit 30): set if value == 0
la_sltui(&as, Xnz->index, Xvalue->index, 1);
la_slli_d(&as, Xnz->index, Xnz->index, 30);
// N flag (bit 31): set if value < 0 (signed)
la_slt(&as, Xscratch0, Xvalue->index, LA_ZERO);
la_slli_d(&as, Xscratch0, Xscratch0, 31);
la_or(&as, Xnz->index, Xnz->index, Xscratch0);
}
EmittedBlockInfo EmitLoongArch64(lagoon_assembler_t& as, IR::Block block, const EmitConfig& emit_conf) {
EmittedBlockInfo ebi;

View file

@ -0,0 +1,59 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "dynarmic/backend/loongarch64/lagoon_cpp.h"
#include "dynarmic/backend/loongarch64/a32_jitstate.h"
#include "dynarmic/backend/loongarch64/abi.h"
#include "dynarmic/backend/loongarch64/emit_context.h"
#include "dynarmic/backend/loongarch64/emit_loongarch64.h"
#include "dynarmic/backend/loongarch64/reg_alloc.h"
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
#include "dynarmic/ir/opcodes.h"
namespace Dynarmic::Backend::LoongArch64 {
template<>
void EmitIR<IR::Opcode::A32GetRegister>(lagoon_assembler_t& as, EmitContext& ctx, IR::Inst* inst) {
const A32::Reg reg = inst->GetArg(0).GetA32RegRef();
auto Xresult = ctx.reg_alloc.WriteX(inst);
RegAlloc::Realize(Xresult);
la_ld_wu(&as, Xresult->index, Xstate,
static_cast<int32_t>(offsetof(A32JitState, regs) + sizeof(u32) * static_cast<size_t>(reg)));
}
template<>
void EmitIR<IR::Opcode::A32SetRegister>(lagoon_assembler_t& as, EmitContext& ctx, IR::Inst* inst) {
const A32::Reg reg = inst->GetArg(0).GetA32RegRef();
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto Xvalue = ctx.reg_alloc.ReadX(args[1]);
RegAlloc::Realize(Xvalue);
la_st_w(&as, Xvalue->index, Xstate,
static_cast<int32_t>(offsetof(A32JitState, regs) + sizeof(u32) * static_cast<size_t>(reg)));
}
template<>
void EmitIR<IR::Opcode::A32SetCpsrNZC>(lagoon_assembler_t& as, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ASSERT(!args[0].IsImmediate() && !args[1].IsImmediate());
auto Xnz = ctx.reg_alloc.ReadX(args[0]);
auto Xc = ctx.reg_alloc.ReadX(args[1]);
RegAlloc::Realize(Xnz, Xc);
la_ld_wu(&as, Xscratch0, Xstate, static_cast<int32_t>(offsetof(A32JitState, cpsr_nzcv)));
la_load_immediate64(&as, Xscratch1, 0x10000000);
la_and(&as, Xscratch0, Xscratch0, Xscratch1);
la_or(&as, Xscratch0, Xscratch0, Xnz->index);
la_slli_w(&as, Xscratch1, Xc->index, 29);
la_or(&as, Xscratch0, Xscratch0, Xscratch1);
la_st_w(&as, Xscratch0, Xstate, static_cast<int32_t>(offsetof(A32JitState, cpsr_nzcv)));
}
} // namespace Dynarmic::Backend::LoongArch64

View file

@ -0,0 +1,52 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "dynarmic/backend/loongarch64/lagoon_cpp.h"
#include "dynarmic/backend/loongarch64/abi.h"
#include "dynarmic/backend/loongarch64/emit_context.h"
#include "dynarmic/backend/loongarch64/emit_loongarch64.h"
#include "dynarmic/backend/loongarch64/reg_alloc.h"
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
#include "dynarmic/ir/opcodes.h"
namespace Dynarmic::Backend::LoongArch64 {
template<>
void EmitIR<IR::Opcode::LogicalShiftLeft32>(lagoon_assembler_t& as, EmitContext& ctx, IR::Inst* inst) {
const auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp);
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto& operand_arg = args[0];
auto& shift_arg = args[1];
auto& carry_arg = args[2];
ASSERT(carry_inst != nullptr);
ASSERT(shift_arg.IsImmediate());
auto Xresult = ctx.reg_alloc.WriteX(inst);
auto Xcarry_out = ctx.reg_alloc.WriteX(carry_inst);
auto Xoperand = ctx.reg_alloc.ReadX(operand_arg);
auto Xcarry_in = ctx.reg_alloc.ReadX(carry_arg);
RegAlloc::Realize(Xresult, Xcarry_out, Xoperand, Xcarry_in);
const u8 shift = shift_arg.GetImmediateU8();
if (shift == 0) {
la_addi_w(&as, Xresult->index, Xoperand->index, 0);
la_addi_w(&as, Xcarry_out->index, Xcarry_in->index, 0);
} else if (shift < 32) {
la_srli_w(&as, Xcarry_out->index, Xoperand->index, 32 - shift);
la_andi(&as, Xcarry_out->index, Xcarry_out->index, 1);
la_slli_w(&as, Xresult->index, Xoperand->index, shift);
} else if (shift > 32) {
la_move(&as, Xresult->index, LA_ZERO);
la_move(&as, Xcarry_out->index, LA_ZERO);
} else {
la_andi(&as, Xcarry_out->index, Xoperand->index, 1);
la_move(&as, Xresult->index, LA_ZERO);
}
}
} // namespace Dynarmic::Backend::LoongArch64