summaryrefslogtreecommitdiff
path: root/src/core/arm/dynarmic
diff options
context:
space:
mode:
authorGravatar Fernando S2023-12-06 14:19:17 +0100
committerGravatar GitHub2023-12-06 14:19:17 +0100
commit8a79dd2d6c6445bff63ea1f2f5f1611a6afcd97a (patch)
tree265bf3c7970a570479c6a3ac1250549995f0329c /src/core/arm/dynarmic
parentMerge pull request #12271 from liamwhite/pretext-fix (diff)
parentarm: fix context save of vector regs (diff)
downloadyuzu-8a79dd2d6c6445bff63ea1f2f5f1611a6afcd97a.tar.gz
yuzu-8a79dd2d6c6445bff63ea1f2f5f1611a6afcd97a.tar.xz
yuzu-8a79dd2d6c6445bff63ea1f2f5f1611a6afcd97a.zip
Merge pull request #12236 from liamwhite/cpu-refactor
core: refactor emulated cpu core activation
Diffstat (limited to 'src/core/arm/dynarmic')
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp325
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h92
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp340
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h77
-rw-r--r--src/core/arm/dynarmic/dynarmic_cp15.cpp4
-rw-r--r--src/core/arm/dynarmic/dynarmic_cp15.h8
-rw-r--r--src/core/arm/dynarmic/dynarmic_exclusive_monitor.h8
7 files changed, 362 insertions, 492 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 44a297cdc..f34865e26 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -1,25 +1,13 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <cinttypes>
5#include <memory>
6#include <dynarmic/interface/A32/a32.h>
7#include <dynarmic/interface/A32/config.h>
8#include "common/assert.h"
9#include "common/literals.h"
10#include "common/logging/log.h"
11#include "common/page_table.h"
12#include "common/settings.h" 4#include "common/settings.h"
13#include "core/arm/dynarmic/arm_dynarmic.h" 5#include "core/arm/dynarmic/arm_dynarmic.h"
14#include "core/arm/dynarmic/arm_dynarmic_32.h" 6#include "core/arm/dynarmic/arm_dynarmic_32.h"
15#include "core/arm/dynarmic/dynarmic_cp15.h" 7#include "core/arm/dynarmic/dynarmic_cp15.h"
16#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" 8#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
17#include "core/core.h"
18#include "core/core_timing.h" 9#include "core/core_timing.h"
19#include "core/debugger/debugger.h"
20#include "core/hle/kernel/k_process.h" 10#include "core/hle/kernel/k_process.h"
21#include "core/hle/kernel/svc.h"
22#include "core/memory.h"
23 11
24namespace Core { 12namespace Core {
25 13
@@ -27,78 +15,78 @@ using namespace Common::Literals;
27 15
28class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { 16class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
29public: 17public:
30 explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) 18 explicit DynarmicCallbacks32(ArmDynarmic32& parent, const Kernel::KProcess* process)
31 : parent{parent_}, memory(parent.system.ApplicationMemory()), 19 : m_parent{parent}, m_memory(process->GetMemory()),
32 debugger_enabled{parent.system.DebuggerEnabled()}, 20 m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
33 check_memory_access{debugger_enabled || 21 m_check_memory_access{m_debugger_enabled ||
34 !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {} 22 !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {}
35 23
36 u8 MemoryRead8(u32 vaddr) override { 24 u8 MemoryRead8(u32 vaddr) override {
37 CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read); 25 CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
38 return memory.Read8(vaddr); 26 return m_memory.Read8(vaddr);
39 } 27 }
40 u16 MemoryRead16(u32 vaddr) override { 28 u16 MemoryRead16(u32 vaddr) override {
41 CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read); 29 CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);
42 return memory.Read16(vaddr); 30 return m_memory.Read16(vaddr);
43 } 31 }
44 u32 MemoryRead32(u32 vaddr) override { 32 u32 MemoryRead32(u32 vaddr) override {
45 CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read); 33 CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);
46 return memory.Read32(vaddr); 34 return m_memory.Read32(vaddr);
47 } 35 }
48 u64 MemoryRead64(u32 vaddr) override { 36 u64 MemoryRead64(u32 vaddr) override {
49 CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read); 37 CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
50 return memory.Read64(vaddr); 38 return m_memory.Read64(vaddr);
51 } 39 }
52 std::optional<u32> MemoryReadCode(u32 vaddr) override { 40 std::optional<u32> MemoryReadCode(u32 vaddr) override {
53 if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) { 41 if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) {
54 return std::nullopt; 42 return std::nullopt;
55 } 43 }
56 return memory.Read32(vaddr); 44 return m_memory.Read32(vaddr);
57 } 45 }
58 46
59 void MemoryWrite8(u32 vaddr, u8 value) override { 47 void MemoryWrite8(u32 vaddr, u8 value) override {
60 if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { 48 if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
61 memory.Write8(vaddr, value); 49 m_memory.Write8(vaddr, value);
62 } 50 }
63 } 51 }
64 void MemoryWrite16(u32 vaddr, u16 value) override { 52 void MemoryWrite16(u32 vaddr, u16 value) override {
65 if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) { 53 if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) {
66 memory.Write16(vaddr, value); 54 m_memory.Write16(vaddr, value);
67 } 55 }
68 } 56 }
69 void MemoryWrite32(u32 vaddr, u32 value) override { 57 void MemoryWrite32(u32 vaddr, u32 value) override {
70 if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) { 58 if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) {
71 memory.Write32(vaddr, value); 59 m_memory.Write32(vaddr, value);
72 } 60 }
73 } 61 }
74 void MemoryWrite64(u32 vaddr, u64 value) override { 62 void MemoryWrite64(u32 vaddr, u64 value) override {
75 if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) { 63 if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) {
76 memory.Write64(vaddr, value); 64 m_memory.Write64(vaddr, value);
77 } 65 }
78 } 66 }
79 67
80 bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override { 68 bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override {
81 return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) && 69 return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) &&
82 memory.WriteExclusive8(vaddr, value, expected); 70 m_memory.WriteExclusive8(vaddr, value, expected);
83 } 71 }
84 bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override { 72 bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override {
85 return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) && 73 return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) &&
86 memory.WriteExclusive16(vaddr, value, expected); 74 m_memory.WriteExclusive16(vaddr, value, expected);
87 } 75 }
88 bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override { 76 bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override {
89 return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) && 77 return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) &&
90 memory.WriteExclusive32(vaddr, value, expected); 78 m_memory.WriteExclusive32(vaddr, value, expected);
91 } 79 }
92 bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override { 80 bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override {
93 return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) && 81 return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) &&
94 memory.WriteExclusive64(vaddr, value, expected); 82 m_memory.WriteExclusive64(vaddr, value, expected);
95 } 83 }
96 84
97 void InterpreterFallback(u32 pc, std::size_t num_instructions) override { 85 void InterpreterFallback(u32 pc, std::size_t num_instructions) override {
98 parent.LogBacktrace(); 86 m_parent.LogBacktrace(m_process);
99 LOG_ERROR(Core_ARM, 87 LOG_ERROR(Core_ARM,
100 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, 88 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
101 num_instructions, memory.Read32(pc)); 89 num_instructions, m_memory.Read32(pc));
102 } 90 }
103 91
104 void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { 92 void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
@@ -108,73 +96,64 @@ public:
108 ReturnException(pc, PrefetchAbort); 96 ReturnException(pc, PrefetchAbort);
109 return; 97 return;
110 default: 98 default:
111 if (debugger_enabled) { 99 if (m_debugger_enabled) {
112 ReturnException(pc, InstructionBreakpoint); 100 ReturnException(pc, InstructionBreakpoint);
113 return; 101 return;
114 } 102 }
115 103
116 parent.LogBacktrace(); 104 m_parent.LogBacktrace(m_process);
117 LOG_CRITICAL(Core_ARM, 105 LOG_CRITICAL(Core_ARM,
118 "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})", 106 "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})",
119 exception, pc, memory.Read32(pc), parent.IsInThumbMode()); 107 exception, pc, m_memory.Read32(pc), m_parent.IsInThumbMode());
120 } 108 }
121 } 109 }
122 110
123 void CallSVC(u32 swi) override { 111 void CallSVC(u32 swi) override {
124 parent.svc_swi = swi; 112 m_parent.m_svc_swi = swi;
125 parent.jit.load()->HaltExecution(SupervisorCall); 113 m_parent.m_jit->HaltExecution(SupervisorCall);
126 } 114 }
127 115
128 void AddTicks(u64 ticks) override { 116 void AddTicks(u64 ticks) override {
129 if (parent.uses_wall_clock) { 117 ASSERT_MSG(!m_parent.m_uses_wall_clock, "Dynarmic ticking disabled");
130 return;
131 }
132 118
133 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a 119 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
134 // rough approximation of the amount of executed ticks in the system, it may be thrown off 120 // rough approximation of the amount of executed ticks in the system, it may be thrown off
135 // if not all cores are doing a similar amount of work. Instead of doing this, we should 121 // if not all cores are doing a similar amount of work. Instead of doing this, we should
136 // device a way so that timing is consistent across all cores without increasing the ticks 4 122 // device a way so that timing is consistent across all cores without increasing the ticks 4
137 // times. 123 // times.
138 u64 amortized_ticks = 124 u64 amortized_ticks = ticks / Core::Hardware::NUM_CPU_CORES;
139 (ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES;
140 // Always execute at least one tick. 125 // Always execute at least one tick.
141 amortized_ticks = std::max<u64>(amortized_ticks, 1); 126 amortized_ticks = std::max<u64>(amortized_ticks, 1);
142 127
143 parent.system.CoreTiming().AddTicks(amortized_ticks); 128 m_parent.m_system.CoreTiming().AddTicks(amortized_ticks);
144 num_interpreted_instructions = 0;
145 } 129 }
146 130
147 u64 GetTicksRemaining() override { 131 u64 GetTicksRemaining() override {
148 if (parent.uses_wall_clock) { 132 ASSERT_MSG(!m_parent.m_uses_wall_clock, "Dynarmic ticking disabled");
149 if (!IsInterrupted()) {
150 return minimum_run_cycles;
151 }
152 return 0U;
153 }
154 133
155 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0); 134 return std::max<s64>(m_parent.m_system.CoreTiming().GetDowncount(), 0);
156 } 135 }
157 136
158 bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) { 137 bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) {
159 if (!check_memory_access) { 138 if (!m_check_memory_access) {
160 return true; 139 return true;
161 } 140 }
162 141
163 if (!memory.IsValidVirtualAddressRange(addr, size)) { 142 if (!m_memory.IsValidVirtualAddressRange(addr, size)) {
164 LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}", 143 LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}",
165 addr); 144 addr);
166 parent.jit.load()->HaltExecution(PrefetchAbort); 145 m_parent.m_jit->HaltExecution(PrefetchAbort);
167 return false; 146 return false;
168 } 147 }
169 148
170 if (!debugger_enabled) { 149 if (!m_debugger_enabled) {
171 return true; 150 return true;
172 } 151 }
173 152
174 const auto match{parent.MatchingWatchpoint(addr, size, type)}; 153 const auto match{m_parent.MatchingWatchpoint(addr, size, type)};
175 if (match) { 154 if (match) {
176 parent.halted_watchpoint = match; 155 m_parent.m_halted_watchpoint = match;
177 parent.jit.load()->HaltExecution(DataAbort); 156 m_parent.m_jit->HaltExecution(DataAbort);
178 return false; 157 return false;
179 } 158 }
180 159
@@ -182,32 +161,31 @@ public:
182 } 161 }
183 162
184 void ReturnException(u32 pc, Dynarmic::HaltReason hr) { 163 void ReturnException(u32 pc, Dynarmic::HaltReason hr) {
185 parent.SaveContext(parent.breakpoint_context); 164 m_parent.GetContext(m_parent.m_breakpoint_context);
186 parent.breakpoint_context.cpu_registers[15] = pc; 165 m_parent.m_breakpoint_context.pc = pc;
187 parent.jit.load()->HaltExecution(hr); 166 m_parent.m_breakpoint_context.r[15] = pc;
188 } 167 m_parent.m_jit->HaltExecution(hr);
189
190 bool IsInterrupted() {
191 return parent.system.Kernel().PhysicalCore(parent.core_index).IsInterrupted();
192 } 168 }
193 169
194 ARM_Dynarmic_32& parent; 170 ArmDynarmic32& m_parent;
195 Core::Memory::Memory& memory; 171 Core::Memory::Memory& m_memory;
196 std::size_t num_interpreted_instructions{}; 172 const Kernel::KProcess* m_process{};
197 const bool debugger_enabled{}; 173 const bool m_debugger_enabled{};
198 const bool check_memory_access{}; 174 const bool m_check_memory_access{};
199 static constexpr u64 minimum_run_cycles = 10000U; 175 static constexpr u64 MinimumRunCycles = 10000U;
200}; 176};
201 177
202std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const { 178std::shared_ptr<Dynarmic::A32::Jit> ArmDynarmic32::MakeJit(Common::PageTable* page_table) const {
203 Dynarmic::A32::UserConfig config; 179 Dynarmic::A32::UserConfig config;
204 config.callbacks = cb.get(); 180 config.callbacks = m_cb.get();
205 config.coprocessors[15] = cp15; 181 config.coprocessors[15] = m_cp15;
206 config.define_unpredictable_behaviour = true; 182 config.define_unpredictable_behaviour = true;
207 static constexpr std::size_t YUZU_PAGEBITS = 12; 183
208 static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - YUZU_PAGEBITS);
209 if (page_table) { 184 if (page_table) {
210 config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>( 185 constexpr size_t PageBits = 12;
186 constexpr size_t NumPageTableEntries = 1 << (32 - PageBits);
187
188 config.page_table = reinterpret_cast<std::array<std::uint8_t*, NumPageTableEntries>*>(
211 page_table->pointers.data()); 189 page_table->pointers.data());
212 config.absolute_offset_page_table = true; 190 config.absolute_offset_page_table = true;
213 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS; 191 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
@@ -221,12 +199,12 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
221 } 199 }
222 200
223 // Multi-process state 201 // Multi-process state
224 config.processor_id = core_index; 202 config.processor_id = m_core_index;
225 config.global_monitor = &exclusive_monitor.monitor; 203 config.global_monitor = &m_exclusive_monitor.monitor;
226 204
227 // Timing 205 // Timing
228 config.wall_clock_cntpct = uses_wall_clock; 206 config.wall_clock_cntpct = m_uses_wall_clock;
229 config.enable_cycle_counting = true; 207 config.enable_cycle_counting = !m_uses_wall_clock;
230 208
231 // Code cache size 209 // Code cache size
232#ifdef ARCHITECTURE_arm64 210#ifdef ARCHITECTURE_arm64
@@ -236,7 +214,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
236#endif 214#endif
237 215
238 // Allow memory fault handling to work 216 // Allow memory fault handling to work
239 if (system.DebuggerEnabled()) { 217 if (m_system.DebuggerEnabled()) {
240 config.check_halt_on_memory_access = true; 218 config.check_halt_on_memory_access = true;
241 } 219 }
242 220
@@ -325,137 +303,140 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
325 return std::make_unique<Dynarmic::A32::Jit>(config); 303 return std::make_unique<Dynarmic::A32::Jit>(config);
326} 304}
327 305
328HaltReason ARM_Dynarmic_32::RunJit() { 306static std::pair<u32, u32> FpscrToFpsrFpcr(u32 fpscr) {
329 return TranslateHaltReason(jit.load()->Run()); 307 // FPSCR bits [31:27] are mapped to FPSR[31:27].
308 // FPSCR bit [7] is mapped to FPSR[7].
309 // FPSCR bits [4:0] are mapped to FPSR[4:0].
310 const u32 nzcv = fpscr & 0xf8000000;
311 const u32 idc = fpscr & 0x80;
312 const u32 fiq = fpscr & 0x1f;
313 const u32 fpsr = nzcv | idc | fiq;
314
315 // FPSCR bits [26:15] are mapped to FPCR[26:15].
316 // FPSCR bits [12:8] are mapped to FPCR[12:8].
317 const u32 round = fpscr & 0x7ff8000;
318 const u32 trap = fpscr & 0x1f00;
319 const u32 fpcr = round | trap;
320
321 return {fpsr, fpcr};
330} 322}
331 323
332HaltReason ARM_Dynarmic_32::StepJit() { 324static u32 FpsrFpcrToFpscr(u64 fpsr, u64 fpcr) {
333 return TranslateHaltReason(jit.load()->Step()); 325 auto [s, c] = FpscrToFpsrFpcr(static_cast<u32>(fpsr | fpcr));
326 return s | c;
334} 327}
335 328
336u32 ARM_Dynarmic_32::GetSvcNumber() const { 329bool ArmDynarmic32::IsInThumbMode() const {
337 return svc_swi; 330 return (m_jit->Cpsr() & 0x20) != 0;
338} 331}
339 332
340const Kernel::DebugWatchpoint* ARM_Dynarmic_32::HaltedWatchpoint() const { 333HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) {
341 return halted_watchpoint; 334 m_jit->ClearExclusiveState();
335 return TranslateHaltReason(m_jit->Run());
342} 336}
343 337
344void ARM_Dynarmic_32::RewindBreakpointInstruction() { 338HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) {
345 LoadContext(breakpoint_context); 339 m_jit->ClearExclusiveState();
340 return TranslateHaltReason(m_jit->Step());
346} 341}
347 342
348ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, 343u32 ArmDynarmic32::GetSvcNumber() const {
349 DynarmicExclusiveMonitor& exclusive_monitor_, 344 return m_svc_swi;
350 std::size_t core_index_) 345}
351 : ARM_Interface{system_, uses_wall_clock_}, cb(std::make_unique<DynarmicCallbacks32>(*this)),
352 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_},
353 exclusive_monitor{exclusive_monitor_}, null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {}
354 346
355ARM_Dynarmic_32::~ARM_Dynarmic_32() = default; 347void ArmDynarmic32::GetSvcArguments(std::span<uint64_t, 8> args) const {
348 Dynarmic::A32::Jit& j = *m_jit;
349 auto& gpr = j.Regs();
356 350
357void ARM_Dynarmic_32::SetPC(u64 pc) { 351 for (size_t i = 0; i < 8; i++) {
358 jit.load()->Regs()[15] = static_cast<u32>(pc); 352 args[i] = gpr[i];
353 }
359} 354}
360 355
361u64 ARM_Dynarmic_32::GetPC() const { 356void ArmDynarmic32::SetSvcArguments(std::span<const uint64_t, 8> args) {
362 return jit.load()->Regs()[15]; 357 Dynarmic::A32::Jit& j = *m_jit;
363} 358 auto& gpr = j.Regs();
364 359
365u64 ARM_Dynarmic_32::GetSP() const { 360 for (size_t i = 0; i < 8; i++) {
366 return jit.load()->Regs()[13]; 361 gpr[i] = static_cast<u32>(args[i]);
362 }
367} 363}
368 364
369u64 ARM_Dynarmic_32::GetReg(int index) const { 365const Kernel::DebugWatchpoint* ArmDynarmic32::HaltedWatchpoint() const {
370 return jit.load()->Regs()[index]; 366 return m_halted_watchpoint;
371} 367}
372 368
373void ARM_Dynarmic_32::SetReg(int index, u64 value) { 369void ArmDynarmic32::RewindBreakpointInstruction() {
374 jit.load()->Regs()[index] = static_cast<u32>(value); 370 this->SetContext(m_breakpoint_context);
375} 371}
376 372
377u128 ARM_Dynarmic_32::GetVectorReg(int index) const { 373ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
378 return {}; 374 DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
375 : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
376 m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)),
377 m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} {
378 auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl();
379 m_jit = MakeJit(&page_table_impl);
379} 380}
380 381
381void ARM_Dynarmic_32::SetVectorReg(int index, u128 value) {} 382ArmDynarmic32::~ArmDynarmic32() = default;
382 383
383u32 ARM_Dynarmic_32::GetPSTATE() const { 384void ArmDynarmic32::SetTpidrroEl0(u64 value) {
384 return jit.load()->Cpsr(); 385 m_cp15->uro = static_cast<u32>(value);
385} 386}
386 387
387void ARM_Dynarmic_32::SetPSTATE(u32 cpsr) { 388void ArmDynarmic32::GetContext(Kernel::Svc::ThreadContext& ctx) const {
388 jit.load()->SetCpsr(cpsr); 389 Dynarmic::A32::Jit& j = *m_jit;
389} 390 auto& gpr = j.Regs();
391 auto& fpr = j.ExtRegs();
390 392
391u64 ARM_Dynarmic_32::GetTlsAddress() const { 393 for (size_t i = 0; i < 16; i++) {
392 return cp15->uro; 394 ctx.r[i] = gpr[i];
393} 395 }
394 396
395void ARM_Dynarmic_32::SetTlsAddress(u64 address) { 397 ctx.fp = gpr[11];
396 cp15->uro = static_cast<u32>(address); 398 ctx.sp = gpr[13];
397} 399 ctx.lr = gpr[14];
400 ctx.pc = gpr[15];
401 ctx.pstate = j.Cpsr();
398 402
399u64 ARM_Dynarmic_32::GetTPIDR_EL0() const { 403 static_assert(sizeof(fpr) <= sizeof(ctx.v));
400 return cp15->uprw; 404 std::memcpy(ctx.v.data(), &fpr, sizeof(fpr));
401}
402 405
403void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) { 406 auto [fpsr, fpcr] = FpscrToFpsrFpcr(j.Fpscr());
404 cp15->uprw = static_cast<u32>(value); 407 ctx.fpcr = fpcr;
408 ctx.fpsr = fpsr;
409 ctx.tpidr = m_cp15->uprw;
405} 410}
406 411
407void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) const { 412void ArmDynarmic32::SetContext(const Kernel::Svc::ThreadContext& ctx) {
408 Dynarmic::A32::Jit* j = jit.load(); 413 Dynarmic::A32::Jit& j = *m_jit;
409 ctx.cpu_registers = j->Regs(); 414 auto& gpr = j.Regs();
410 ctx.extension_registers = j->ExtRegs(); 415 auto& fpr = j.ExtRegs();
411 ctx.cpsr = j->Cpsr();
412 ctx.fpscr = j->Fpscr();
413}
414 416
415void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { 417 for (size_t i = 0; i < 16; i++) {
416 Dynarmic::A32::Jit* j = jit.load(); 418 gpr[i] = static_cast<u32>(ctx.r[i]);
417 j->Regs() = ctx.cpu_registers; 419 }
418 j->ExtRegs() = ctx.extension_registers;
419 j->SetCpsr(ctx.cpsr);
420 j->SetFpscr(ctx.fpscr);
421}
422 420
423void ARM_Dynarmic_32::SignalInterrupt() { 421 j.SetCpsr(ctx.pstate);
424 jit.load()->HaltExecution(BreakLoop);
425}
426 422
427void ARM_Dynarmic_32::ClearInterrupt() { 423 static_assert(sizeof(fpr) <= sizeof(ctx.v));
428 jit.load()->ClearHalt(BreakLoop); 424 std::memcpy(&fpr, ctx.v.data(), sizeof(fpr));
429}
430 425
431void ARM_Dynarmic_32::ClearInstructionCache() { 426 j.SetFpscr(FpsrFpcrToFpscr(ctx.fpsr, ctx.fpcr));
432 jit.load()->ClearCache(); 427 m_cp15->uprw = static_cast<u32>(ctx.tpidr);
433} 428}
434 429
435void ARM_Dynarmic_32::InvalidateCacheRange(u64 addr, std::size_t size) { 430void ArmDynarmic32::SignalInterrupt(Kernel::KThread* thread) {
436 jit.load()->InvalidateCacheRange(static_cast<u32>(addr), size); 431 m_jit->HaltExecution(BreakLoop);
437} 432}
438 433
439void ARM_Dynarmic_32::ClearExclusiveState() { 434void ArmDynarmic32::ClearInstructionCache() {
440 jit.load()->ClearExclusiveState(); 435 m_jit->ClearCache();
441} 436}
442 437
443void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table, 438void ArmDynarmic32::InvalidateCacheRange(u64 addr, std::size_t size) {
444 std::size_t new_address_space_size_in_bits) { 439 m_jit->InvalidateCacheRange(static_cast<u32>(addr), size);
445 ThreadContext32 ctx{};
446 SaveContext(ctx);
447
448 auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
449 auto iter = jit_cache.find(key);
450 if (iter != jit_cache.end()) {
451 jit.store(iter->second.get());
452 LoadContext(ctx);
453 return;
454 }
455 std::shared_ptr new_jit = MakeJit(&page_table);
456 jit.store(new_jit.get());
457 LoadContext(ctx);
458 jit_cache.emplace(key, std::move(new_jit));
459} 440}
460 441
461} // namespace Core 442} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index 92fb3f836..185ac7cbf 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -3,14 +3,8 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <atomic>
7#include <memory>
8#include <unordered_map>
9
10#include <dynarmic/interface/A32/a32.h> 6#include <dynarmic/interface/A32/a32.h>
11#include <dynarmic/interface/A64/a64.h> 7
12#include "common/common_types.h"
13#include "common/hash.h"
14#include "core/arm/arm_interface.h" 8#include "core/arm/arm_interface.h"
15#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" 9#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
16 10
@@ -20,89 +14,63 @@ class Memory;
20 14
21namespace Core { 15namespace Core {
22 16
23class CPUInterruptHandler;
24class DynarmicCallbacks32; 17class DynarmicCallbacks32;
25class DynarmicCP15; 18class DynarmicCP15;
26class DynarmicExclusiveMonitor;
27class System; 19class System;
28 20
29class ARM_Dynarmic_32 final : public ARM_Interface { 21class ArmDynarmic32 final : public ArmInterface {
30public: 22public:
31 ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, 23 ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
32 DynarmicExclusiveMonitor& exclusive_monitor_, std::size_t core_index_); 24 DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
33 ~ARM_Dynarmic_32() override; 25 ~ArmDynarmic32() override;
34
35 void SetPC(u64 pc) override;
36 u64 GetPC() const override;
37 u64 GetSP() const override;
38 u64 GetReg(int index) const override;
39 void SetReg(int index, u64 value) override;
40 u128 GetVectorReg(int index) const override;
41 void SetVectorReg(int index, u128 value) override;
42 u32 GetPSTATE() const override;
43 void SetPSTATE(u32 pstate) override;
44 u64 GetTlsAddress() const override;
45 void SetTlsAddress(u64 address) override;
46 void SetTPIDR_EL0(u64 value) override;
47 u64 GetTPIDR_EL0() const override;
48
49 bool IsInThumbMode() const {
50 return (GetPSTATE() & 0x20) != 0;
51 }
52 26
53 Architecture GetArchitecture() const override { 27 Architecture GetArchitecture() const override {
54 return Architecture::Aarch32; 28 return Architecture::AArch32;
55 } 29 }
56 void SaveContext(ThreadContext32& ctx) const override;
57 void SaveContext(ThreadContext64& ctx) const override {}
58 void LoadContext(const ThreadContext32& ctx) override;
59 void LoadContext(const ThreadContext64& ctx) override {}
60 30
61 void SignalInterrupt() override; 31 bool IsInThumbMode() const;
62 void ClearInterrupt() override; 32
63 void ClearExclusiveState() override; 33 HaltReason RunThread(Kernel::KThread* thread) override;
34 HaltReason StepThread(Kernel::KThread* thread) override;
35
36 void GetContext(Kernel::Svc::ThreadContext& ctx) const override;
37 void SetContext(const Kernel::Svc::ThreadContext& ctx) override;
38 void SetTpidrroEl0(u64 value) override;
39
40 void GetSvcArguments(std::span<uint64_t, 8> args) const override;
41 void SetSvcArguments(std::span<const uint64_t, 8> args) override;
42 u32 GetSvcNumber() const override;
64 43
44 void SignalInterrupt(Kernel::KThread* thread) override;
65 void ClearInstructionCache() override; 45 void ClearInstructionCache() override;
66 void InvalidateCacheRange(u64 addr, std::size_t size) override; 46 void InvalidateCacheRange(u64 addr, std::size_t size) override;
67 void PageTableChanged(Common::PageTable& new_page_table,
68 std::size_t new_address_space_size_in_bits) override;
69 47
70protected: 48protected:
71 HaltReason RunJit() override;
72 HaltReason StepJit() override;
73 u32 GetSvcNumber() const override;
74 const Kernel::DebugWatchpoint* HaltedWatchpoint() const override; 49 const Kernel::DebugWatchpoint* HaltedWatchpoint() const override;
75 void RewindBreakpointInstruction() override; 50 void RewindBreakpointInstruction() override;
76 51
77private: 52private:
78 std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; 53 System& m_system;
79 54 DynarmicExclusiveMonitor& m_exclusive_monitor;
80 static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc);
81
82 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
83 using JitCacheType =
84 std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A32::Jit>, Common::PairHash>;
85 55
56private:
86 friend class DynarmicCallbacks32; 57 friend class DynarmicCallbacks32;
87 friend class DynarmicCP15; 58 friend class DynarmicCP15;
88 59
89 std::unique_ptr<DynarmicCallbacks32> cb; 60 std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const;
90 JitCacheType jit_cache;
91 std::shared_ptr<DynarmicCP15> cp15;
92 std::size_t core_index;
93 DynarmicExclusiveMonitor& exclusive_monitor;
94 61
95 std::shared_ptr<Dynarmic::A32::Jit> null_jit; 62 std::unique_ptr<DynarmicCallbacks32> m_cb{};
63 std::shared_ptr<DynarmicCP15> m_cp15{};
64 std::size_t m_core_index{};
96 65
97 // A raw pointer here is fine; we never delete Jit instances. 66 std::shared_ptr<Dynarmic::A32::Jit> m_jit{};
98 std::atomic<Dynarmic::A32::Jit*> jit;
99 67
100 // SVC callback 68 // SVC callback
101 u32 svc_swi{}; 69 u32 m_svc_swi{};
102 70
103 // Watchpoint info 71 // Watchpoint info
104 const Kernel::DebugWatchpoint* halted_watchpoint; 72 const Kernel::DebugWatchpoint* m_halted_watchpoint{};
105 ThreadContext32 breakpoint_context; 73 Kernel::Svc::ThreadContext m_breakpoint_context{};
106}; 74};
107 75
108} // namespace Core 76} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 2e3674b6d..dff14756e 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -1,25 +1,12 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <cinttypes>
5#include <memory>
6#include <dynarmic/interface/A64/a64.h>
7#include <dynarmic/interface/A64/config.h>
8#include "common/assert.h"
9#include "common/literals.h"
10#include "common/logging/log.h"
11#include "common/page_table.h"
12#include "common/settings.h" 4#include "common/settings.h"
13#include "core/arm/dynarmic/arm_dynarmic.h" 5#include "core/arm/dynarmic/arm_dynarmic.h"
14#include "core/arm/dynarmic/arm_dynarmic_64.h" 6#include "core/arm/dynarmic/arm_dynarmic_64.h"
15#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" 7#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
16#include "core/core.h"
17#include "core/core_timing.h" 8#include "core/core_timing.h"
18#include "core/debugger/debugger.h"
19#include "core/hardware_properties.h"
20#include "core/hle/kernel/k_process.h" 9#include "core/hle/kernel/k_process.h"
21#include "core/hle/kernel/svc.h"
22#include "core/memory.h"
23 10
24namespace Core { 11namespace Core {
25 12
@@ -28,92 +15,92 @@ using namespace Common::Literals;
28 15
29class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { 16class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
30public: 17public:
31 explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) 18 explicit DynarmicCallbacks64(ArmDynarmic64& parent, const Kernel::KProcess* process)
32 : parent{parent_}, memory(parent.system.ApplicationMemory()), 19 : m_parent{parent}, m_memory(process->GetMemory()),
33 debugger_enabled{parent.system.DebuggerEnabled()}, 20 m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
34 check_memory_access{debugger_enabled || 21 m_check_memory_access{m_debugger_enabled ||
35 !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {} 22 !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {}
36 23
37 u8 MemoryRead8(u64 vaddr) override { 24 u8 MemoryRead8(u64 vaddr) override {
38 CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read); 25 CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
39 return memory.Read8(vaddr); 26 return m_memory.Read8(vaddr);
40 } 27 }
41 u16 MemoryRead16(u64 vaddr) override { 28 u16 MemoryRead16(u64 vaddr) override {
42 CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read); 29 CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);
43 return memory.Read16(vaddr); 30 return m_memory.Read16(vaddr);
44 } 31 }
45 u32 MemoryRead32(u64 vaddr) override { 32 u32 MemoryRead32(u64 vaddr) override {
46 CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read); 33 CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);
47 return memory.Read32(vaddr); 34 return m_memory.Read32(vaddr);
48 } 35 }
49 u64 MemoryRead64(u64 vaddr) override { 36 u64 MemoryRead64(u64 vaddr) override {
50 CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read); 37 CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
51 return memory.Read64(vaddr); 38 return m_memory.Read64(vaddr);
52 } 39 }
53 Vector MemoryRead128(u64 vaddr) override { 40 Vector MemoryRead128(u64 vaddr) override {
54 CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read); 41 CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
55 return {memory.Read64(vaddr), memory.Read64(vaddr + 8)}; 42 return {m_memory.Read64(vaddr), m_memory.Read64(vaddr + 8)};
56 } 43 }
57 std::optional<u32> MemoryReadCode(u64 vaddr) override { 44 std::optional<u32> MemoryReadCode(u64 vaddr) override {
58 if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) { 45 if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) {
59 return std::nullopt; 46 return std::nullopt;
60 } 47 }
61 return memory.Read32(vaddr); 48 return m_memory.Read32(vaddr);
62 } 49 }
63 50
64 void MemoryWrite8(u64 vaddr, u8 value) override { 51 void MemoryWrite8(u64 vaddr, u8 value) override {
65 if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { 52 if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
66 memory.Write8(vaddr, value); 53 m_memory.Write8(vaddr, value);
67 } 54 }
68 } 55 }
69 void MemoryWrite16(u64 vaddr, u16 value) override { 56 void MemoryWrite16(u64 vaddr, u16 value) override {
70 if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) { 57 if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) {
71 memory.Write16(vaddr, value); 58 m_memory.Write16(vaddr, value);
72 } 59 }
73 } 60 }
74 void MemoryWrite32(u64 vaddr, u32 value) override { 61 void MemoryWrite32(u64 vaddr, u32 value) override {
75 if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) { 62 if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) {
76 memory.Write32(vaddr, value); 63 m_memory.Write32(vaddr, value);
77 } 64 }
78 } 65 }
79 void MemoryWrite64(u64 vaddr, u64 value) override { 66 void MemoryWrite64(u64 vaddr, u64 value) override {
80 if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) { 67 if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) {
81 memory.Write64(vaddr, value); 68 m_memory.Write64(vaddr, value);
82 } 69 }
83 } 70 }
84 void MemoryWrite128(u64 vaddr, Vector value) override { 71 void MemoryWrite128(u64 vaddr, Vector value) override {
85 if (CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write)) { 72 if (CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write)) {
86 memory.Write64(vaddr, value[0]); 73 m_memory.Write64(vaddr, value[0]);
87 memory.Write64(vaddr + 8, value[1]); 74 m_memory.Write64(vaddr + 8, value[1]);
88 } 75 }
89 } 76 }
90 77
91 bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override { 78 bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override {
92 return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) && 79 return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) &&
93 memory.WriteExclusive8(vaddr, value, expected); 80 m_memory.WriteExclusive8(vaddr, value, expected);
94 } 81 }
95 bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override { 82 bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override {
96 return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) && 83 return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) &&
97 memory.WriteExclusive16(vaddr, value, expected); 84 m_memory.WriteExclusive16(vaddr, value, expected);
98 } 85 }
99 bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, std::uint32_t expected) override { 86 bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, std::uint32_t expected) override {
100 return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) && 87 return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) &&
101 memory.WriteExclusive32(vaddr, value, expected); 88 m_memory.WriteExclusive32(vaddr, value, expected);
102 } 89 }
103 bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, std::uint64_t expected) override { 90 bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, std::uint64_t expected) override {
104 return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) && 91 return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) &&
105 memory.WriteExclusive64(vaddr, value, expected); 92 m_memory.WriteExclusive64(vaddr, value, expected);
106 } 93 }
107 bool MemoryWriteExclusive128(u64 vaddr, Vector value, Vector expected) override { 94 bool MemoryWriteExclusive128(u64 vaddr, Vector value, Vector expected) override {
108 return CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write) && 95 return CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write) &&
109 memory.WriteExclusive128(vaddr, value, expected); 96 m_memory.WriteExclusive128(vaddr, value, expected);
110 } 97 }
111 98
112 void InterpreterFallback(u64 pc, std::size_t num_instructions) override { 99 void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
113 parent.LogBacktrace(); 100 m_parent.LogBacktrace(m_process);
114 LOG_ERROR(Core_ARM, 101 LOG_ERROR(Core_ARM,
115 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, 102 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
116 num_instructions, memory.Read32(pc)); 103 num_instructions, m_memory.Read32(pc));
117 ReturnException(pc, PrefetchAbort); 104 ReturnException(pc, PrefetchAbort);
118 } 105 }
119 106
@@ -124,11 +111,11 @@ public:
124 static constexpr u64 ICACHE_LINE_SIZE = 64; 111 static constexpr u64 ICACHE_LINE_SIZE = 64;
125 112
126 const u64 cache_line_start = value & ~(ICACHE_LINE_SIZE - 1); 113 const u64 cache_line_start = value & ~(ICACHE_LINE_SIZE - 1);
127 parent.system.InvalidateCpuInstructionCacheRange(cache_line_start, ICACHE_LINE_SIZE); 114 m_parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE);
128 break; 115 break;
129 } 116 }
130 case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU: 117 case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU:
131 parent.system.InvalidateCpuInstructionCaches(); 118 m_parent.ClearInstructionCache();
132 break; 119 break;
133 case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable: 120 case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable:
134 default: 121 default:
@@ -136,7 +123,7 @@ public:
136 break; 123 break;
137 } 124 }
138 125
139 parent.jit.load()->HaltExecution(Dynarmic::HaltReason::CacheInvalidation); 126 m_parent.m_jit->HaltExecution(Dynarmic::HaltReason::CacheInvalidation);
140 } 127 }
141 128
142 void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { 129 void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
@@ -152,26 +139,24 @@ public:
152 ReturnException(pc, PrefetchAbort); 139 ReturnException(pc, PrefetchAbort);
153 return; 140 return;
154 default: 141 default:
155 if (debugger_enabled) { 142 if (m_debugger_enabled) {
156 ReturnException(pc, InstructionBreakpoint); 143 ReturnException(pc, InstructionBreakpoint);
157 return; 144 return;
158 } 145 }
159 146
160 parent.LogBacktrace(); 147 m_parent.LogBacktrace(m_process);
161 LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", 148 LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
162 static_cast<std::size_t>(exception), pc, memory.Read32(pc)); 149 static_cast<std::size_t>(exception), pc, m_memory.Read32(pc));
163 } 150 }
164 } 151 }
165 152
166 void CallSVC(u32 swi) override { 153 void CallSVC(u32 svc) override {
167 parent.svc_swi = swi; 154 m_parent.m_svc = svc;
168 parent.jit.load()->HaltExecution(SupervisorCall); 155 m_parent.m_jit->HaltExecution(SupervisorCall);
169 } 156 }
170 157
171 void AddTicks(u64 ticks) override { 158 void AddTicks(u64 ticks) override {
172 if (parent.uses_wall_clock) { 159 ASSERT_MSG(!m_parent.m_uses_wall_clock, "Dynarmic ticking disabled");
173 return;
174 }
175 160
176 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a 161 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
177 // rough approximation of the amount of executed ticks in the system, it may be thrown off 162 // rough approximation of the amount of executed ticks in the system, it may be thrown off
@@ -182,44 +167,39 @@ public:
182 // Always execute at least one tick. 167 // Always execute at least one tick.
183 amortized_ticks = std::max<u64>(amortized_ticks, 1); 168 amortized_ticks = std::max<u64>(amortized_ticks, 1);
184 169
185 parent.system.CoreTiming().AddTicks(amortized_ticks); 170 m_parent.m_system.CoreTiming().AddTicks(amortized_ticks);
186 } 171 }
187 172
188 u64 GetTicksRemaining() override { 173 u64 GetTicksRemaining() override {
189 if (parent.uses_wall_clock) { 174 ASSERT_MSG(!m_parent.m_uses_wall_clock, "Dynarmic ticking disabled");
190 if (!IsInterrupted()) {
191 return minimum_run_cycles;
192 }
193 return 0U;
194 }
195 175
196 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0); 176 return std::max<s64>(m_parent.m_system.CoreTiming().GetDowncount(), 0);
197 } 177 }
198 178
199 u64 GetCNTPCT() override { 179 u64 GetCNTPCT() override {
200 return parent.system.CoreTiming().GetClockTicks(); 180 return m_parent.m_system.CoreTiming().GetClockTicks();
201 } 181 }
202 182
203 bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) { 183 bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) {
204 if (!check_memory_access) { 184 if (!m_check_memory_access) {
205 return true; 185 return true;
206 } 186 }
207 187
208 if (!memory.IsValidVirtualAddressRange(addr, size)) { 188 if (!m_memory.IsValidVirtualAddressRange(addr, size)) {
209 LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}", 189 LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}",
210 addr); 190 addr);
211 parent.jit.load()->HaltExecution(PrefetchAbort); 191 m_parent.m_jit->HaltExecution(PrefetchAbort);
212 return false; 192 return false;
213 } 193 }
214 194
215 if (!debugger_enabled) { 195 if (!m_debugger_enabled) {
216 return true; 196 return true;
217 } 197 }
218 198
219 const auto match{parent.MatchingWatchpoint(addr, size, type)}; 199 const auto match{m_parent.MatchingWatchpoint(addr, size, type)};
220 if (match) { 200 if (match) {
221 parent.halted_watchpoint = match; 201 m_parent.m_halted_watchpoint = match;
222 parent.jit.load()->HaltExecution(DataAbort); 202 m_parent.m_jit->HaltExecution(DataAbort);
223 return false; 203 return false;
224 } 204 }
225 205
@@ -227,30 +207,27 @@ public:
227 } 207 }
228 208
229 void ReturnException(u64 pc, Dynarmic::HaltReason hr) { 209 void ReturnException(u64 pc, Dynarmic::HaltReason hr) {
230 parent.SaveContext(parent.breakpoint_context); 210 m_parent.GetContext(m_parent.m_breakpoint_context);
231 parent.breakpoint_context.pc = pc; 211 m_parent.m_breakpoint_context.pc = pc;
232 parent.jit.load()->HaltExecution(hr); 212 m_parent.m_jit->HaltExecution(hr);
233 } 213 }
234 214
235 bool IsInterrupted() { 215 ArmDynarmic64& m_parent;
236 return parent.system.Kernel().PhysicalCore(parent.core_index).IsInterrupted(); 216 Core::Memory::Memory& m_memory;
237 } 217 u64 m_tpidrro_el0{};
238 218 u64 m_tpidr_el0{};
239 ARM_Dynarmic_64& parent; 219 const Kernel::KProcess* m_process{};
240 Core::Memory::Memory& memory; 220 const bool m_debugger_enabled{};
241 u64 tpidrro_el0 = 0; 221 const bool m_check_memory_access{};
242 u64 tpidr_el0 = 0; 222 static constexpr u64 MinimumRunCycles = 10000U;
243 const bool debugger_enabled{};
244 const bool check_memory_access{};
245 static constexpr u64 minimum_run_cycles = 10000U;
246}; 223};
247 224
248std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table, 225std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* page_table,
249 std::size_t address_space_bits) const { 226 std::size_t address_space_bits) const {
250 Dynarmic::A64::UserConfig config; 227 Dynarmic::A64::UserConfig config;
251 228
252 // Callbacks 229 // Callbacks
253 config.callbacks = cb.get(); 230 config.callbacks = m_cb.get();
254 231
255 // Memory 232 // Memory
256 if (page_table) { 233 if (page_table) {
@@ -271,12 +248,12 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
271 } 248 }
272 249
273 // Multi-process state 250 // Multi-process state
274 config.processor_id = core_index; 251 config.processor_id = m_core_index;
275 config.global_monitor = &exclusive_monitor.monitor; 252 config.global_monitor = &m_exclusive_monitor.monitor;
276 253
277 // System registers 254 // System registers
278 config.tpidrro_el0 = &cb->tpidrro_el0; 255 config.tpidrro_el0 = &m_cb->m_tpidrro_el0;
279 config.tpidr_el0 = &cb->tpidr_el0; 256 config.tpidr_el0 = &m_cb->m_tpidr_el0;
280 config.dczid_el0 = 4; 257 config.dczid_el0 = 4;
281 config.ctr_el0 = 0x8444c004; 258 config.ctr_el0 = 0x8444c004;
282 config.cntfrq_el0 = Hardware::CNTFREQ; 259 config.cntfrq_el0 = Hardware::CNTFREQ;
@@ -285,8 +262,8 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
285 config.define_unpredictable_behaviour = true; 262 config.define_unpredictable_behaviour = true;
286 263
287 // Timing 264 // Timing
288 config.wall_clock_cntpct = uses_wall_clock; 265 config.wall_clock_cntpct = m_uses_wall_clock;
289 config.enable_cycle_counting = true; 266 config.enable_cycle_counting = !m_uses_wall_clock;
290 267
291 // Code cache size 268 // Code cache size
292#ifdef ARCHITECTURE_arm64 269#ifdef ARCHITECTURE_arm64
@@ -296,7 +273,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
296#endif 273#endif
297 274
298 // Allow memory fault handling to work 275 // Allow memory fault handling to work
299 if (system.DebuggerEnabled()) { 276 if (m_system.DebuggerEnabled()) {
300 config.check_halt_on_memory_access = true; 277 config.check_halt_on_memory_access = true;
301 } 278 }
302 279
@@ -384,147 +361,112 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
384 return std::make_shared<Dynarmic::A64::Jit>(config); 361 return std::make_shared<Dynarmic::A64::Jit>(config);
385} 362}
386 363
387HaltReason ARM_Dynarmic_64::RunJit() { 364HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) {
388 return TranslateHaltReason(jit.load()->Run()); 365 m_jit->ClearExclusiveState();
389} 366 return TranslateHaltReason(m_jit->Run());
390
391HaltReason ARM_Dynarmic_64::StepJit() {
392 return TranslateHaltReason(jit.load()->Step());
393}
394
395u32 ARM_Dynarmic_64::GetSvcNumber() const {
396 return svc_swi;
397}
398
399const Kernel::DebugWatchpoint* ARM_Dynarmic_64::HaltedWatchpoint() const {
400 return halted_watchpoint;
401}
402
403void ARM_Dynarmic_64::RewindBreakpointInstruction() {
404 LoadContext(breakpoint_context);
405}
406
407ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, bool uses_wall_clock_,
408 DynarmicExclusiveMonitor& exclusive_monitor_,
409 std::size_t core_index_)
410 : ARM_Interface{system_, uses_wall_clock_},
411 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_},
412 exclusive_monitor{exclusive_monitor_}, null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {}
413
414ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
415
416void ARM_Dynarmic_64::SetPC(u64 pc) {
417 jit.load()->SetPC(pc);
418}
419
420u64 ARM_Dynarmic_64::GetPC() const {
421 return jit.load()->GetPC();
422} 367}
423 368
424u64 ARM_Dynarmic_64::GetSP() const { 369HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) {
425 return jit.load()->GetSP(); 370 m_jit->ClearExclusiveState();
371 return TranslateHaltReason(m_jit->Step());
426} 372}
427 373
428u64 ARM_Dynarmic_64::GetReg(int index) const { 374u32 ArmDynarmic64::GetSvcNumber() const {
429 return jit.load()->GetRegister(index); 375 return m_svc;
430} 376}
431 377
432void ARM_Dynarmic_64::SetReg(int index, u64 value) { 378void ArmDynarmic64::GetSvcArguments(std::span<uint64_t, 8> args) const {
433 jit.load()->SetRegister(index, value); 379 Dynarmic::A64::Jit& j = *m_jit;
434}
435 380
436u128 ARM_Dynarmic_64::GetVectorReg(int index) const { 381 for (size_t i = 0; i < 8; i++) {
437 return jit.load()->GetVector(index); 382 args[i] = j.GetRegister(i);
383 }
438} 384}
439 385
440void ARM_Dynarmic_64::SetVectorReg(int index, u128 value) { 386void ArmDynarmic64::SetSvcArguments(std::span<const uint64_t, 8> args) {
441 jit.load()->SetVector(index, value); 387 Dynarmic::A64::Jit& j = *m_jit;
442}
443 388
444u32 ARM_Dynarmic_64::GetPSTATE() const { 389 for (size_t i = 0; i < 8; i++) {
445 return jit.load()->GetPstate(); 390 j.SetRegister(i, args[i]);
391 }
446} 392}
447 393
448void ARM_Dynarmic_64::SetPSTATE(u32 pstate) { 394const Kernel::DebugWatchpoint* ArmDynarmic64::HaltedWatchpoint() const {
449 jit.load()->SetPstate(pstate); 395 return m_halted_watchpoint;
450} 396}
451 397
452u64 ARM_Dynarmic_64::GetTlsAddress() const { 398void ArmDynarmic64::RewindBreakpointInstruction() {
453 return cb->tpidrro_el0; 399 this->SetContext(m_breakpoint_context);
454} 400}
455 401
456void ARM_Dynarmic_64::SetTlsAddress(u64 address) { 402ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
457 cb->tpidrro_el0 = address; 403 DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
404 : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
405 m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} {
406 auto& page_table = process->GetPageTable().GetBasePageTable();
407 auto& page_table_impl = page_table.GetImpl();
408 m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth());
458} 409}
459 410
460u64 ARM_Dynarmic_64::GetTPIDR_EL0() const { 411ArmDynarmic64::~ArmDynarmic64() = default;
461 return cb->tpidr_el0;
462}
463 412
464void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) { 413void ArmDynarmic64::SetTpidrroEl0(u64 value) {
465 cb->tpidr_el0 = value; 414 m_cb->m_tpidrro_el0 = value;
466} 415}
467 416
468void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) const { 417void ArmDynarmic64::GetContext(Kernel::Svc::ThreadContext& ctx) const {
469 Dynarmic::A64::Jit* j = jit.load(); 418 Dynarmic::A64::Jit& j = *m_jit;
470 ctx.cpu_registers = j->GetRegisters(); 419 auto gpr = j.GetRegisters();
471 ctx.sp = j->GetSP(); 420 auto fpr = j.GetVectors();
472 ctx.pc = j->GetPC();
473 ctx.pstate = j->GetPstate();
474 ctx.vector_registers = j->GetVectors();
475 ctx.fpcr = j->GetFpcr();
476 ctx.fpsr = j->GetFpsr();
477 ctx.tpidr = cb->tpidr_el0;
478}
479 421
480void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) { 422 // TODO: this is inconvenient
481 Dynarmic::A64::Jit* j = jit.load(); 423 for (size_t i = 0; i < 29; i++) {
482 j->SetRegisters(ctx.cpu_registers); 424 ctx.r[i] = gpr[i];
483 j->SetSP(ctx.sp); 425 }
484 j->SetPC(ctx.pc); 426 ctx.fp = gpr[29];
485 j->SetPstate(ctx.pstate); 427 ctx.lr = gpr[30];
486 j->SetVectors(ctx.vector_registers); 428
487 j->SetFpcr(ctx.fpcr); 429 ctx.sp = j.GetSP();
488 j->SetFpsr(ctx.fpsr); 430 ctx.pc = j.GetPC();
489 SetTPIDR_EL0(ctx.tpidr); 431 ctx.pstate = j.GetPstate();
432 ctx.v = fpr;
433 ctx.fpcr = j.GetFpcr();
434 ctx.fpsr = j.GetFpsr();
435 ctx.tpidr = m_cb->m_tpidr_el0;
490} 436}
491 437
492void ARM_Dynarmic_64::SignalInterrupt() { 438void ArmDynarmic64::SetContext(const Kernel::Svc::ThreadContext& ctx) {
493 jit.load()->HaltExecution(BreakLoop); 439 Dynarmic::A64::Jit& j = *m_jit;
494}
495 440
496void ARM_Dynarmic_64::ClearInterrupt() { 441 // TODO: this is inconvenient
497 jit.load()->ClearHalt(BreakLoop); 442 std::array<u64, 31> gpr;
498}
499 443
500void ARM_Dynarmic_64::ClearInstructionCache() { 444 for (size_t i = 0; i < 29; i++) {
501 jit.load()->ClearCache(); 445 gpr[i] = ctx.r[i];
446 }
447 gpr[29] = ctx.fp;
448 gpr[30] = ctx.lr;
449
450 j.SetRegisters(gpr);
451 j.SetSP(ctx.sp);
452 j.SetPC(ctx.pc);
453 j.SetPstate(ctx.pstate);
454 j.SetVectors(ctx.v);
455 j.SetFpcr(ctx.fpcr);
456 j.SetFpsr(ctx.fpsr);
457 m_cb->m_tpidr_el0 = ctx.tpidr;
502} 458}
503 459
504void ARM_Dynarmic_64::InvalidateCacheRange(u64 addr, std::size_t size) { 460void ArmDynarmic64::SignalInterrupt(Kernel::KThread* thread) {
505 jit.load()->InvalidateCacheRange(addr, size); 461 m_jit->HaltExecution(BreakLoop);
506} 462}
507 463
508void ARM_Dynarmic_64::ClearExclusiveState() { 464void ArmDynarmic64::ClearInstructionCache() {
509 jit.load()->ClearExclusiveState(); 465 m_jit->ClearCache();
510} 466}
511 467
512void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table, 468void ArmDynarmic64::InvalidateCacheRange(u64 addr, std::size_t size) {
513 std::size_t new_address_space_size_in_bits) { 469 m_jit->InvalidateCacheRange(addr, size);
514 ThreadContext64 ctx{};
515 SaveContext(ctx);
516
517 auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
518 auto iter = jit_cache.find(key);
519 if (iter != jit_cache.end()) {
520 jit.store(iter->second.get());
521 LoadContext(ctx);
522 return;
523 }
524 std::shared_ptr new_jit = MakeJit(&page_table, new_address_space_size_in_bits);
525 jit.store(new_jit.get());
526 LoadContext(ctx);
527 jit_cache.emplace(key, std::move(new_jit));
528} 470}
529 471
530} // namespace Core 472} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index 2b88a08e2..4f3dd026f 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -23,76 +23,55 @@ class DynarmicCallbacks64;
23class DynarmicExclusiveMonitor; 23class DynarmicExclusiveMonitor;
24class System; 24class System;
25 25
26class ARM_Dynarmic_64 final : public ARM_Interface { 26class ArmDynarmic64 final : public ArmInterface {
27public: 27public:
28 ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, 28 ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
29 DynarmicExclusiveMonitor& exclusive_monitor_, std::size_t core_index_); 29 DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
30 ~ARM_Dynarmic_64() override; 30 ~ArmDynarmic64() override;
31
32 void SetPC(u64 pc) override;
33 u64 GetPC() const override;
34 u64 GetSP() const override;
35 u64 GetReg(int index) const override;
36 void SetReg(int index, u64 value) override;
37 u128 GetVectorReg(int index) const override;
38 void SetVectorReg(int index, u128 value) override;
39 u32 GetPSTATE() const override;
40 void SetPSTATE(u32 pstate) override;
41 u64 GetTlsAddress() const override;
42 void SetTlsAddress(u64 address) override;
43 void SetTPIDR_EL0(u64 value) override;
44 u64 GetTPIDR_EL0() const override;
45 31
46 Architecture GetArchitecture() const override { 32 Architecture GetArchitecture() const override {
47 return Architecture::Aarch64; 33 return Architecture::AArch64;
48 } 34 }
49 void SaveContext(ThreadContext32& ctx) const override {}
50 void SaveContext(ThreadContext64& ctx) const override;
51 void LoadContext(const ThreadContext32& ctx) override {}
52 void LoadContext(const ThreadContext64& ctx) override;
53 35
54 void SignalInterrupt() override; 36 HaltReason RunThread(Kernel::KThread* thread) override;
55 void ClearInterrupt() override; 37 HaltReason StepThread(Kernel::KThread* thread) override;
56 void ClearExclusiveState() override;
57 38
39 void GetContext(Kernel::Svc::ThreadContext& ctx) const override;
40 void SetContext(const Kernel::Svc::ThreadContext& ctx) override;
41 void SetTpidrroEl0(u64 value) override;
42
43 void GetSvcArguments(std::span<uint64_t, 8> args) const override;
44 void SetSvcArguments(std::span<const uint64_t, 8> args) override;
45 u32 GetSvcNumber() const override;
46
47 void SignalInterrupt(Kernel::KThread* thread) override;
58 void ClearInstructionCache() override; 48 void ClearInstructionCache() override;
59 void InvalidateCacheRange(u64 addr, std::size_t size) override; 49 void InvalidateCacheRange(u64 addr, std::size_t size) override;
60 void PageTableChanged(Common::PageTable& new_page_table,
61 std::size_t new_address_space_size_in_bits) override;
62 50
63protected: 51protected:
64 HaltReason RunJit() override;
65 HaltReason StepJit() override;
66 u32 GetSvcNumber() const override;
67 const Kernel::DebugWatchpoint* HaltedWatchpoint() const override; 52 const Kernel::DebugWatchpoint* HaltedWatchpoint() const override;
68 void RewindBreakpointInstruction() override; 53 void RewindBreakpointInstruction() override;
69 54
70private: 55private:
71 std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, 56 System& m_system;
72 std::size_t address_space_bits) const; 57 DynarmicExclusiveMonitor& m_exclusive_monitor;
73
74 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
75 using JitCacheType =
76 std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A64::Jit>, Common::PairHash>;
77 58
59private:
78 friend class DynarmicCallbacks64; 60 friend class DynarmicCallbacks64;
79 std::unique_ptr<DynarmicCallbacks64> cb;
80 JitCacheType jit_cache;
81
82 std::size_t core_index;
83 DynarmicExclusiveMonitor& exclusive_monitor;
84 61
85 std::shared_ptr<Dynarmic::A64::Jit> null_jit; 62 std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table,
63 std::size_t address_space_bits) const;
64 std::unique_ptr<DynarmicCallbacks64> m_cb{};
65 std::size_t m_core_index{};
86 66
87 // A raw pointer here is fine; we never delete Jit instances. 67 std::shared_ptr<Dynarmic::A64::Jit> m_jit{};
88 std::atomic<Dynarmic::A64::Jit*> jit;
89 68
90 // SVC callback 69 // SVC callback
91 u32 svc_swi{}; 70 u32 m_svc{};
92 71
93 // Breakpoint info 72 // Watchpoint info
94 const Kernel::DebugWatchpoint* halted_watchpoint; 73 const Kernel::DebugWatchpoint* m_halted_watchpoint{};
95 ThreadContext64 breakpoint_context; 74 Kernel::Svc::ThreadContext m_breakpoint_context{};
96}; 75};
97 76
98} // namespace Core 77} // namespace Core
diff --git a/src/core/arm/dynarmic/dynarmic_cp15.cpp b/src/core/arm/dynarmic/dynarmic_cp15.cpp
index 92c548db0..f3eee0d42 100644
--- a/src/core/arm/dynarmic/dynarmic_cp15.cpp
+++ b/src/core/arm/dynarmic/dynarmic_cp15.cpp
@@ -124,8 +124,8 @@ CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc
124 if (!two && opc == 0 && CRm == CoprocReg::C14) { 124 if (!two && opc == 0 && CRm == CoprocReg::C14) {
125 // CNTPCT 125 // CNTPCT
126 const auto callback = [](void* arg, u32, u32) -> u64 { 126 const auto callback = [](void* arg, u32, u32) -> u64 {
127 const auto& parent_arg = *static_cast<ARM_Dynarmic_32*>(arg); 127 const auto& parent_arg = *static_cast<ArmDynarmic32*>(arg);
128 return parent_arg.system.CoreTiming().GetClockTicks(); 128 return parent_arg.m_system.CoreTiming().GetClockTicks();
129 }; 129 };
130 return Callback{callback, &parent}; 130 return Callback{callback, &parent};
131 } 131 }
diff --git a/src/core/arm/dynarmic/dynarmic_cp15.h b/src/core/arm/dynarmic/dynarmic_cp15.h
index d90b3e568..f3d96b0d8 100644
--- a/src/core/arm/dynarmic/dynarmic_cp15.h
+++ b/src/core/arm/dynarmic/dynarmic_cp15.h
@@ -10,13 +10,13 @@
10 10
11namespace Core { 11namespace Core {
12 12
13class ARM_Dynarmic_32; 13class ArmDynarmic32;
14 14
15class DynarmicCP15 final : public Dynarmic::A32::Coprocessor { 15class DynarmicCP15 final : public Dynarmic::A32::Coprocessor {
16public: 16public:
17 using CoprocReg = Dynarmic::A32::CoprocReg; 17 using CoprocReg = Dynarmic::A32::CoprocReg;
18 18
19 explicit DynarmicCP15(ARM_Dynarmic_32& parent_) : parent{parent_} {} 19 explicit DynarmicCP15(ArmDynarmic32& parent_) : parent{parent_} {}
20 20
21 std::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, 21 std::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd,
22 CoprocReg CRn, CoprocReg CRm, 22 CoprocReg CRn, CoprocReg CRm,
@@ -32,11 +32,11 @@ public:
32 std::optional<Callback> CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, 32 std::optional<Callback> CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd,
33 std::optional<u8> option) override; 33 std::optional<u8> option) override;
34 34
35 ARM_Dynarmic_32& parent; 35 ArmDynarmic32& parent;
36 u32 uprw = 0; 36 u32 uprw = 0;
37 u32 uro = 0; 37 u32 uro = 0;
38 38
39 friend class ARM_Dynarmic_32; 39 friend class ArmDynarmic32;
40}; 40};
41 41
42} // namespace Core 42} // namespace Core
diff --git a/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h
index fbfcd8d95..c4f22ec89 100644
--- a/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h
+++ b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h
@@ -14,8 +14,8 @@ class Memory;
14 14
15namespace Core { 15namespace Core {
16 16
17class ARM_Dynarmic_32; 17class ArmDynarmic32;
18class ARM_Dynarmic_64; 18class ArmDynarmic64;
19 19
20class DynarmicExclusiveMonitor final : public ExclusiveMonitor { 20class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
21public: 21public:
@@ -36,8 +36,8 @@ public:
36 bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) override; 36 bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) override;
37 37
38private: 38private:
39 friend class ARM_Dynarmic_32; 39 friend class ArmDynarmic32;
40 friend class ARM_Dynarmic_64; 40 friend class ArmDynarmic64;
41 Dynarmic::ExclusiveMonitor monitor; 41 Dynarmic::ExclusiveMonitor monitor;
42 Core::Memory::Memory& memory; 42 Core::Memory::Memory& memory;
43}; 43};