diff --git a/externals/dynarmic b/externals/dynarmic
index 4b350a354a..68ca03e8d4 160000
--- a/externals/dynarmic
+++ b/externals/dynarmic
@@ -1 +1 @@
-Subproject commit 4b350a354a21339052c7fff88832c3f81f5624be
+Subproject commit 68ca03e8d4822c78e15315e67ddbb1d6bf4d3827
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 461f1e564f..c1bde8cbf2 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -3,8 +3,8 @@
 // Refer to the license.txt file included.
 
 #include <cstring>
-#include <dynarmic/context.h>
-#include <dynarmic/dynarmic.h>
+#include <dynarmic/A32/a32.h>
+#include <dynarmic/A32/context.h>
 #include "common/assert.h"
 #include "common/microprofile.h"
 #include "core/arm/dynarmic/arm_dynarmic.h"
@@ -64,86 +64,101 @@ public:
 private:
     friend class ARM_Dynarmic;
 
-    Dynarmic::Context ctx;
+    Dynarmic::A32::Context ctx;
     u32 fpexc;
 };
 
-static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void* user_arg) {
-    ARMul_State* state = static_cast<ARMul_State*>(user_arg);
+class DynarmicUserCallbacks final : public Dynarmic::A32::UserCallbacks {
+public:
+    explicit DynarmicUserCallbacks(ARM_Dynarmic& parent) : parent(parent) {}
+    ~DynarmicUserCallbacks() = default;
 
-    state->Reg = jit->Regs();
-    state->Cpsr = jit->Cpsr();
-    state->Reg[15] = pc;
-    state->ExtReg = jit->ExtRegs();
-    state->VFP[VFP_FPSCR] = jit->Fpscr();
-    state->NumInstrsToExecute = 1;
+    std::uint8_t MemoryRead8(VAddr vaddr) override {
+        return Memory::Read8(vaddr);
+    }
+    std::uint16_t MemoryRead16(VAddr vaddr) override {
+        return Memory::Read16(vaddr);
+    }
+    std::uint32_t MemoryRead32(VAddr vaddr) override {
+        return Memory::Read32(vaddr);
+    }
+    std::uint64_t MemoryRead64(VAddr vaddr) override {
+        return Memory::Read64(vaddr);
+    }
 
-    InterpreterMainLoop(state);
+    void MemoryWrite8(VAddr vaddr, std::uint8_t value) override {
+        Memory::Write8(vaddr, value);
+    }
+    void MemoryWrite16(VAddr vaddr, std::uint16_t value) override {
+        Memory::Write16(vaddr, value);
+    }
+    void MemoryWrite32(VAddr vaddr, std::uint32_t value) override {
+        Memory::Write32(vaddr, value);
+    }
+    void MemoryWrite64(VAddr vaddr, std::uint64_t value) override {
+        Memory::Write64(vaddr, value);
+    }
 
-    bool is_thumb = (state->Cpsr & (1 << 5)) != 0;
-    state->Reg[15] &= (is_thumb ? 0xFFFFFFFE : 0xFFFFFFFC);
+    void InterpreterFallback(VAddr pc, size_t num_instructions) override {
+        parent.interpreter_state->Reg = parent.jit->Regs();
+        parent.interpreter_state->Cpsr = parent.jit->Cpsr();
+        parent.interpreter_state->Reg[15] = pc;
+        parent.interpreter_state->ExtReg = parent.jit->ExtRegs();
+        parent.interpreter_state->VFP[VFP_FPSCR] = parent.jit->Fpscr();
+        parent.interpreter_state->NumInstrsToExecute = num_instructions;
 
-    jit->Regs() = state->Reg;
-    jit->SetCpsr(state->Cpsr);
-    jit->ExtRegs() = state->ExtReg;
-    jit->SetFpscr(state->VFP[VFP_FPSCR]);
+        InterpreterMainLoop(parent.interpreter_state.get());
 
-    state->ServeBreak();
-}
+        bool is_thumb = (parent.interpreter_state->Cpsr & (1 << 5)) != 0;
+        parent.interpreter_state->Reg[15] &= (is_thumb ? 0xFFFFFFFE : 0xFFFFFFFC);
 
-static bool IsReadOnlyMemory(u32 vaddr) {
-    // TODO(bunnei): ImplementMe
-    return false;
-}
+        parent.jit->Regs() = parent.interpreter_state->Reg;
+        parent.jit->SetCpsr(parent.interpreter_state->Cpsr);
+        parent.jit->ExtRegs() = parent.interpreter_state->ExtReg;
+        parent.jit->SetFpscr(parent.interpreter_state->VFP[VFP_FPSCR]);
 
-static void AddTicks(u64 ticks) {
-    CoreTiming::AddTicks(ticks);
-}
+        parent.interpreter_state->ServeBreak();
+    }
 
-static u64 GetTicksRemaining() {
-    s64 ticks = CoreTiming::GetDowncount();
-    return static_cast<u64>(ticks <= 0 ? 0 : ticks);
-}
+    void CallSVC(std::uint32_t swi) override {
+        Kernel::CallSVC(swi);
+    }
 
-static Dynarmic::UserCallbacks GetUserCallbacks(
-    const std::shared_ptr<ARMul_State>& interpreter_state, Memory::PageTable* current_page_table) {
-    Dynarmic::UserCallbacks user_callbacks{};
-    user_callbacks.InterpreterFallback = &InterpreterFallback;
-    user_callbacks.user_arg = static_cast<void*>(interpreter_state.get());
-    user_callbacks.CallSVC = &Kernel::CallSVC;
-    user_callbacks.memory.IsReadOnlyMemory = &IsReadOnlyMemory;
-    user_callbacks.memory.ReadCode = &Memory::Read32;
-    user_callbacks.memory.Read8 = &Memory::Read8;
-    user_callbacks.memory.Read16 = &Memory::Read16;
-    user_callbacks.memory.Read32 = &Memory::Read32;
-    user_callbacks.memory.Read64 = &Memory::Read64;
-    user_callbacks.memory.Write8 = &Memory::Write8;
-    user_callbacks.memory.Write16 = &Memory::Write16;
-    user_callbacks.memory.Write32 = &Memory::Write32;
-    user_callbacks.memory.Write64 = &Memory::Write64;
-    user_callbacks.AddTicks = &AddTicks;
-    user_callbacks.GetTicksRemaining = &GetTicksRemaining;
-    user_callbacks.page_table = &current_page_table->pointers;
-    user_callbacks.coprocessors[15] = std::make_shared<DynarmicCP15>(interpreter_state);
-    return user_callbacks;
-}
+    void ExceptionRaised(VAddr pc, Dynarmic::A32::Exception exception) override {
+        ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:X})",
+                   static_cast<size_t>(exception), pc);
+    }
 
-ARM_Dynarmic::ARM_Dynarmic(PrivilegeMode initial_mode) {
+    void AddTicks(std::uint64_t ticks) override {
+        CoreTiming::AddTicks(ticks);
+    }
+    std::uint64_t GetTicksRemaining() override {
+        s64 ticks = CoreTiming::GetDowncount();
+        return static_cast<u64>(ticks <= 0 ? 0 : ticks);
+    }
+
+    ARM_Dynarmic& parent;
+};
+
+ARM_Dynarmic::ARM_Dynarmic(PrivilegeMode initial_mode)
+    : cb(std::make_unique<DynarmicUserCallbacks>(*this)) {
     interpreter_state = std::make_shared<ARMul_State>(initial_mode);
     PageTableChanged();
 }
 
+ARM_Dynarmic::~ARM_Dynarmic() = default;
+
 MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64));
 
 void ARM_Dynarmic::Run() {
     ASSERT(Memory::GetCurrentPageTable() == current_page_table);
     MICROPROFILE_SCOPE(ARM_Jit);
 
-    jit->Run(GetTicksRemaining());
+    jit->Run();
 }
 
 void ARM_Dynarmic::Step() {
-    InterpreterFallback(jit->Regs()[15], jit, static_cast<void*>(interpreter_state.get()));
+    cb->InterpreterFallback(jit->Regs()[15], 1);
 }
 
 void ARM_Dynarmic::SetPC(u32 pc) {
@@ -251,6 +266,16 @@ void ARM_Dynarmic::PageTableChanged() {
         return;
     }
 
-    jit = new Dynarmic::Jit(GetUserCallbacks(interpreter_state, current_page_table));
-    jits.emplace(current_page_table, std::unique_ptr<Dynarmic::Jit>(jit));
+    auto new_jit = MakeJit();
+    jit = new_jit.get();
+    jits.emplace(current_page_table, std::move(new_jit));
+}
+
+std::unique_ptr<Dynarmic::A32::Jit> ARM_Dynarmic::MakeJit() {
+    Dynarmic::A32::UserConfig config;
+    config.callbacks = cb.get();
+    config.page_table = &current_page_table->pointers;
+    config.coprocessors[15] = std::make_shared<DynarmicCP15>(interpreter_state);
+    config.define_unpredictable_behaviour = true;
+    return std::make_unique<Dynarmic::A32::Jit>(config);
 }
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index fa3023cb9d..f8c395d0f7 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -6,7 +6,7 @@
 
 #include <map>
 #include <memory>
-#include <dynarmic/dynarmic.h>
+#include <dynarmic/A32/a32.h>
 #include "common/common_types.h"
 #include "core/arm/arm_interface.h"
 #include "core/arm/skyeye_common/armstate.h"
@@ -15,9 +15,12 @@ namespace Memory {
 struct PageTable;
 } // namespace Memory
 
+class DynarmicUserCallbacks;
+
 class ARM_Dynarmic final : public ARM_Interface {
 public:
     explicit ARM_Dynarmic(PrivilegeMode initial_mode);
+    ~ARM_Dynarmic();
 
     void Run() override;
     void Step() override;
@@ -46,8 +49,12 @@ public:
     void PageTableChanged() override;
 
 private:
-    Dynarmic::Jit* jit = nullptr;
+    friend class DynarmicUserCallbacks;
+    std::unique_ptr<DynarmicUserCallbacks> cb;
+    std::unique_ptr<Dynarmic::A32::Jit> MakeJit();
+
+    Dynarmic::A32::Jit* jit = nullptr;
     Memory::PageTable* current_page_table = nullptr;
-    std::map<Memory::PageTable*, std::unique_ptr<Dynarmic::Jit>> jits;
+    std::map<Memory::PageTable*, std::unique_ptr<Dynarmic::A32::Jit>> jits;
     std::shared_ptr<ARMul_State> interpreter_state;
 };
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
index b1fdce0962..119aefac7d 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
@@ -6,9 +6,9 @@
 #include "core/arm/skyeye_common/arm_regformat.h"
 #include "core/arm/skyeye_common/armstate.h"
 
-using Callback = Dynarmic::Coprocessor::Callback;
-using CallbackOrAccessOneWord = Dynarmic::Coprocessor::CallbackOrAccessOneWord;
-using CallbackOrAccessTwoWords = Dynarmic::Coprocessor::CallbackOrAccessTwoWords;
+using Callback = Dynarmic::A32::Coprocessor::Callback;
+using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord;
+using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords;
 
 DynarmicCP15::DynarmicCP15(const std::shared_ptr<ARMul_State>& state) : interpreter_state(state) {}
 
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
index 1d270870c9..66740ea71a 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
@@ -5,13 +5,15 @@
 #pragma once
 
 #include <memory>
-#include <dynarmic/coprocessor.h>
+#include <dynarmic/A32/coprocessor.h>
 #include "common/common_types.h"
 
 struct ARMul_State;
 
-class DynarmicCP15 final : public Dynarmic::Coprocessor {
+class DynarmicCP15 final : public Dynarmic::A32::Coprocessor {
 public:
+    using CoprocReg = Dynarmic::A32::CoprocReg;
+
     explicit DynarmicCP15(const std::shared_ptr<ARMul_State>&);
     ~DynarmicCP15() override;