summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt6
-rw-r--r--src/core/arm/arm_interface.h9
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp174
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h50
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp17
-rw-r--r--src/core/arm/dyncom/arm_dyncom.h3
-rw-r--r--src/core/core.cpp19
-rw-r--r--src/core/hle/kernel/thread.cpp18
-rw-r--r--src/core/settings.h1
9 files changed, 265 insertions, 32 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 174e9dc79..4a9c6fd2f 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 de5e9c8fa..480c90e66 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -122,15 +122,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 000000000..a521aec7c
--- /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 000000000..d493cabd5
--- /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 ab77da965..d84917529 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 e763abc24..70f71a828 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 cabab744a..a3834adae 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -6,16 +6,16 @@
#include "common/logging/log.h"
-#include "core/core.h"
-#include "core/core_timing.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/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 9dea995f4..f1e5cf3cb 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 fb3fbe391..fcd14c6f3 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