aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/dynarmic/CMakeLists.txt4
-rw-r--r--src/dynarmic/src/dynarmic/CMakeLists.txt14
-rw-r--r--src/dynarmic/src/dynarmic/backend/exception_handler.h10
-rw-r--r--src/dynarmic/src/dynarmic/backend/exception_handler_generic.cpp6
-rw-r--r--src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp33
-rw-r--r--src/dynarmic/src/dynarmic/backend/loongarch64/a32_interface.cpp170
-rw-r--r--src/dynarmic/src/dynarmic/backend/loongarch64/a64_interface.cpp268
-rw-r--r--src/dynarmic/src/dynarmic/backend/loongarch64/code_block.h23
-rw-r--r--src/dynarmic/src/dynarmic/backend/loongarch64/exclusive_monitor.cpp54
-rw-r--r--src/dynarmic/src/dynarmic/common/spin_lock_loongarch64.cpp14
-rw-r--r--src/dynarmic/src/dynarmic/frontend/decoder/matcher.h5
13 files changed, 596 insertions, 9 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 86aa23c627..a6d526c5eb 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -8,7 +8,7 @@
include_directories(.)
# Dynarmic
-if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64) AND NOT YUZU_STATIC_ROOM)
+if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64) AND NOT YUZU_STATIC_ROOM)
add_subdirectory(dynarmic)
add_library(dynarmic::dynarmic ALIAS dynarmic)
endif()
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 39aebd5f48..2a42090ddc 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -1246,7 +1246,7 @@ if (HAS_NCE)
target_link_libraries(core PRIVATE merry::oaknut)
endif()
-if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64)
+if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64)
target_sources(core PRIVATE
arm/dynarmic/arm_dynarmic.h
arm/dynarmic/arm_dynarmic_64.cpp
diff --git a/src/dynarmic/CMakeLists.txt b/src/dynarmic/CMakeLists.txt
index 4c4bf86d3e..46b0b618e8 100644
--- a/src/dynarmic/CMakeLists.txt
+++ b/src/dynarmic/CMakeLists.txt
@@ -130,6 +130,10 @@ if ("riscv64" IN_LIST ARCHITECTURE)
find_package(biscuit 0.9.1 REQUIRED)
endif()
+if ("loongarch64" IN_LIST ARCHITECTURE)
+ find_package(lagoon REQUIRED)
+endif()
+
if ("x86_64" IN_LIST ARCHITECTURE)
find_package(xbyak 7 CONFIG)
endif()
diff --git a/src/dynarmic/src/dynarmic/CMakeLists.txt b/src/dynarmic/src/dynarmic/CMakeLists.txt
index c51a660c03..2274943613 100644
--- a/src/dynarmic/src/dynarmic/CMakeLists.txt
+++ b/src/dynarmic/src/dynarmic/CMakeLists.txt
@@ -295,6 +295,20 @@ if ("riscv64" IN_LIST ARCHITECTURE)
message(WARNING "TODO: Incomplete frontend for this host architecture")
endif()
+if ("loongarch64" IN_LIST ARCHITECTURE)
+ target_link_libraries(dynarmic PRIVATE lagoon::lagoon)
+
+ target_sources(dynarmic PRIVATE
+ backend/loongarch64/exclusive_monitor.cpp
+ backend/loongarch64/a32_interface.cpp
+ backend/loongarch64/a64_interface.cpp
+ backend/loongarch64/code_block.h
+
+ common/spin_lock_loongarch64.cpp
+ )
+ message(WARNING "TODO: Incomplete frontend for this host architecture")
+endif()
+
if (WIN32)
target_sources(dynarmic PRIVATE backend/exception_handler_windows.cpp)
elseif (APPLE)
diff --git a/src/dynarmic/src/dynarmic/backend/exception_handler.h b/src/dynarmic/src/dynarmic/backend/exception_handler.h
index b62bd7ab71..ce6abef5ce 100644
--- a/src/dynarmic/src/dynarmic/backend/exception_handler.h
+++ b/src/dynarmic/src/dynarmic/backend/exception_handler.h
@@ -26,6 +26,10 @@ class CodeBlock;
namespace Dynarmic::Backend::RV64 {
class CodeBlock;
} // namespace Dynarmic::Backend::RV64
+#elif defined(ARCHITECTURE_loongarch64)
+namespace Dynarmic::Backend::LoongArch64 {
+class CodeBlock;
+} // namespace Dynarmic::Backend::LoongArch64
#else
# error "Invalid architecture"
#endif
@@ -45,6 +49,10 @@ struct FakeCall {
struct FakeCall {
u64 call_sepc;
};
+#elif defined(ARCHITECTURE_loongarch64)
+struct FakeCall {
+ u64 call_pc;
+};
#else
# error "Invalid architecture"
#endif
@@ -60,6 +68,8 @@ public:
void Register(oaknut::CodeBlock& mem, std::size_t mem_size);
#elif defined(ARCHITECTURE_riscv64)
void Register(RV64::CodeBlock& mem, std::size_t mem_size);
+#elif defined(ARCHITECTURE_loongarch64)
+ void Register(LoongArch64::CodeBlock& mem, std::size_t mem_size);
#else
# error "Invalid architecture"
#endif
diff --git a/src/dynarmic/src/dynarmic/backend/exception_handler_generic.cpp b/src/dynarmic/src/dynarmic/backend/exception_handler_generic.cpp
index 23dc294511..f19fe98a6d 100644
--- a/src/dynarmic/src/dynarmic/backend/exception_handler_generic.cpp
+++ b/src/dynarmic/src/dynarmic/backend/exception_handler_generic.cpp
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
@@ -28,6 +28,10 @@ void ExceptionHandler::Register(oaknut::CodeBlock&, std::size_t) {
void ExceptionHandler::Register(RV64::CodeBlock&, std::size_t) {
// Do nothing
}
+#elif defined(ARCHITECTURE_loongarch64)
+void ExceptionHandler::Register(LoongArch64::CodeBlock&, std::size_t) {
+ // Do nothing
+}
#else
# error "Invalid architecture"
#endif
diff --git a/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp b/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp
index 224559133a..c586cf2fb1 100644
--- a/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp
+++ b/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp
@@ -6,20 +6,25 @@
* SPDX-License-Identifier: 0BSD
*/
+#include <signal.h>
+
+#include <algorithm>
+#include <bit>
#include <cstring>
#include <functional>
-#include <algorithm>
#include <memory>
#include <mutex>
-#include <shared_mutex>
#include <optional>
-#include <bit>
-#include <fmt/format.h>
+#include <shared_mutex>
+
#include <ankerl/unordered_dense.h>
-#include "dynarmic/backend/exception_handler.h"
+#include <fmt/format.h>
+#include <sys/mman.h>
+
#include "common/assert.h"
-#include "dynarmic/common/context.h"
#include "common/common_types.h"
+#include "dynarmic/backend/exception_handler.h"
+#include "dynarmic/common/context.h"
#if defined(ARCHITECTURE_x86_64)
# include "dynarmic/backend/x64/block_of_code.h"
#elif defined(ARCHITECTURE_arm64)
@@ -27,6 +32,8 @@
# include "dynarmic/backend/arm64/abi.h"
#elif defined(ARCHITECTURE_riscv64)
# include "dynarmic/backend/riscv64/code_block.h"
+#elif defined(ARCHITECTURE_loongarch64)
+# include "dynarmic/backend/loongarch64/code_block.h"
#else
# error "Invalid architecture"
#endif
@@ -150,6 +157,16 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
}
}
fmt::print(stderr, "Unhandled {} at pc {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_SEPC);
+#elif defined(ARCHITECTURE_loongarch64)
+ {
+ std::shared_lock guard(sig_handler->code_block_infos_mutex);
+ if (const auto iter = sig_handler->FindCodeBlockInfo(CTX_PC); iter != sig_handler->code_block_infos.end()) {
+ FakeCall fc = iter->second.cb(CTX_PC);
+ CTX_PC = fc.call_pc;
+ return;
+ }
+ }
+ fmt::print(stderr, "Unhandled {} at pc {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
#else
# error "Invalid architecture"
#endif
@@ -209,6 +226,10 @@ void ExceptionHandler::Register(oaknut::CodeBlock& mem, std::size_t size) {
void ExceptionHandler::Register(RV64::CodeBlock& mem, std::size_t size) {
impl = std::make_unique<Impl>(std::bit_cast<u64>(mem.ptr<u64>()), size);
}
+#elif defined(ARCHITECTURE_loongarch64)
+void ExceptionHandler::Register(LoongArch64::CodeBlock& mem, std::size_t size) {
+ impl = std::make_unique<Impl>(std::bit_cast<u64>(mem.ptr<u64>()), size);
+}
#else
# error "Invalid architecture"
#endif
diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/a32_interface.cpp b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_interface.cpp
new file mode 100644
index 0000000000..d1166d79b6
--- /dev/null
+++ b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_interface.cpp
@@ -0,0 +1,170 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <array>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "dynarmic/interface/A32/a32.h"
+
+namespace Dynarmic::A32 {
+
+struct Jit::Impl final {
+ explicit Impl(UserConfig conf_) : conf(std::move(conf_)) {}
+
+ HaltReason Run() {
+ UNIMPLEMENTED();
+ return halt_reason;
+ }
+
+ HaltReason Step() {
+ UNIMPLEMENTED();
+ return halt_reason | HaltReason::Step;
+ }
+
+ void ClearCache() {
+ HaltExecution(HaltReason::CacheInvalidation);
+ }
+
+ void InvalidateCacheRange(u32, std::size_t) {
+ HaltExecution(HaltReason::CacheInvalidation);
+ }
+
+ void Reset() {
+ regs = {};
+ ext_regs = {};
+ cpsr = 0;
+ fpscr = 0;
+ halt_reason = {};
+ }
+
+ void HaltExecution(HaltReason hr) {
+ halt_reason |= hr;
+ }
+
+ void ClearHalt(HaltReason hr) {
+ halt_reason &= ~hr;
+ }
+
+ std::array<u32, 16>& Regs() {
+ return regs;
+ }
+
+ const std::array<u32, 16>& Regs() const {
+ return regs;
+ }
+
+ std::array<u32, 64>& ExtRegs() {
+ return ext_regs;
+ }
+
+ const std::array<u32, 64>& ExtRegs() const {
+ return ext_regs;
+ }
+
+ u32 Cpsr() const {
+ return cpsr;
+ }
+
+ void SetCpsr(u32 value) {
+ cpsr = value;
+ }
+
+ u32 Fpscr() const {
+ return fpscr;
+ }
+
+ void SetFpscr(u32 value) {
+ fpscr = value;
+ }
+
+ void ClearExclusiveState() {}
+
+ std::string Disassemble() const {
+ return {};
+ }
+
+ UserConfig conf;
+ std::array<u32, 16> regs{};
+ std::array<u32, 64> ext_regs{};
+ u32 cpsr = 0;
+ u32 fpscr = 0;
+ HaltReason halt_reason{};
+};
+
+Jit::Jit(UserConfig conf) : impl(std::make_unique<Impl>(std::move(conf))) {}
+
+Jit::~Jit() = default;
+
+HaltReason Jit::Run() {
+ return impl->Run();
+}
+
+HaltReason Jit::Step() {
+ return impl->Step();
+}
+
+void Jit::ClearCache() {
+ impl->ClearCache();
+}
+
+void Jit::InvalidateCacheRange(u32 start_address, std::size_t length) {
+ impl->InvalidateCacheRange(start_address, length);
+}
+
+void Jit::Reset() {
+ impl->Reset();
+}
+
+void Jit::HaltExecution(HaltReason hr) {
+ impl->HaltExecution(hr);
+}
+
+void Jit::ClearHalt(HaltReason hr) {
+ impl->ClearHalt(hr);
+}
+
+std::array<u32, 16>& Jit::Regs() {
+ return impl->Regs();
+}
+
+const std::array<u32, 16>& Jit::Regs() const {
+ return impl->Regs();
+}
+
+std::array<u32, 64>& Jit::ExtRegs() {
+ return impl->ExtRegs();
+}
+
+const std::array<u32, 64>& Jit::ExtRegs() const {
+ return impl->ExtRegs();
+}
+
+u32 Jit::Cpsr() const {
+ return impl->Cpsr();
+}
+
+void Jit::SetCpsr(u32 value) {
+ impl->SetCpsr(value);
+}
+
+u32 Jit::Fpscr() const {
+ return impl->Fpscr();
+}
+
+void Jit::SetFpscr(u32 value) {
+ impl->SetFpscr(value);
+}
+
+void Jit::ClearExclusiveState() {
+ impl->ClearExclusiveState();
+}
+
+std::string Jit::Disassemble() const {
+ return impl->Disassemble();
+}
+
+} // namespace Dynarmic::A32
diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/a64_interface.cpp b/src/dynarmic/src/dynarmic/backend/loongarch64/a64_interface.cpp
new file mode 100644
index 0000000000..0af55797f9
--- /dev/null
+++ b/src/dynarmic/src/dynarmic/backend/loongarch64/a64_interface.cpp
@@ -0,0 +1,268 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <array>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "dynarmic/interface/A64/a64.h"
+
+namespace Dynarmic::A64 {
+
+struct Jit::Impl final {
+ explicit Impl(UserConfig conf_) : conf(std::move(conf_)) {}
+
+ HaltReason Run() {
+ UNIMPLEMENTED();
+ return halt_reason;
+ }
+
+ HaltReason Step() {
+ UNIMPLEMENTED();
+ return halt_reason | HaltReason::Step;
+ }
+
+ void ClearCache() {
+ HaltExecution(HaltReason::CacheInvalidation);
+ }
+
+ void InvalidateCacheRange(u64, std::size_t) {
+ HaltExecution(HaltReason::CacheInvalidation);
+ }
+
+ void Reset() {
+ regs = {};
+ vectors = {};
+ sp = 0;
+ pc = 0;
+ fpcr = 0;
+ fpsr = 0;
+ pstate = 0;
+ halt_reason = {};
+ }
+
+ void HaltExecution(HaltReason hr) {
+ halt_reason |= hr;
+ }
+
+ void ClearHalt(HaltReason hr) {
+ halt_reason &= ~hr;
+ }
+
+ u64 GetSP() const {
+ return sp;
+ }
+
+ void SetSP(u64 value) {
+ sp = value;
+ }
+
+ u64 GetPC() const {
+ return pc;
+ }
+
+ void SetPC(u64 value) {
+ pc = value;
+ }
+
+ u64 GetRegister(std::size_t index) const {
+ return index == 31 ? sp : regs.at(index);
+ }
+
+ void SetRegister(std::size_t index, u64 value) {
+ if (index == 31) {
+ sp = value;
+ return;
+ }
+ regs.at(index) = value;
+ }
+
+ std::array<u64, 31> GetRegisters() const {
+ return regs;
+ }
+
+ void SetRegisters(const std::array<u64, 31>& value) {
+ regs = value;
+ }
+
+ Vector GetVector(std::size_t index) const {
+ return vectors.at(index);
+ }
+
+ void SetVector(std::size_t index, Vector value) {
+ vectors.at(index) = value;
+ }
+
+ std::array<Vector, 32> GetVectors() const {
+ return vectors;
+ }
+
+ void SetVectors(const std::array<Vector, 32>& value) {
+ vectors = value;
+ }
+
+ u32 GetFpcr() const {
+ return fpcr;
+ }
+
+ void SetFpcr(u32 value) {
+ fpcr = value;
+ }
+
+ u32 GetFpsr() const {
+ return fpsr;
+ }
+
+ void SetFpsr(u32 value) {
+ fpsr = value;
+ }
+
+ u32 GetPstate() const {
+ return pstate;
+ }
+
+ void SetPstate(u32 value) {
+ pstate = value;
+ }
+
+ void ClearExclusiveState() {}
+
+ bool IsExecuting() const {
+ return false;
+ }
+
+ std::string Disassemble() const {
+ return {};
+ }
+
+ UserConfig conf;
+ std::array<u64, 31> regs{};
+ std::array<Vector, 32> vectors{};
+ u64 sp = 0;
+ u64 pc = 0;
+ u32 fpcr = 0;
+ u32 fpsr = 0;
+ u32 pstate = 0;
+ HaltReason halt_reason{};
+};
+
+Jit::Jit(UserConfig conf) : impl(std::make_unique<Impl>(std::move(conf))) {}
+
+Jit::~Jit() = default;
+
+HaltReason Jit::Run() {
+ return impl->Run();
+}
+
+HaltReason Jit::Step() {
+ return impl->Step();
+}
+
+void Jit::ClearCache() {
+ impl->ClearCache();
+}
+
+void Jit::InvalidateCacheRange(u64 start_address, std::size_t length) {
+ impl->InvalidateCacheRange(start_address, length);
+}
+
+void Jit::Reset() {
+ impl->Reset();
+}
+
+void Jit::HaltExecution(HaltReason hr) {
+ impl->HaltExecution(hr);
+}
+
+void Jit::ClearHalt(HaltReason hr) {
+ impl->ClearHalt(hr);
+}
+
+u64 Jit::GetSP() const {
+ return impl->GetSP();
+}
+
+void Jit::SetSP(u64 value) {
+ impl->SetSP(value);
+}
+
+u64 Jit::GetPC() const {
+ return impl->GetPC();
+}
+
+void Jit::SetPC(u64 value) {
+ impl->SetPC(value);
+}
+
+u64 Jit::GetRegister(std::size_t index) const {
+ return impl->GetRegister(index);
+}
+
+void Jit::SetRegister(std::size_t index, u64 value) {
+ impl->SetRegister(index, value);
+}
+
+std::array<u64, 31> Jit::GetRegisters() const {
+ return impl->GetRegisters();
+}
+
+void Jit::SetRegisters(const std::array<u64, 31>& value) {
+ impl->SetRegisters(value);
+}
+
+Vector Jit::GetVector(std::size_t index) const {
+ return impl->GetVector(index);
+}
+
+void Jit::SetVector(std::size_t index, Vector value) {
+ impl->SetVector(index, value);
+}
+
+std::array<Vector, 32> Jit::GetVectors() const {
+ return impl->GetVectors();
+}
+
+void Jit::SetVectors(const std::array<Vector, 32>& value) {
+ impl->SetVectors(value);
+}
+
+u32 Jit::GetFpcr() const {
+ return impl->GetFpcr();
+}
+
+void Jit::SetFpcr(u32 value) {
+ impl->SetFpcr(value);
+}
+
+u32 Jit::GetFpsr() const {
+ return impl->GetFpsr();
+}
+
+void Jit::SetFpsr(u32 value) {
+ impl->SetFpsr(value);
+}
+
+u32 Jit::GetPstate() const {
+ return impl->GetPstate();
+}
+
+void Jit::SetPstate(u32 value) {
+ impl->SetPstate(value);
+}
+
+void Jit::ClearExclusiveState() {
+ impl->ClearExclusiveState();
+}
+
+bool Jit::IsExecuting() const {
+ return impl->IsExecuting();
+}
+
+std::string Jit::Disassemble() const {
+ return impl->Disassemble();
+}
+
+} // namespace Dynarmic::A64
diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/code_block.h b/src/dynarmic/src/dynarmic/backend/loongarch64/code_block.h
new file mode 100644
index 0000000000..a4011719d1
--- /dev/null
+++ b/src/dynarmic/src/dynarmic/backend/loongarch64/code_block.h
@@ -0,0 +1,23 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <cstdint>
+
+#include "common/common_types.h"
+
+namespace Dynarmic::Backend::LoongArch64 {
+
+class CodeBlock {
+public:
+ template<typename T>
+ T ptr() const noexcept {
+ return reinterpret_cast<T>(mem);
+ }
+
+private:
+ u8* mem = nullptr;
+};
+
+} // namespace Dynarmic::Backend::LoongArch64
diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/exclusive_monitor.cpp b/src/dynarmic/src/dynarmic/backend/loongarch64/exclusive_monitor.cpp
new file mode 100644
index 0000000000..24aa4853bb
--- /dev/null
+++ b/src/dynarmic/src/dynarmic/backend/loongarch64/exclusive_monitor.cpp
@@ -0,0 +1,54 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "dynarmic/interface/exclusive_monitor.h"
+
+#include <algorithm>
+
+namespace Dynarmic {
+
+ExclusiveMonitor::ExclusiveMonitor(std::size_t processor_count)
+ : exclusive_addresses(processor_count, INVALID_EXCLUSIVE_ADDRESS), exclusive_values(processor_count) {}
+
+size_t ExclusiveMonitor::GetProcessorCount() const {
+ return exclusive_addresses.size();
+}
+
+void ExclusiveMonitor::Lock() {
+ lock.Lock();
+}
+
+void ExclusiveMonitor::Unlock() {
+ lock.Unlock();
+}
+
+bool ExclusiveMonitor::CheckAndClear(std::size_t processor_id, VAddr address) {
+ const VAddr masked_address = address & RESERVATION_GRANULE_MASK;
+
+ Lock();
+ if (exclusive_addresses[processor_id] != masked_address) {
+ Unlock();
+ return false;
+ }
+
+ for (VAddr& other_address : exclusive_addresses) {
+ if (other_address == masked_address) {
+ other_address = INVALID_EXCLUSIVE_ADDRESS;
+ }
+ }
+ return true;
+}
+
+void ExclusiveMonitor::Clear() {
+ Lock();
+ std::fill(exclusive_addresses.begin(), exclusive_addresses.end(), INVALID_EXCLUSIVE_ADDRESS);
+ Unlock();
+}
+
+void ExclusiveMonitor::ClearProcessor(std::size_t processor_id) {
+ Lock();
+ exclusive_addresses[processor_id] = INVALID_EXCLUSIVE_ADDRESS;
+ Unlock();
+}
+
+} // namespace Dynarmic
diff --git a/src/dynarmic/src/dynarmic/common/spin_lock_loongarch64.cpp b/src/dynarmic/src/dynarmic/common/spin_lock_loongarch64.cpp
new file mode 100644
index 0000000000..6efd05bc26
--- /dev/null
+++ b/src/dynarmic/src/dynarmic/common/spin_lock_loongarch64.cpp
@@ -0,0 +1,14 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "dynarmic/common/spin_lock.h"
+
+namespace Dynarmic {
+
+void SpinLock::Lock() noexcept {
+}
+
+void SpinLock::Unlock() noexcept {
+}
+
+} // namespace Dynarmic
diff --git a/src/dynarmic/src/dynarmic/frontend/decoder/matcher.h b/src/dynarmic/src/dynarmic/frontend/decoder/matcher.h
index 49095f67e3..77fb7d941f 100644
--- a/src/dynarmic/src/dynarmic/frontend/decoder/matcher.h
+++ b/src/dynarmic/src/dynarmic/frontend/decoder/matcher.h
@@ -9,6 +9,7 @@
#pragma once
#include <functional>
+#include <tuple>
#include "common/assert.h"
@@ -31,6 +32,10 @@ public:
, expected{expected}
{}
+ constexpr Matcher(std::tuple<T, T> t) noexcept
+ : Matcher(std::get<0>(t), std::get<1>(t))
+ {}
+
/// @brief Gets the mask for this instruction.
constexpr inline T GetMask() const noexcept {
return mask;