From dab20371a24700e345c795939164508f468c6033 Mon Sep 17 00:00:00 2001 From: Yang Liu Date: Tue, 26 May 2026 17:29:01 +0800 Subject: [PATCH] [dynarmic,loongarch64] Add minimal toy implementation enough to execute LSLS --- src/dynarmic/src/dynarmic/CMakeLists.txt | 2 + .../backend/loongarch64/a32_address_space.cpp | 7 ++- .../backend/loongarch64/emit_loongarch64.cpp | 32 ++++++++++ .../loongarch64/emit_loongarch64_a32.cpp | 59 +++++++++++++++++++ .../emit_loongarch64_data_processing.cpp | 52 ++++++++++++++++ 5 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64_a32.cpp create mode 100644 src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64_data_processing.cpp diff --git a/src/dynarmic/src/dynarmic/CMakeLists.txt b/src/dynarmic/src/dynarmic/CMakeLists.txt index 20924d35b9..98fcea6333 100644 --- a/src/dynarmic/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/src/dynarmic/CMakeLists.txt @@ -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 diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/a32_address_space.cpp b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_address_space.cpp index 5f35695311..f1a7d55d2c 100644 --- a/src/dynarmic/src/dynarmic/backend/loongarch64/a32_address_space.cpp +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_address_space.cpp @@ -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(i), LA_SP, static_cast(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(); diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.cpp b/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.cpp index b37fc3d2b0..d4d8454fce 100644 --- a/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.cpp +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.cpp @@ -18,11 +18,43 @@ void EmitIR(lagoon_assembler_t&, EmitContext&, IR::Inst*) { ASSERT(false && "Unimplemented opcode"); } +template<> +void EmitIR(lagoon_assembler_t&, EmitContext&, IR::Inst*) {} + +template<> +void EmitIR(lagoon_assembler_t&, EmitContext& ctx, IR::Inst* inst); + +template<> +void EmitIR(lagoon_assembler_t&, EmitContext& ctx, IR::Inst* inst); + +template<> +void EmitIR(lagoon_assembler_t&, EmitContext& ctx, IR::Inst* inst); + +template<> +void EmitIR(lagoon_assembler_t&, EmitContext& ctx, IR::Inst* inst); + template<> void EmitIR(lagoon_assembler_t&, EmitContext& ctx, IR::Inst* inst) { ASSERT(ctx.reg_alloc.IsValueLive(inst)); } +template<> +void EmitIR(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; diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64_a32.cpp b/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64_a32.cpp new file mode 100644 index 0000000000..7ecadbec90 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64_a32.cpp @@ -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(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(offsetof(A32JitState, regs) + sizeof(u32) * static_cast(reg))); +} + +template<> +void EmitIR(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(offsetof(A32JitState, regs) + sizeof(u32) * static_cast(reg))); +} + +template<> +void EmitIR(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(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(offsetof(A32JitState, cpsr_nzcv))); +} + +} // namespace Dynarmic::Backend::LoongArch64 diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64_data_processing.cpp b/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64_data_processing.cpp new file mode 100644 index 0000000000..4f1683edcf --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64_data_processing.cpp @@ -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(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