From ffc7910cd3892f6206ff94d8a09bb74bcdc70431 Mon Sep 17 00:00:00 2001 From: Yang Liu Date: Tue, 26 May 2026 16:23:28 +0800 Subject: [PATCH] [dynarmic,loongarch64] Add initial loongarch64 framework --- src/dynarmic/src/dynarmic/CMakeLists.txt | 10 +- .../backend/loongarch64/a32_address_space.cpp | 119 ++++++++++++++++++ .../backend/loongarch64/a32_address_space.h | 68 ++++++++++ .../backend/loongarch64/a32_interface.cpp | 99 ++++++++++----- .../backend/loongarch64/a32_jitstate.cpp | 57 +++++++++ .../backend/loongarch64/a32_jitstate.h | 43 +++++++ .../dynarmic/backend/loongarch64/code_block.h | 24 ++++ .../backend/loongarch64/emit_loongarch64.cpp | 33 +++++ .../backend/loongarch64/emit_loongarch64.h | 40 ++++++ .../dynarmic/backend/loongarch64/lagoon_cpp.h | 8 ++ src/dynarmic/src/dynarmic/common/atomic.h | 8 ++ 11 files changed, 475 insertions(+), 34 deletions(-) create mode 100644 src/dynarmic/src/dynarmic/backend/loongarch64/a32_address_space.cpp create mode 100644 src/dynarmic/src/dynarmic/backend/loongarch64/a32_address_space.h create mode 100644 src/dynarmic/src/dynarmic/backend/loongarch64/a32_jitstate.cpp create mode 100644 src/dynarmic/src/dynarmic/backend/loongarch64/a32_jitstate.h create mode 100644 src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.cpp create mode 100644 src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.h create mode 100644 src/dynarmic/src/dynarmic/backend/loongarch64/lagoon_cpp.h diff --git a/src/dynarmic/src/dynarmic/CMakeLists.txt b/src/dynarmic/src/dynarmic/CMakeLists.txt index 2274943613..37c24109c7 100644 --- a/src/dynarmic/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/src/dynarmic/CMakeLists.txt @@ -299,10 +299,18 @@ if ("loongarch64" IN_LIST ARCHITECTURE) target_link_libraries(dynarmic PRIVATE lagoon::lagoon) target_sources(dynarmic PRIVATE - backend/loongarch64/exclusive_monitor.cpp + backend/loongarch64/a32_jitstate.cpp + backend/loongarch64/a32_jitstate.h + backend/loongarch64/code_block.h + backend/loongarch64/emit_loongarch64.cpp + backend/loongarch64/emit_loongarch64.h + backend/loongarch64/a32_address_space.cpp + backend/loongarch64/a32_address_space.h backend/loongarch64/a32_interface.cpp backend/loongarch64/a64_interface.cpp + backend/loongarch64/exclusive_monitor.cpp backend/loongarch64/code_block.h + backend/loongarch64/lagoon_cpp.h common/spin_lock_loongarch64.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 new file mode 100644 index 0000000000..45b0a17727 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_address_space.cpp @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dynarmic/backend/loongarch64/a32_address_space.h" + +#include "common/assert.h" + +#include "dynarmic/backend/loongarch64/a32_jitstate.h" +#include "dynarmic/backend/loongarch64/emit_loongarch64.h" +#include "dynarmic/frontend/A32/a32_location_descriptor.h" +#include "dynarmic/frontend/A32/translate/a32_translate.h" +#include "dynarmic/ir/opt_passes.h" + +namespace Dynarmic::Backend::LoongArch64 { + +A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf) + : conf(conf) + , cb(conf.code_cache_size) { + EmitPrelude(); +} + +void A32AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const { + A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions}); + Optimization::Optimize(ir_block, conf, {.sha256 = true}); +} + +CodePtr A32AddressSpace::Get(IR::LocationDescriptor descriptor) { + if (const auto iter = block_entries.find(descriptor.Value()); iter != block_entries.end()) { + return iter->second; + } + return nullptr; +} + +CodePtr A32AddressSpace::GetOrEmit(IR::LocationDescriptor descriptor) { + if (CodePtr block_entry = Get(descriptor)) { + return block_entry; + } + + IR::Block ir_block{descriptor}; + GenerateIR(ir_block, descriptor); + const EmittedBlockInfo block_info = Emit(std::move(ir_block)); + + block_infos.insert_or_assign(descriptor.Value(), block_info); + block_entries.insert_or_assign(descriptor.Value(), block_info.entry_point); + return block_info.entry_point; +} + +void A32AddressSpace::ClearCache() { + block_entries.clear(); + block_infos.clear(); + SetCursorPtr(prelude_info.end_of_prelude); +} + +void A32AddressSpace::EmitPrelude() { + prelude_info.run_code = GetCursorPtr(); + + // Save all GPRs except sp (r3) and tp (r2) + la_addi_d(&cb.as, LA_SP, LA_SP, -64 * 8); + for (u32 i = 1; i < 32; i++) { + if (i == LA_SP || i == LA_TP) + continue; + 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); + + prelude_info.return_from_run_code = GetCursorPtr(); + + // Restore all GPRs except sp and tp + for (u32 i = 1; i < 32; i++) { + if (i == LA_SP || i == LA_TP) + continue; + la_ld_d(&cb.as, static_cast(i), LA_SP, static_cast(i * 8)); + } + la_addi_d(&cb.as, LA_SP, LA_SP, 64 * 8); + la_ret(&cb.as); + + prelude_info.end_of_prelude = GetCursorPtr(); +} + +void A32AddressSpace::SetCursorPtr(CodePtr ptr) { + cb.as.cursor = reinterpret_cast(ptr); +} + +size_t A32AddressSpace::GetRemainingSize() { + return la_get_remaining_buffer_size(&cb.as); +} + +EmittedBlockInfo A32AddressSpace::Emit(IR::Block block) { + if (GetRemainingSize() < 1024 * 1024) { + ClearCache(); + } + + EmittedBlockInfo block_info = EmitLoongArch64(cb.as, std::move(block)); + Link(block_info); + + return block_info; +} + +void A32AddressSpace::Link(EmittedBlockInfo& block_info) { + for (const auto& reloc : block_info.relocations) { + uint8_t* patch_location = reinterpret_cast(block_info.entry_point) + reloc.code_offset; + + switch (reloc.target) { + case LinkTarget::ReturnFromRunCode: { + std::ptrdiff_t off = reinterpret_cast(prelude_info.return_from_run_code) - patch_location; + lagoon_assembler_t patch_as; + la_init_assembler(&patch_as, patch_location, 4); + la_b(&patch_as, static_cast(off)); + break; + } + default: + ASSERT(false && "Invalid relocation target"); + } + } +} + +} // namespace Dynarmic::Backend::LoongArch64 diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/a32_address_space.h b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_address_space.h new file mode 100644 index 0000000000..55c4d8c5f3 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_address_space.h @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "dynarmic/backend/loongarch64/lagoon_cpp.h" +#include + +#include "dynarmic/backend/loongarch64/code_block.h" +#include "dynarmic/backend/loongarch64/emit_loongarch64.h" +#include "dynarmic/interface/A32/config.h" +#include "dynarmic/interface/halt_reason.h" +#include "dynarmic/ir/basic_block.h" +#include "dynarmic/ir/location_descriptor.h" + +namespace Dynarmic::Backend::LoongArch64 { + +struct A32JitState; + +class A32AddressSpace final { +public: + explicit A32AddressSpace(const A32::UserConfig& conf); + + void GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const; + CodePtr Get(IR::LocationDescriptor descriptor); + CodePtr GetOrEmit(IR::LocationDescriptor descriptor); + + void ClearCache(); + +private: + void EmitPrelude(); + + template + T GetCursorPtr() { + return reinterpret_cast(cb.as.cursor); + } + + template + T GetCursorPtr() const { + return reinterpret_cast(cb.as.cursor); + } + + template + T GetMemPtr() const { + return cb.ptr(); + } + + void SetCursorPtr(CodePtr ptr); + size_t GetRemainingSize(); + EmittedBlockInfo Emit(IR::Block block); + void Link(EmittedBlockInfo& block_info); + + const A32::UserConfig conf; + CodeBlock cb; + + ankerl::unordered_dense::map block_entries; + ankerl::unordered_dense::map block_infos; + +public: + struct PreludeInfo { + CodePtr end_of_prelude; + using RunCodeFuncType = HaltReason (*)(CodePtr entry_point, A32JitState* context, volatile u32* halt_reason); + RunCodeFuncType run_code; + CodePtr return_from_run_code; + } prelude_info; +}; + +} // namespace Dynarmic::Backend::LoongArch64 diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/a32_interface.cpp b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_interface.cpp index d1166d79b6..93ad34017a 100644 --- a/src/dynarmic/src/dynarmic/backend/loongarch64/a32_interface.cpp +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_interface.cpp @@ -1,101 +1,134 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -#include #include -#include -#include +#include +#include #include "common/assert.h" #include "common/common_types.h" + +#include "dynarmic/backend/loongarch64/a32_address_space.h" +#include "dynarmic/backend/loongarch64/a32_jitstate.h" +#include "dynarmic/common/atomic.h" +#include "dynarmic/frontend/A32/a32_location_descriptor.h" #include "dynarmic/interface/A32/a32.h" namespace Dynarmic::A32 { +using namespace Backend::LoongArch64; + struct Jit::Impl final { - explicit Impl(UserConfig conf_) : conf(std::move(conf_)) {} + Impl(Jit* jit_interface, A32::UserConfig conf) + : jit_interface(jit_interface) + , conf(conf) + , current_address_space(conf) {} HaltReason Run() { - UNIMPLEMENTED(); - return halt_reason; + ASSERT(!jit_interface->is_executing); + jit_interface->is_executing = true; + + const auto location_descriptor = current_state.GetLocationDescriptor(); + const auto entry_point = current_address_space.GetOrEmit(location_descriptor); + current_address_space.prelude_info.run_code(entry_point, ¤t_state, &halt_reason); + + HaltReason hr = static_cast(Atomic::Exchange(&halt_reason, 0)); + jit_interface->is_executing = false; + return hr; } HaltReason Step() { - UNIMPLEMENTED(); - return halt_reason | HaltReason::Step; + ASSERT(!jit_interface->is_executing); + jit_interface->is_executing = true; + + const auto location_descriptor = A32::LocationDescriptor{current_state.GetLocationDescriptor()}.SetSingleStepping(true); + const auto entry_point = current_address_space.GetOrEmit(location_descriptor); + current_address_space.prelude_info.run_code(entry_point, ¤t_state, &halt_reason); + + HaltReason hr = static_cast(Atomic::Exchange(&halt_reason, 0)); + jit_interface->is_executing = false; + return hr; } void ClearCache() { + std::unique_lock lock{invalidation_mutex}; + invalidate_entire_cache = true; HaltExecution(HaltReason::CacheInvalidation); } - void InvalidateCacheRange(u32, std::size_t) { + void InvalidateCacheRange(u32 start_address, size_t length) { + std::unique_lock lock{invalidation_mutex}; + invalid_cache_ranges.add(boost::icl::discrete_interval::closed(start_address, static_cast(start_address + length - 1))); HaltExecution(HaltReason::CacheInvalidation); } void Reset() { - regs = {}; - ext_regs = {}; - cpsr = 0; - fpscr = 0; - halt_reason = {}; + current_state = {}; } void HaltExecution(HaltReason hr) { - halt_reason |= hr; + Atomic::Or(&halt_reason, static_cast(hr)); } void ClearHalt(HaltReason hr) { - halt_reason &= ~hr; + Atomic::And(&halt_reason, ~static_cast(hr)); } std::array& Regs() { - return regs; + return current_state.regs; } const std::array& Regs() const { - return regs; + return current_state.regs; } std::array& ExtRegs() { - return ext_regs; + return current_state.ext_regs; } const std::array& ExtRegs() const { - return ext_regs; + return current_state.ext_regs; } u32 Cpsr() const { - return cpsr; + return current_state.Cpsr(); } void SetCpsr(u32 value) { - cpsr = value; + current_state.SetCpsr(value); } u32 Fpscr() const { - return fpscr; + return current_state.Fpscr(); } void SetFpscr(u32 value) { - fpscr = value; + current_state.SetFpscr(value); } - void ClearExclusiveState() {} + void ClearExclusiveState() { + current_state.exclusive_state = false; + } std::string Disassemble() const { return {}; } - UserConfig conf; - std::array regs{}; - std::array ext_regs{}; - u32 cpsr = 0; - u32 fpscr = 0; - HaltReason halt_reason{}; +private: + Jit* jit_interface; + A32::UserConfig conf; + A32JitState current_state{}; + A32AddressSpace current_address_space; + + volatile u32 halt_reason = 0; + + std::mutex invalidation_mutex; + boost::icl::interval_set invalid_cache_ranges; + bool invalidate_entire_cache = false; }; -Jit::Jit(UserConfig conf) : impl(std::make_unique(std::move(conf))) {} +Jit::Jit(UserConfig conf) + : impl(std::make_unique(this, conf)) {} Jit::~Jit() = default; @@ -111,7 +144,7 @@ void Jit::ClearCache() { impl->ClearCache(); } -void Jit::InvalidateCacheRange(u32 start_address, std::size_t length) { +void Jit::InvalidateCacheRange(u32 start_address, size_t length) { impl->InvalidateCacheRange(start_address, length); } diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/a32_jitstate.cpp b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_jitstate.cpp new file mode 100644 index 0000000000..d895d840e5 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_jitstate.cpp @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dynarmic/backend/loongarch64/a32_jitstate.h" + +#include "dynarmic/mcl/bit.hpp" +#include "common/common_types.h" + +namespace Dynarmic::Backend::LoongArch64 { + +u32 A32JitState::Cpsr() const { + u32 cpsr = 0; + cpsr |= cpsr_nzcv; + cpsr |= cpsr_q; + cpsr |= mcl::bit::get_bit<31>(cpsr_ge) ? 1 << 19 : 0; + cpsr |= mcl::bit::get_bit<23>(cpsr_ge) ? 1 << 18 : 0; + cpsr |= mcl::bit::get_bit<15>(cpsr_ge) ? 1 << 17 : 0; + cpsr |= mcl::bit::get_bit<7>(cpsr_ge) ? 1 << 16 : 0; + cpsr |= mcl::bit::get_bit<1>(upper_location_descriptor) ? 1 << 9 : 0; + cpsr |= mcl::bit::get_bit<0>(upper_location_descriptor) ? 1 << 5 : 0; + cpsr |= static_cast(upper_location_descriptor & 0b11111100'00000000); + cpsr |= static_cast(upper_location_descriptor & 0b00000011'00000000) << 17; + cpsr |= cpsr_jaifm; + return cpsr; +} + +void A32JitState::SetCpsr(u32 cpsr) { + cpsr_nzcv = cpsr & 0xF0000000; + cpsr_q = cpsr & (1 << 27); + cpsr_ge = 0; + cpsr_ge |= mcl::bit::get_bit<19>(cpsr) ? 0xFF000000 : 0; + cpsr_ge |= mcl::bit::get_bit<18>(cpsr) ? 0x00FF0000 : 0; + cpsr_ge |= mcl::bit::get_bit<17>(cpsr) ? 0x0000FF00 : 0; + cpsr_ge |= mcl::bit::get_bit<16>(cpsr) ? 0x000000FF : 0; + + upper_location_descriptor &= 0xFFFF0000; + upper_location_descriptor |= mcl::bit::get_bit<9>(cpsr) ? 2 : 0; + upper_location_descriptor |= mcl::bit::get_bit<5>(cpsr) ? 1 : 0; + upper_location_descriptor |= (cpsr >> 0) & 0b11111100'00000000; + upper_location_descriptor |= (cpsr >> 17) & 0b00000011'00000000; + cpsr_jaifm = cpsr & 0x010001DF; +} + +constexpr u32 FPCR_MASK = A32::LocationDescriptor::FPSCR_MODE_MASK; +constexpr u32 FPSR_MASK = 0x0800009F; + +u32 A32JitState::Fpscr() const { + return (upper_location_descriptor & FPCR_MASK) | fpsr | fpsr_nzcv; +} + +void A32JitState::SetFpscr(u32 fpscr) { + fpsr = fpscr & FPSR_MASK; + fpsr_nzcv = fpscr & 0xF0000000; + upper_location_descriptor = (upper_location_descriptor & 0x0000ffff) | (fpscr & FPCR_MASK); +} + +} // namespace Dynarmic::Backend::LoongArch64 diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/a32_jitstate.h b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_jitstate.h new file mode 100644 index 0000000000..045b31f6f6 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_jitstate.h @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include "common/common_types.h" + +#include "dynarmic/frontend/A32/a32_location_descriptor.h" +#include "dynarmic/ir/location_descriptor.h" + +namespace Dynarmic::Backend::LoongArch64 { + +struct A32JitState { + u32 cpsr_nzcv = 0; + u32 cpsr_q = 0; + u32 cpsr_jaifm = 0; + u32 cpsr_ge = 0; + + u32 fpsr = 0; + u32 fpsr_nzcv = 0; + + std::array regs{}; + + u32 upper_location_descriptor; + + alignas(16) std::array ext_regs{}; + + u32 exclusive_state = 0; + + u32 Cpsr() const; + void SetCpsr(u32 cpsr); + + u32 Fpscr() const; + void SetFpscr(u32 fpscr); + + IR::LocationDescriptor GetLocationDescriptor() const { + return IR::LocationDescriptor{regs[15] | (static_cast(upper_location_descriptor) << 32)}; + } +}; + +} // namespace Dynarmic::Backend::LoongArch64 diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/code_block.h b/src/dynarmic/src/dynarmic/backend/loongarch64/code_block.h index a4011719d1..bedf8a6db4 100644 --- a/src/dynarmic/src/dynarmic/backend/loongarch64/code_block.h +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/code_block.h @@ -4,20 +4,44 @@ #pragma once #include +#include +#include +#include +#include "dynarmic/backend/loongarch64/lagoon_cpp.h" + +#include "common/assert.h" #include "common/common_types.h" namespace Dynarmic::Backend::LoongArch64 { class CodeBlock { public: + explicit CodeBlock(std::size_t size) noexcept + : memsize(size) { + mem = static_cast(mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0)); + ASSERT(mem != nullptr); + la_init_assembler(&as, mem, size); + } + + ~CodeBlock() noexcept { + if (mem == nullptr) { + return; + } + munmap(mem, memsize); + } + template T ptr() const noexcept { + static_assert(std::is_pointer_v || std::is_same_v || std::is_same_v); return reinterpret_cast(mem); } + lagoon_assembler_t as{}; + private: u8* mem = nullptr; + size_t memsize = 0; }; } // namespace Dynarmic::Backend::LoongArch64 diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.cpp b/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.cpp new file mode 100644 index 0000000000..ca7a47c33d --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.cpp @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dynarmic/backend/loongarch64/emit_loongarch64.h" + +#include "dynarmic/backend/loongarch64/a32_jitstate.h" +#include "dynarmic/ir/basic_block.h" + +namespace Dynarmic::Backend::LoongArch64 { + +EmittedBlockInfo EmitLoongArch64(lagoon_assembler_t& as, [[maybe_unused]] IR::Block block) { + EmittedBlockInfo ebi; + ebi.entry_point = reinterpret_cast(as.cursor); + + // Dummy code: set regs[0] = 8, regs[1] = 2, regs[15] = 2 + la_addi_d(&as, LA_A0, LA_ZERO, 8); + la_st_w(&as, LA_A0, LA_A1, static_cast(offsetof(A32JitState, regs) + 0 * sizeof(u32))); + + la_addi_d(&as, LA_A0, LA_ZERO, 2); + la_st_w(&as, LA_A0, LA_A1, static_cast(offsetof(A32JitState, regs) + 1 * sizeof(u32))); + la_st_w(&as, LA_A0, LA_A1, static_cast(offsetof(A32JitState, regs) + 15 * sizeof(u32))); + + ebi.relocations.push_back(Relocation{ + reinterpret_cast(as.cursor) - ebi.entry_point, + LinkTarget::ReturnFromRunCode + }); + la_nop(&as); + + ebi.size = reinterpret_cast(as.cursor) - ebi.entry_point; + return ebi; +} + +} // namespace Dynarmic::Backend::LoongArch64 diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.h b/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.h new file mode 100644 index 0000000000..6a4398eee2 --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/emit_loongarch64.h @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include + +#include "dynarmic/backend/loongarch64/lagoon_cpp.h" + +#include "common/common_types.h" + +namespace Dynarmic::IR { +class Block; +class LocationDescriptor; +} // namespace Dynarmic::IR + +namespace Dynarmic::Backend::LoongArch64 { + +using CodePtr = std::byte*; + +enum class LinkTarget { + ReturnFromRunCode, +}; + +struct Relocation { + std::ptrdiff_t code_offset; + LinkTarget target; +}; + +struct EmittedBlockInfo { + CodePtr entry_point; + size_t size; + size_t cycle_count; + std::vector relocations; +}; + +EmittedBlockInfo EmitLoongArch64(lagoon_assembler_t& as, IR::Block block); + +} // namespace Dynarmic::Backend::LoongArch64 diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/lagoon_cpp.h b/src/dynarmic/src/dynarmic/backend/loongarch64/lagoon_cpp.h new file mode 100644 index 0000000000..da0edcff1c --- /dev/null +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/lagoon_cpp.h @@ -0,0 +1,8 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +extern "C" { +#include +} diff --git a/src/dynarmic/src/dynarmic/common/atomic.h b/src/dynarmic/src/dynarmic/common/atomic.h index 5eb4288517..8af6626be9 100644 --- a/src/dynarmic/src/dynarmic/common/atomic.h +++ b/src/dynarmic/src/dynarmic/common/atomic.h @@ -36,6 +36,14 @@ inline void And(volatile u32* ptr, u32 value) { #endif } +inline u32 Exchange(volatile u32* ptr, u32 value) { +#ifdef _MSC_VER + return static_cast(_InterlockedExchange(reinterpret_cast(ptr), value)); +#else + return __atomic_exchange_n(ptr, value, __ATOMIC_SEQ_CST); +#endif +} + inline void Barrier() { #ifdef _MSC_VER _ReadWriteBarrier();