summaryrefslogtreecommitdiffstats
path: root/src/core/arm
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/arm')
-rw-r--r--src/core/arm/arm_interface.cpp12
-rw-r--r--src/core/arm/arm_interface.h29
-rw-r--r--src/core/arm/cpu_interrupt_handler.h4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp37
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h6
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp66
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.cpp6
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.h4
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp295
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h63
11 files changed, 106 insertions, 420 deletions
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index d2295ed90..0951e1976 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -147,10 +147,18 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContex
auto fp = ctx.cpu_registers[29];
auto lr = ctx.cpu_registers[30];
while (true) {
- out.push_back({"", 0, lr, 0});
- if (!fp) {
+ out.push_back({
+ .module = "",
+ .address = 0,
+ .original_address = lr,
+ .offset = 0,
+ .name = {},
+ });
+
+ if (fp == 0) {
break;
}
+
lr = memory.Read64(fp + 8) - 4;
fp = memory.Read64(fp);
}
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 1f24051e4..9a0151736 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -26,9 +26,10 @@ using CPUInterrupts = std::array<CPUInterruptHandler, Core::Hardware::NUM_CPU_CO
/// Generic ARMv8 CPU interface
class ARM_Interface : NonCopyable {
public:
- explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers, bool uses_wall_clock)
- : system{system_}, interrupt_handlers{interrupt_handlers}, uses_wall_clock{
- uses_wall_clock} {}
+ explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers_,
+ bool uses_wall_clock_)
+ : system{system_}, interrupt_handlers{interrupt_handlers_}, uses_wall_clock{
+ uses_wall_clock_} {}
virtual ~ARM_Interface() = default;
struct ThreadContext32 {
@@ -64,15 +65,25 @@ public:
/// Step CPU by one instruction
virtual void Step() = 0;
+ /// Exits execution from a callback, the callback must rewind the stack
+ virtual void ExceptionalExit() = 0;
+
/// Clear all instruction cache
virtual void ClearInstructionCache() = 0;
- /// Notifies CPU emulation that the current page table has changed.
- ///
- /// @param new_page_table The new page table.
- /// @param new_address_space_size_in_bits The new usable size of the address space in bits.
- /// This can be either 32, 36, or 39 on official software.
- ///
+ /**
+ * Clear instruction cache range
+ * @param addr Start address of the cache range to clear
+ * @param size Size of the cache range to clear, starting at addr
+ */
+ virtual void InvalidateCacheRange(VAddr addr, std::size_t size) = 0;
+
+ /**
+ * Notifies CPU emulation that the current page table has changed.
+ * @param new_page_table The new page table.
+ * @param new_address_space_size_in_bits The new usable size of the address space in bits.
+ * This can be either 32, 36, or 39 on official software.
+ */
virtual void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) = 0;
diff --git a/src/core/arm/cpu_interrupt_handler.h b/src/core/arm/cpu_interrupt_handler.h
index 71e582f79..c20c280f1 100644
--- a/src/core/arm/cpu_interrupt_handler.h
+++ b/src/core/arm/cpu_interrupt_handler.h
@@ -21,8 +21,8 @@ public:
CPUInterruptHandler(const CPUInterruptHandler&) = delete;
CPUInterruptHandler& operator=(const CPUInterruptHandler&) = delete;
- CPUInterruptHandler(CPUInterruptHandler&&) = default;
- CPUInterruptHandler& operator=(CPUInterruptHandler&&) = default;
+ CPUInterruptHandler(CPUInterruptHandler&&) = delete;
+ CPUInterruptHandler& operator=(CPUInterruptHandler&&) = delete;
bool IsInterrupted() const {
return is_interrupted;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index b5f28a86e..ec4407b6e 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -7,6 +7,7 @@
#include <dynarmic/A32/a32.h>
#include <dynarmic/A32/config.h>
#include <dynarmic/A32/context.h>
+#include "common/assert.h"
#include "common/logging/log.h"
#include "common/page_table.h"
#include "core/arm/cpu_interrupt_handler.h"
@@ -70,15 +71,9 @@ public:
}
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
- switch (exception) {
- case Dynarmic::A32::Exception::UndefinedInstruction:
- case Dynarmic::A32::Exception::UnpredictableInstruction:
- break;
- case Dynarmic::A32::Exception::Breakpoint:
- break;
- }
- LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
- static_cast<std::size_t>(exception), pc, MemoryReadCode(pc));
+ LOG_CRITICAL(Core_ARM,
+ "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})",
+ exception, pc, MemoryReadCode(pc), parent.IsInThumbMode());
UNIMPLEMENTED();
}
@@ -132,6 +127,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>(
page_table.pointers.data());
config.absolute_offset_page_table = true;
+ config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
config.only_detect_misalignment_via_page_table_on_page_boundary = true;
@@ -179,6 +175,9 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
}
+ if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
+ config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
+ }
}
return std::make_unique<Dynarmic::A32::Jit>(config);
@@ -188,6 +187,10 @@ void ARM_Dynarmic_32::Run() {
jit->Run();
}
+void ARM_Dynarmic_32::ExceptionalExit() {
+ jit->ExceptionalExit();
+}
+
void ARM_Dynarmic_32::Step() {
jit->Step();
}
@@ -253,6 +256,9 @@ void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) {
}
void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
+ if (!jit) {
+ return;
+ }
Dynarmic::A32::Context context;
jit->SaveContext(context);
ctx.cpu_registers = context.Regs();
@@ -262,6 +268,9 @@ void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
}
void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
+ if (!jit) {
+ return;
+ }
Dynarmic::A32::Context context;
context.Regs() = ctx.cpu_registers;
context.ExtRegs() = ctx.extension_registers;
@@ -281,7 +290,17 @@ void ARM_Dynarmic_32::ClearInstructionCache() {
jit->ClearCache();
}
+void ARM_Dynarmic_32::InvalidateCacheRange(VAddr addr, std::size_t size) {
+ if (!jit) {
+ return;
+ }
+ jit->InvalidateCacheRange(static_cast<u32>(addr), size);
+}
+
void ARM_Dynarmic_32::ClearExclusiveState() {
+ if (!jit) {
+ return;
+ }
jit->ClearExclusiveState();
}
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index 2bab31b92..f6c4d4db9 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -42,6 +42,7 @@ public:
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
void Run() override;
+ void ExceptionalExit() override;
void Step() override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
@@ -49,6 +50,10 @@ public:
u64 GetTPIDR_EL0() const override;
void ChangeProcessorID(std::size_t new_core_id) override;
+ bool IsInThumbMode() const {
+ return (GetPSTATE() & 0x20) != 0;
+ }
+
void SaveContext(ThreadContext32& ctx) override;
void SaveContext(ThreadContext64& ctx) override {}
void LoadContext(const ThreadContext32& ctx) override;
@@ -58,6 +63,7 @@ public:
void ClearExclusiveState() override;
void ClearInstructionCache() override;
+ void InvalidateCacheRange(VAddr addr, std::size_t size) override;
void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) override;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index ce9968724..ae5566ab8 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -6,6 +6,7 @@
#include <memory>
#include <dynarmic/A64/a64.h>
#include <dynarmic/A64/config.h>
+#include "common/assert.h"
#include "common/logging/log.h"
#include "common/page_table.h"
#include "core/arm/cpu_interrupt_handler.h"
@@ -13,11 +14,9 @@
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
#include "core/core.h"
#include "core/core_timing.h"
-#include "core/core_timing_util.h"
-#include "core/gdbstub/gdbstub.h"
#include "core/hardware_properties.h"
+#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
#include "core/settings.h"
@@ -82,16 +81,9 @@ public:
}
void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
- LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc,
- num_instructions, MemoryReadCode(pc));
-
- ARM_Interface::ThreadContext64 ctx;
- parent.SaveContext(ctx);
- parent.inner_unicorn.LoadContext(ctx);
- parent.inner_unicorn.ExecuteInstructions(num_instructions);
- parent.inner_unicorn.SaveContext(ctx);
- parent.LoadContext(ctx);
- num_interpreted_instructions += num_instructions;
+ LOG_ERROR(Core_ARM,
+ "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
+ num_instructions, MemoryReadCode(pc));
}
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
@@ -103,16 +95,6 @@ public:
case Dynarmic::A64::Exception::Yield:
return;
case Dynarmic::A64::Exception::Breakpoint:
- if (GDBStub::IsServerEnabled()) {
- parent.jit->HaltExecution();
- parent.SetPC(pc);
- Kernel::Thread* const thread = parent.system.CurrentScheduler().GetCurrentThread();
- parent.SaveContext(thread->GetContext64());
- GDBStub::Break();
- GDBStub::SendTrap(thread, 5);
- return;
- }
- [[fallthrough]];
default:
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
static_cast<std::size_t>(exception), pc, MemoryReadCode(pc));
@@ -127,18 +109,17 @@ public:
if (parent.uses_wall_clock) {
return;
}
+
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
// rough approximation of the amount of executed ticks in the system, it may be thrown off
// if not all cores are doing a similar amount of work. Instead of doing this, we should
// device a way so that timing is consistent across all cores without increasing the ticks 4
// times.
- u64 amortized_ticks =
- (ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES;
+ u64 amortized_ticks = ticks / Core::Hardware::NUM_CPU_CORES;
// Always execute at least one tick.
amortized_ticks = std::max<u64>(amortized_ticks, 1);
parent.system.CoreTiming().AddTicks(amortized_ticks);
- num_interpreted_instructions = 0;
}
u64 GetTicksRemaining() override {
@@ -156,7 +137,6 @@ public:
}
ARM_Dynarmic_64& parent;
- std::size_t num_interpreted_instructions = 0;
u64 tpidrro_el0 = 0;
u64 tpidr_el0 = 0;
static constexpr u64 minimum_run_cycles = 1000U;
@@ -172,6 +152,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
// Memory
config.page_table = reinterpret_cast<void**>(page_table.pointers.data());
config.page_table_address_space_bits = address_space_bits;
+ config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
config.silently_mirror_page_table = false;
config.absolute_offset_page_table = true;
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
@@ -231,6 +212,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
}
+ if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
+ config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
+ }
}
return std::make_shared<Dynarmic::A64::Jit>(config);
@@ -240,6 +224,10 @@ void ARM_Dynarmic_64::Run() {
jit->Run();
}
+void ARM_Dynarmic_64::ExceptionalExit() {
+ jit->ExceptionalExit();
+}
+
void ARM_Dynarmic_64::Step() {
cb->InterpreterFallback(jit->GetPC(), 1);
}
@@ -248,12 +236,8 @@ ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handle
bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor,
std::size_t core_index)
: ARM_Interface{system, interrupt_handlers, uses_wall_clock},
- cb(std::make_unique<DynarmicCallbacks64>(*this)), inner_unicorn{system, interrupt_handlers,
- uses_wall_clock,
- ARM_Unicorn::Arch::AArch64,
- core_index},
- core_index{core_index}, exclusive_monitor{
- dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
+ cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index},
+ exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
@@ -310,6 +294,9 @@ void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) {
}
void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
+ if (!jit) {
+ return;
+ }
ctx.cpu_registers = jit->GetRegisters();
ctx.sp = jit->GetSP();
ctx.pc = jit->GetPC();
@@ -321,6 +308,9 @@ void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
}
void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
+ if (!jit) {
+ return;
+ }
jit->SetRegisters(ctx.cpu_registers);
jit->SetSP(ctx.sp);
jit->SetPC(ctx.pc);
@@ -342,7 +332,17 @@ void ARM_Dynarmic_64::ClearInstructionCache() {
jit->ClearCache();
}
+void ARM_Dynarmic_64::InvalidateCacheRange(VAddr addr, std::size_t size) {
+ if (!jit) {
+ return;
+ }
+ jit->InvalidateCacheRange(addr, size);
+}
+
void ARM_Dynarmic_64::ClearExclusiveState() {
+ if (!jit) {
+ return;
+ }
jit->ClearExclusiveState();
}
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index 403c55961..329b59a32 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -12,7 +12,6 @@
#include "common/hash.h"
#include "core/arm/arm_interface.h"
#include "core/arm/exclusive_monitor.h"
-#include "core/arm/unicorn/arm_unicorn.h"
namespace Core::Memory {
class Memory;
@@ -41,6 +40,7 @@ public:
void SetPSTATE(u32 pstate) override;
void Run() override;
void Step() override;
+ void ExceptionalExit() override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
void SetTPIDR_EL0(u64 value) override;
@@ -56,6 +56,7 @@ public:
void ClearExclusiveState() override;
void ClearInstructionCache() override;
+ void InvalidateCacheRange(VAddr addr, std::size_t size) override;
void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) override;
@@ -71,7 +72,6 @@ private:
std::unique_ptr<DynarmicCallbacks64> cb;
JitCacheType jit_cache;
std::shared_ptr<Dynarmic::A64::Jit> jit;
- ARM_Unicorn inner_unicorn;
std::size_t core_index;
DynarmicExclusiveMonitor& exclusive_monitor;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
index 54556e0f9..caefc09f4 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
@@ -34,7 +34,7 @@ std::optional<Callback> DynarmicCP15::CompileInternalOperation(bool two, unsigne
CoprocReg CRm, unsigned opc2) {
LOG_CRITICAL(Core_ARM, "CP15: cdp{} p15, {}, {}, {}, {}, {}", two ? "2" : "", opc1, CRd, CRn,
CRm, opc2);
- return {};
+ return std::nullopt;
}
CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn,
@@ -115,7 +115,7 @@ std::optional<Callback> DynarmicCP15::CompileLoadWords(bool two, bool long_trans
LOG_CRITICAL(Core_ARM, "CP15: mrrc{}{} p15, {}, [...]", two ? "2" : "",
long_transfer ? "l" : "", CRd);
}
- return {};
+ return std::nullopt;
}
std::optional<Callback> DynarmicCP15::CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd,
@@ -127,7 +127,7 @@ std::optional<Callback> DynarmicCP15::CompileStoreWords(bool two, bool long_tran
LOG_CRITICAL(Core_ARM, "CP15: mrrc{}{} p15, {}, [...]", two ? "2" : "",
long_transfer ? "l" : "", CRd);
}
- return {};
+ return std::nullopt;
}
} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
index 7356d252e..dc6f4af3a 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
@@ -35,8 +35,8 @@ public:
std::optional<u8> option) override;
ARM_Dynarmic_32& parent;
- u32 uprw;
- u32 uro;
+ u32 uprw = 0;
+ u32 uro = 0;
};
} // namespace Core
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
deleted file mode 100644
index 1df3f3ed1..000000000
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <algorithm>
-#include <unicorn/arm64.h>
-#include "common/assert.h"
-#include "common/microprofile.h"
-#include "core/arm/cpu_interrupt_handler.h"
-#include "core/arm/unicorn/arm_unicorn.h"
-#include "core/core.h"
-#include "core/core_timing.h"
-#include "core/hle/kernel/scheduler.h"
-#include "core/hle/kernel/svc.h"
-#include "core/memory.h"
-
-namespace Core {
-
-// Load Unicorn DLL once on Windows using RAII
-#ifdef _MSC_VER
-#include <unicorn_dynload.h>
-struct LoadDll {
-private:
- LoadDll() {
- ASSERT(uc_dyn_load(NULL, 0));
- }
- ~LoadDll() {
- ASSERT(uc_dyn_free());
- }
- static LoadDll g_load_dll;
-};
-LoadDll LoadDll::g_load_dll;
-#endif
-
-#define CHECKED(expr) \
- do { \
- if (auto _cerr = (expr)) { \
- ASSERT_MSG(false, "Call " #expr " failed with error: {} ({})\n", _cerr, \
- uc_strerror(_cerr)); \
- } \
- } while (0)
-
-static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
- GDBStub::BreakpointAddress bkpt =
- GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute);
- if (GDBStub::IsMemoryBreak() ||
- (bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) {
- auto core = static_cast<ARM_Unicorn*>(user_data);
- core->RecordBreak(bkpt);
- uc_emu_stop(uc);
- }
-}
-
-static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value,
- void* user_data) {
- auto* const system = static_cast<System*>(user_data);
-
- ARM_Interface::ThreadContext64 ctx{};
- system->CurrentArmInterface().SaveContext(ctx);
- ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x{:X}, pc=0x{:X}, lr=0x{:X}", addr,
- ctx.pc, ctx.cpu_registers[30]);
-
- return false;
-}
-
-ARM_Unicorn::ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
- Arch architecture, std::size_t core_index)
- : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, core_index{core_index} {
- const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64;
- CHECKED(uc_open(arch, UC_MODE_ARM, &uc));
-
- auto fpv = 3 << 20;
- CHECKED(uc_reg_write(uc, UC_ARM64_REG_CPACR_EL1, &fpv));
-
- uc_hook hook{};
- CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, UINT64_MAX));
- CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, &system, 0,
- UINT64_MAX));
- if (GDBStub::IsServerEnabled()) {
- CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, UINT64_MAX));
- last_bkpt_hit = false;
- }
-}
-
-ARM_Unicorn::~ARM_Unicorn() {
- CHECKED(uc_close(uc));
-}
-
-void ARM_Unicorn::SetPC(u64 pc) {
- CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc));
-}
-
-u64 ARM_Unicorn::GetPC() const {
- u64 val{};
- CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &val));
- return val;
-}
-
-u64 ARM_Unicorn::GetReg(int regn) const {
- u64 val{};
- auto treg = UC_ARM64_REG_SP;
- if (regn <= 28) {
- treg = (uc_arm64_reg)(UC_ARM64_REG_X0 + regn);
- } else if (regn < 31) {
- treg = (uc_arm64_reg)(UC_ARM64_REG_X29 + regn - 29);
- }
- CHECKED(uc_reg_read(uc, treg, &val));
- return val;
-}
-
-void ARM_Unicorn::SetReg(int regn, u64 val) {
- auto treg = UC_ARM64_REG_SP;
- if (regn <= 28) {
- treg = (uc_arm64_reg)(UC_ARM64_REG_X0 + regn);
- } else if (regn < 31) {
- treg = (uc_arm64_reg)(UC_ARM64_REG_X29 + regn - 29);
- }
- CHECKED(uc_reg_write(uc, treg, &val));
-}
-
-u128 ARM_Unicorn::GetVectorReg(int /*index*/) const {
- UNIMPLEMENTED();
- static constexpr u128 res{};
- return res;
-}
-
-void ARM_Unicorn::SetVectorReg(int /*index*/, u128 /*value*/) {
- UNIMPLEMENTED();
-}
-
-u32 ARM_Unicorn::GetPSTATE() const {
- u64 nzcv{};
- CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &nzcv));
- return static_cast<u32>(nzcv);
-}
-
-void ARM_Unicorn::SetPSTATE(u32 pstate) {
- u64 nzcv = pstate;
- CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &nzcv));
-}
-
-VAddr ARM_Unicorn::GetTlsAddress() const {
- u64 base{};
- CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
- return base;
-}
-
-void ARM_Unicorn::SetTlsAddress(VAddr base) {
- CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
-}
-
-u64 ARM_Unicorn::GetTPIDR_EL0() const {
- u64 value{};
- CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDR_EL0, &value));
- return value;
-}
-
-void ARM_Unicorn::SetTPIDR_EL0(u64 value) {
- CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value));
-}
-
-void ARM_Unicorn::ChangeProcessorID(std::size_t new_core_id) {
- core_index = new_core_id;
-}
-
-void ARM_Unicorn::Run() {
- if (GDBStub::IsServerEnabled()) {
- ExecuteInstructions(std::max(4000000U, 0U));
- } else {
- while (true) {
- if (interrupt_handlers[core_index].IsInterrupted()) {
- return;
- }
- ExecuteInstructions(10);
- }
- }
-}
-
-void ARM_Unicorn::Step() {
- ExecuteInstructions(1);
-}
-
-MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64));
-
-void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) {
- MICROPROFILE_SCOPE(ARM_Jit_Unicorn);
-
- // Temporarily map the code page for Unicorn
- u64 map_addr{GetPC() & ~Memory::PAGE_MASK};
- std::vector<u8> page_buffer(Memory::PAGE_SIZE);
- system.Memory().ReadBlock(map_addr, page_buffer.data(), page_buffer.size());
-
- CHECKED(uc_mem_map_ptr(uc, map_addr, page_buffer.size(),
- UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, page_buffer.data()));
- CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
- CHECKED(uc_mem_unmap(uc, map_addr, page_buffer.size()));
- if (GDBStub::IsServerEnabled()) {
- if (last_bkpt_hit && last_bkpt.type == GDBStub::BreakpointType::Execute) {
- uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
- }
-
- Kernel::Thread* const thread = system.CurrentScheduler().GetCurrentThread();
- SaveContext(thread->GetContext64());
- if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) {
- last_bkpt_hit = false;
- GDBStub::Break();
- GDBStub::SendTrap(thread, 5);
- }
- }
-}
-
-void ARM_Unicorn::SaveContext(ThreadContext64& ctx) {
- int uregs[32];
- void* tregs[32];
-
- CHECKED(uc_reg_read(uc, UC_ARM64_REG_SP, &ctx.sp));
- CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &ctx.pc));
- CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
-
- for (auto i = 0; i < 29; ++i) {
- uregs[i] = UC_ARM64_REG_X0 + i;
- tregs[i] = &ctx.cpu_registers[i];
- }
- uregs[29] = UC_ARM64_REG_X29;
- tregs[29] = (void*)&ctx.cpu_registers[29];
- uregs[30] = UC_ARM64_REG_X30;
- tregs[30] = (void*)&ctx.cpu_registers[30];
-
- CHECKED(uc_reg_read_batch(uc, uregs, tregs, 31));
-
- for (int i = 0; i < 32; ++i) {
- uregs[i] = UC_ARM64_REG_Q0 + i;
- tregs[i] = &ctx.vector_registers[i];
- }
-
- CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32));
-}
-
-void ARM_Unicorn::LoadContext(const ThreadContext64& ctx) {
- int uregs[32];
- void* tregs[32];
-
- CHECKED(uc_reg_write(uc, UC_ARM64_REG_SP, &ctx.sp));
- CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &ctx.pc));
- CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
-
- for (int i = 0; i < 29; ++i) {
- uregs[i] = UC_ARM64_REG_X0 + i;
- tregs[i] = (void*)&ctx.cpu_registers[i];
- }
- uregs[29] = UC_ARM64_REG_X29;
- tregs[29] = (void*)&ctx.cpu_registers[29];
- uregs[30] = UC_ARM64_REG_X30;
- tregs[30] = (void*)&ctx.cpu_registers[30];
-
- CHECKED(uc_reg_write_batch(uc, uregs, tregs, 31));
-
- for (auto i = 0; i < 32; ++i) {
- uregs[i] = UC_ARM64_REG_Q0 + i;
- tregs[i] = (void*)&ctx.vector_registers[i];
- }
-
- CHECKED(uc_reg_write_batch(uc, uregs, tregs, 32));
-}
-
-void ARM_Unicorn::PrepareReschedule() {
- CHECKED(uc_emu_stop(uc));
-}
-
-void ARM_Unicorn::ClearExclusiveState() {}
-
-void ARM_Unicorn::ClearInstructionCache() {}
-
-void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) {
- last_bkpt = bkpt;
- last_bkpt_hit = true;
-}
-
-void ARM_Unicorn::InterruptHook(uc_engine* uc, u32 int_no, void* user_data) {
- u32 esr{};
- CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
-
- const auto ec = esr >> 26;
- const auto iss = esr & 0xFFFFFF;
-
- auto* const arm_instance = static_cast<ARM_Unicorn*>(user_data);
-
- switch (ec) {
- case 0x15: // SVC
- Kernel::Svc::Call(arm_instance->system, iss);
- break;
- }
-}
-
-} // namespace Core
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
deleted file mode 100644
index 810aff311..000000000
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <unicorn/unicorn.h>
-#include "common/common_types.h"
-#include "core/arm/arm_interface.h"
-#include "core/gdbstub/gdbstub.h"
-
-namespace Core {
-
-class System;
-
-class ARM_Unicorn final : public ARM_Interface {
-public:
- enum class Arch {
- AArch32, // 32-bit ARM
- AArch64, // 64-bit ARM
- };
-
- explicit ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
- Arch architecture, std::size_t core_index);
- ~ARM_Unicorn() override;
-
- void SetPC(u64 pc) override;
- u64 GetPC() const override;
- u64 GetReg(int index) const override;
- void SetReg(int index, u64 value) override;
- u128 GetVectorReg(int index) const override;
- void SetVectorReg(int index, u128 value) override;
- u32 GetPSTATE() const override;
- void SetPSTATE(u32 pstate) override;
- VAddr GetTlsAddress() const override;
- void SetTlsAddress(VAddr address) override;
- void SetTPIDR_EL0(u64 value) override;
- u64 GetTPIDR_EL0() const override;
- void ChangeProcessorID(std::size_t new_core_id) override;
- void PrepareReschedule() override;
- void ClearExclusiveState() override;
- void ExecuteInstructions(std::size_t num_instructions);
- void Run() override;
- void Step() override;
- void ClearInstructionCache() override;
- void PageTableChanged(Common::PageTable&, std::size_t) override {}
- void RecordBreak(GDBStub::BreakpointAddress bkpt);
-
- void SaveContext(ThreadContext32& ctx) override {}
- void SaveContext(ThreadContext64& ctx) override;
- void LoadContext(const ThreadContext32& ctx) override {}
- void LoadContext(const ThreadContext64& ctx) override;
-
-private:
- static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data);
-
- uc_engine* uc{};
- GDBStub::BreakpointAddress last_bkpt{};
- bool last_bkpt_hit = false;
- std::size_t core_index;
-};
-
-} // namespace Core