diff --git a/.gitmodules b/.gitmodules
index 1f0b80768b..f498a60de5 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,15 +1,18 @@
 [submodule "inih"]
-	path = externals/inih/inih
-	url = https://github.com/svn2github/inih
+    path = externals/inih/inih
+    url = https://github.com/svn2github/inih
 [submodule "boost"]
-	path = externals/boost
-	url = https://github.com/citra-emu/ext-boost.git
+    path = externals/boost
+    url = https://github.com/citra-emu/ext-boost.git
 [submodule "nihstro"]
-	path = externals/nihstro
-	url = https://github.com/neobrain/nihstro.git
+    path = externals/nihstro
+    url = https://github.com/neobrain/nihstro.git
 [submodule "soundtouch"]
-	path = externals/soundtouch
-	url = https://github.com/citra-emu/ext-soundtouch.git
+    path = externals/soundtouch
+    url = https://github.com/citra-emu/ext-soundtouch.git
 [submodule "catch"]
-	path = externals/catch
-	url = https://github.com/philsquared/Catch.git
+    path = externals/catch
+    url = https://github.com/philsquared/Catch.git
+[submodule "dynarmic"]
+    path = externals/dynarmic
+    url = https://github.com/MerryMage/dynarmic.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6ac3df0e0c..c7a24f04fc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -118,12 +118,11 @@ else()
 endif()
 
 find_package(Boost 1.57.0 QUIET)
-if (Boost_FOUND)
-    include_directories(${Boost_INCLUDE_DIRS})
-else()
+if (NOT Boost_FOUND)
     message(STATUS "Boost 1.57.0 or newer not found, falling back to externals")
-    include_directories(externals/boost)
+    set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost")
 endif()
+include_directories(${Boost_INCLUDE_DIR})
 
 # Include bundled CMake modules
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/externals/cmake-modules")
@@ -227,6 +226,9 @@ set(INI_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/externals/inih")
 include_directories(${INI_PREFIX})
 add_subdirectory(${INI_PREFIX})
 
+option(DYNARMIC_TESTS OFF)
+add_subdirectory(externals/dynarmic)
+
 add_subdirectory(externals/glad)
 include_directories(externals/microprofile)
 include_directories(externals/nihstro/include)
diff --git a/externals/boost b/externals/boost
index 2dcb9d9796..f005c955f8 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit 2dcb9d979665b6aabb1635c617973e02914e60ec
+Subproject commit f005c955f8147a29667aa0b65257abc3dd520b0c
diff --git a/externals/dynarmic b/externals/dynarmic
new file mode 160000
index 0000000000..943487ecee
--- /dev/null
+++ b/externals/dynarmic
@@ -0,0 +1 @@
+Subproject commit 943487eceed82fbae016c333dc9fe33981e69aa8
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index 110b883fb4..1a09f0e551 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -65,6 +65,7 @@ void Config::ReadValues() {
     Settings::values.pad_circle_modifier_scale = (float)sdl2_config->GetReal("Controls", "pad_circle_modifier_scale", 0.5);
 
     // Core
+    Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true);
     Settings::values.frame_skip = sdl2_config->GetInteger("Core", "frame_skip", 0);
 
     // Renderer
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index 2031620a5f..7881745085 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -38,6 +38,10 @@ pad_circle_modifier =
 pad_circle_modifier_scale =
 
 [Core]
+# Whether to use the Just-In-Time (JIT) compiler for CPU emulation
+# 0: Interpreter (slow), 1 (default): JIT (fast)
+use_cpu_jit =
+
 # The applied frameskip amount. Must be a power of two.
 # 0 (default): No frameskip, 1: x2 frameskip, 2: x4 frameskip, 3: x8 frameskip, etc.
 frame_skip =
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index fa3fa210c7..cf1c09930c 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -41,6 +41,7 @@ void Config::ReadValues() {
     qt_config->endGroup();
 
     qt_config->beginGroup("Core");
+    Settings::values.use_cpu_jit = qt_config->value("use_cpu_jit", true).toBool();
     Settings::values.frame_skip = qt_config->value("frame_skip", 0).toInt();
     qt_config->endGroup();
 
@@ -134,6 +135,7 @@ void Config::SaveValues() {
     qt_config->endGroup();
 
     qt_config->beginGroup("Core");
+    qt_config->setValue("use_cpu_jit", Settings::values.use_cpu_jit);
     qt_config->setValue("frame_skip", Settings::values.frame_skip);
     qt_config->endGroup();
 
diff --git a/src/citra_qt/configure_general.cpp b/src/citra_qt/configure_general.cpp
index 95aab9f2eb..e6832341ab 100644
--- a/src/citra_qt/configure_general.cpp
+++ b/src/citra_qt/configure_general.cpp
@@ -7,6 +7,7 @@
 #include "ui_configure_general.h"
 
 #include "core/settings.h"
+#include "core/system.h"
 
 ConfigureGeneral::ConfigureGeneral(QWidget *parent) :
     QWidget(parent),
@@ -14,6 +15,8 @@ ConfigureGeneral::ConfigureGeneral(QWidget *parent) :
 {
     ui->setupUi(this);
     this->setConfiguration();
+
+    ui->toggle_cpu_jit->setEnabled(!System::IsPoweredOn());
 }
 
 ConfigureGeneral::~ConfigureGeneral() {
@@ -22,6 +25,7 @@ ConfigureGeneral::~ConfigureGeneral() {
 void ConfigureGeneral::setConfiguration() {
     ui->toggle_deepscan->setChecked(UISettings::values.gamedir_deepscan);
     ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
+    ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit);
     ui->region_combobox->setCurrentIndex(Settings::values.region_value);
 }
 
@@ -29,5 +33,6 @@ void ConfigureGeneral::applyConfiguration() {
     UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked();
     UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
     Settings::values.region_value = ui->region_combobox->currentIndex();
+    Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked();
     Settings::Apply();
 }
diff --git a/src/citra_qt/configure_general.ui b/src/citra_qt/configure_general.ui
index 343f804c00..81688113f2 100644
--- a/src/citra_qt/configure_general.ui
+++ b/src/citra_qt/configure_general.ui
@@ -43,6 +43,26 @@
        </layout>
       </widget>
      </item>
+      <item>
+        <widget class="QGroupBox" name="groupBox_2">
+          <property name="title">
+            <string>Performance</string>
+          </property>
+          <layout class="QHBoxLayout" name="horizontalLayout_7">
+            <item>
+              <layout class="QVBoxLayout" name="verticalLayout_5">
+                <item>
+                  <widget class="QCheckBox" name="toggle_cpu_jit">
+                    <property name="text">
+                      <string>Enable CPU JIT</string>
+                    </property>
+                  </widget>
+                </item>
+              </layout>
+            </item>
+          </layout>
+        </widget>
+      </item>
      <item>
       <widget class="QGroupBox" name="groupBox_4">
        <property name="title">
diff --git a/src/common/microprofile.h b/src/common/microprofile.h
index ef312c6e18..670a58fe57 100644
--- a/src/common/microprofile.h
+++ b/src/common/microprofile.h
@@ -13,7 +13,7 @@
 #define MICROPROFILE_WEBSERVER 0
 #define MICROPROFILE_GPU_TIMERS 0 // TODO: Implement timer queries when we upgrade to OpenGL 3.3
 #define MICROPROFILE_CONTEXT_SWITCH_TRACE 0
-#define MICROPROFILE_PER_THREAD_BUFFER_SIZE (2048<<12) // 8 MB
+#define MICROPROFILE_PER_THREAD_BUFFER_SIZE (2048<<13) // 16 MB
 
 #ifdef _WIN32
 // This isn't defined by the standard library in MSVC2015
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 174e9dc794..4a9c6fd2fe 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -1,6 +1,7 @@
 set(SRCS
             arm/disassembler/arm_disasm.cpp
             arm/disassembler/load_symbol_map.cpp
+            arm/dynarmic/arm_dynarmic.cpp
             arm/dyncom/arm_dyncom.cpp
             arm/dyncom/arm_dyncom_dec.cpp
             arm/dyncom/arm_dyncom_interpreter.cpp
@@ -141,6 +142,7 @@ set(HEADERS
             arm/arm_interface.h
             arm/disassembler/arm_disasm.h
             arm/disassembler/load_symbol_map.h
+            arm/dynarmic/arm_dynarmic.h
             arm/dyncom/arm_dyncom.h
             arm/dyncom/arm_dyncom_dec.h
             arm/dyncom/arm_dyncom_interpreter.h
@@ -285,6 +287,10 @@ set(HEADERS
             system.h
             )
 
+include_directories(../../externals/dynarmic/include)
+
 create_directory_groups(${SRCS} ${HEADERS})
 
 add_library(core STATIC ${SRCS} ${HEADERS})
+
+target_link_libraries(core dynarmic)
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index de5e9c8fac..480c90e660 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -121,15 +121,6 @@ public:
      */
     virtual void AddTicks(u64 ticks) = 0;
 
-    /**
-     * Initializes a CPU context for use on this CPU
-     * @param context Thread context to reset
-     * @param stack_top Pointer to the top of the stack
-     * @param entry_point Entry point for execution
-     * @param arg User argument for thread
-     */
-    virtual void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) = 0;
-
     /**
      * Saves the current CPU context
      * @param ctx Thread context to save
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
new file mode 100644
index 0000000000..a521aec7ce
--- /dev/null
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -0,0 +1,174 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/microprofile.h"
+
+#include <dynarmic/dynarmic.h>
+
+#include "core/arm/dynarmic/arm_dynarmic.h"
+#include "core/arm/dyncom/arm_dyncom_interpreter.h"
+#include "core/core.h"
+#include "core/core_timing.h"
+#include "core/hle/svc.h"
+#include "core/memory.h"
+
+static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void* user_arg) {
+    ARMul_State* state = static_cast<ARMul_State*>(user_arg);
+
+    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;
+
+    InterpreterMainLoop(state);
+
+    bool is_thumb = (state->Cpsr & (1 << 5)) != 0;
+    state->Reg[15] &= (is_thumb ? 0xFFFFFFFE : 0xFFFFFFFC);
+
+    jit->Regs() = state->Reg;
+    jit->Cpsr() = state->Cpsr;
+    jit->ExtRegs() = state->ExtReg;
+    jit->SetFpscr(state->VFP[VFP_FPSCR]);
+}
+
+static bool IsReadOnlyMemory(u32 vaddr) {
+    // TODO(bunnei): ImplementMe
+    return false;
+}
+
+static Dynarmic::UserCallbacks GetUserCallbacks(ARMul_State* interpeter_state) {
+    Dynarmic::UserCallbacks user_callbacks{};
+    user_callbacks.InterpreterFallback = &InterpreterFallback;
+    user_callbacks.user_arg = static_cast<void*>(interpeter_state);
+    user_callbacks.CallSVC = &SVC::CallSVC;
+    user_callbacks.IsReadOnlyMemory = &IsReadOnlyMemory;
+    user_callbacks.MemoryRead8 = &Memory::Read8;
+    user_callbacks.MemoryRead16 = &Memory::Read16;
+    user_callbacks.MemoryRead32 = &Memory::Read32;
+    user_callbacks.MemoryRead64 = &Memory::Read64;
+    user_callbacks.MemoryWrite8 = &Memory::Write8;
+    user_callbacks.MemoryWrite16 = &Memory::Write16;
+    user_callbacks.MemoryWrite32 = &Memory::Write32;
+    user_callbacks.MemoryWrite64 = &Memory::Write64;
+    return user_callbacks;
+}
+
+ARM_Dynarmic::ARM_Dynarmic(PrivilegeMode initial_mode) {
+    interpreter_state = std::make_unique<ARMul_State>(initial_mode);
+    jit = std::make_unique<Dynarmic::Jit>(GetUserCallbacks(interpreter_state.get()));
+}
+
+void ARM_Dynarmic::SetPC(u32 pc) {
+    jit->Regs()[15] = pc;
+}
+
+u32 ARM_Dynarmic::GetPC() const {
+    return jit->Regs()[15];
+}
+
+u32 ARM_Dynarmic::GetReg(int index) const {
+    return jit->Regs()[index];
+}
+
+void ARM_Dynarmic::SetReg(int index, u32 value) {
+    jit->Regs()[index] = value;
+}
+
+u32 ARM_Dynarmic::GetVFPReg(int index) const {
+    return jit->ExtRegs()[index];
+}
+
+void ARM_Dynarmic::SetVFPReg(int index, u32 value) {
+    jit->ExtRegs()[index] = value;
+}
+
+u32 ARM_Dynarmic::GetVFPSystemReg(VFPSystemRegister reg) const {
+    if (reg == VFP_FPSCR) {
+        return jit->Fpscr();
+    }
+
+    // Dynarmic does not implement and/or expose other VFP registers, fallback to interpreter state
+    return interpreter_state->VFP[reg];
+}
+
+void ARM_Dynarmic::SetVFPSystemReg(VFPSystemRegister reg, u32 value) {
+    if (reg == VFP_FPSCR) {
+        jit->SetFpscr(value);
+    }
+
+    // Dynarmic does not implement and/or expose other VFP registers, fallback to interpreter state
+    interpreter_state->VFP[reg] = value;
+}
+
+u32 ARM_Dynarmic::GetCPSR() const {
+    return jit->Cpsr();
+}
+
+void ARM_Dynarmic::SetCPSR(u32 cpsr) {
+    jit->Cpsr() = cpsr;
+}
+
+u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) {
+    return interpreter_state->CP15[reg];
+}
+
+void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) {
+    interpreter_state->CP15[reg] = value;
+}
+
+void ARM_Dynarmic::AddTicks(u64 ticks) {
+    down_count -= ticks;
+    if (down_count < 0) {
+        CoreTiming::Advance();
+    }
+}
+
+MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64));
+
+void ARM_Dynarmic::ExecuteInstructions(int num_instructions) {
+    MICROPROFILE_SCOPE(ARM_Jit);
+
+    jit->Run(static_cast<unsigned>(num_instructions));
+
+    AddTicks(num_instructions);
+}
+
+void ARM_Dynarmic::SaveContext(Core::ThreadContext& ctx) {
+    memcpy(ctx.cpu_registers, jit->Regs().data(), sizeof(ctx.cpu_registers));
+    memcpy(ctx.fpu_registers, jit->ExtRegs().data(), sizeof(ctx.fpu_registers));
+
+    ctx.sp = jit->Regs()[13];
+    ctx.lr = jit->Regs()[14];
+    ctx.pc = jit->Regs()[15];
+    ctx.cpsr = jit->Cpsr();
+
+    ctx.fpscr = jit->Fpscr();
+    ctx.fpexc = interpreter_state->VFP[VFP_FPEXC];
+}
+
+void ARM_Dynarmic::LoadContext(const Core::ThreadContext& ctx) {
+    memcpy(jit->Regs().data(), ctx.cpu_registers, sizeof(ctx.cpu_registers));
+    memcpy(jit->ExtRegs().data(), ctx.fpu_registers, sizeof(ctx.fpu_registers));
+
+    jit->Regs()[13] = ctx.sp;
+    jit->Regs()[14] = ctx.lr;
+    jit->Regs()[15] = ctx.pc;
+    jit->Cpsr() = ctx.cpsr;
+
+    jit->SetFpscr(ctx.fpscr);
+    interpreter_state->VFP[VFP_FPEXC] = ctx.fpexc;
+}
+
+void ARM_Dynarmic::PrepareReschedule() {
+    if (jit->IsExecuting()) {
+        jit->HaltExecution();
+    }
+}
+
+void ARM_Dynarmic::ClearInstructionCache() {
+    jit->ClearCache();
+}
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
new file mode 100644
index 0000000000..d493cabd53
--- /dev/null
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -0,0 +1,50 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+
+#include <dynarmic/dynarmic.h>
+
+#include "common/common_types.h"
+
+#include "core/arm/arm_interface.h"
+#include "core/arm/skyeye_common/armstate.h"
+
+namespace Core {
+struct ThreadContext;
+}
+
+class ARM_Dynarmic final : public ARM_Interface {
+public:
+    ARM_Dynarmic(PrivilegeMode initial_mode);
+
+    void SetPC(u32 pc) override;
+    u32 GetPC() const override;
+    u32 GetReg(int index) const override;
+    void SetReg(int index, u32 value) override;
+    u32 GetVFPReg(int index) const override;
+    void SetVFPReg(int index, u32 value) override;
+    u32 GetVFPSystemReg(VFPSystemRegister reg) const override;
+    void SetVFPSystemReg(VFPSystemRegister reg, u32 value) override;
+    u32 GetCPSR() const override;
+    void SetCPSR(u32 cpsr) override;
+    u32 GetCP15Register(CP15Register reg) override;
+    void SetCP15Register(CP15Register reg, u32 value) override;
+
+    void AddTicks(u64 ticks) override;
+
+    void SaveContext(Core::ThreadContext& ctx) override;
+    void LoadContext(const Core::ThreadContext& ctx) override;
+
+    void PrepareReschedule() override;
+    void ExecuteInstructions(int num_instructions) override;
+
+    void ClearInstructionCache() override;
+
+private:
+    std::unique_ptr<Dynarmic::Jit> jit;
+    std::unique_ptr<ARMul_State> interpreter_state;
+};
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index ab77da9657..d849175296 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -93,15 +93,6 @@ void ARM_DynCom::ExecuteInstructions(int num_instructions) {
     AddTicks(ticks_executed);
 }
 
-void ARM_DynCom::ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) {
-    memset(&context, 0, sizeof(Core::ThreadContext));
-
-    context.cpu_registers[0] = arg;
-    context.pc = entry_point;
-    context.sp = stack_top;
-    context.cpsr = USER32MODE | ((entry_point & 1) << 5); // Usermode and THUMB mode
-}
-
 void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
     memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers));
     memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers));
@@ -111,8 +102,8 @@ void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
     ctx.pc = state->Reg[15];
     ctx.cpsr = state->Cpsr;
 
-    ctx.fpscr = state->VFP[1];
-    ctx.fpexc = state->VFP[2];
+    ctx.fpscr = state->VFP[VFP_FPSCR];
+    ctx.fpexc = state->VFP[VFP_FPEXC];
 }
 
 void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) {
@@ -124,8 +115,8 @@ void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) {
     state->Reg[15] = ctx.pc;
     state->Cpsr = ctx.cpsr;
 
-    state->VFP[1] = ctx.fpscr;
-    state->VFP[2] = ctx.fpexc;
+    state->VFP[VFP_FPSCR] = ctx.fpscr;
+    state->VFP[VFP_FPEXC] = ctx.fpexc;
 }
 
 void ARM_DynCom::PrepareReschedule() {
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index e763abc24d..70f71a8280 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -16,7 +16,7 @@ namespace Core {
 struct ThreadContext;
 }
 
-class ARM_DynCom final : virtual public ARM_Interface {
+class ARM_DynCom final : public ARM_Interface {
 public:
     ARM_DynCom(PrivilegeMode initial_mode);
     ~ARM_DynCom();
@@ -38,7 +38,6 @@ public:
 
     void AddTicks(u64 ticks) override;
 
-    void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) override;
     void SaveContext(Core::ThreadContext& ctx) override;
     void LoadContext(const Core::ThreadContext& ctx) override;
 
diff --git a/src/core/core.cpp b/src/core/core.cpp
index cabab744ad..a3834adae6 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -6,16 +6,16 @@
 
 #include "common/logging/log.h"
 
+#include "core/arm/arm_interface.h"
+#include "core/arm/dynarmic/arm_dynarmic.h"
+#include "core/arm/dyncom/arm_dyncom.h"
 #include "core/core.h"
 #include "core/core_timing.h"
-
-#include "core/arm/arm_interface.h"
-#include "core/arm/dyncom/arm_dyncom.h"
+#include "core/gdbstub/gdbstub.h"
 #include "core/hle/hle.h"
 #include "core/hle/kernel/thread.h"
 #include "core/hw/hw.h"
-
-#include "core/gdbstub/gdbstub.h"
+#include "core/settings.h"
 
 namespace Core {
 
@@ -73,8 +73,13 @@ void Stop() {
 
 /// Initialize the core
 void Init() {
-    g_sys_core = std::make_unique<ARM_DynCom>(USER32MODE);
-    g_app_core = std::make_unique<ARM_DynCom>(USER32MODE);
+    if (Settings::values.use_cpu_jit) {
+        g_sys_core = std::make_unique<ARM_Dynarmic>(USER32MODE);
+        g_app_core = std::make_unique<ARM_Dynarmic>(USER32MODE);
+    } else {
+        g_sys_core = std::make_unique<ARM_DynCom>(USER32MODE);
+        g_app_core = std::make_unique<ARM_DynCom>(USER32MODE);
+    }
 
     LOG_DEBUG(Core, "Initialized OK");
 }
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 9dea995f41..f1e5cf3cbf 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -441,6 +441,22 @@ std::tuple<u32, u32, bool> GetFreeThreadLocalSlot(std::vector<std::bitset<8>>& t
     return std::make_tuple(0, 0, true);
 }
 
+/**
+ * Resets a thread context, making it ready to be scheduled and run by the CPU
+ * @param context Thread context to reset
+ * @param stack_top Address of the top of the stack
+ * @param entry_point Address of entry point for execution
+ * @param arg User argument for thread
+ */
+static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) {
+    memset(&context, 0, sizeof(Core::ThreadContext));
+
+    context.cpu_registers[0] = arg;
+    context.pc = entry_point;
+    context.sp = stack_top;
+    context.cpsr = USER32MODE | ((entry_point & 1) << 5); // Usermode and THUMB mode
+}
+
 ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority,
         u32 arg, s32 processor_id, VAddr stack_top) {
     if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
@@ -525,7 +541,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
 
     // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
     // to initialize the context
-    Core::g_app_core->ResetContext(thread->context, stack_top, entry_point, arg);
+    ResetThreadContext(thread->context, stack_top, entry_point, arg);
 
     ready_queue.push_back(thread->current_priority, thread.get());
     thread->status = THREADSTATUS_READY;
diff --git a/src/core/settings.h b/src/core/settings.h
index fb3fbe391d..fcd14c6f3e 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -60,6 +60,7 @@ struct Values {
     float pad_circle_modifier_scale;
 
     // Core
+    bool use_cpu_jit;
     int frame_skip;
 
     // Data Storage