diff options
Diffstat (limited to '')
| -rw-r--r-- | src/citra/config.cpp | 1 | ||||
| -rw-r--r-- | src/citra/default_ini.h | 4 | ||||
| -rw-r--r-- | src/citra_qt/config.cpp | 2 | ||||
| -rw-r--r-- | src/citra_qt/configure_general.cpp | 5 | ||||
| -rw-r--r-- | src/citra_qt/configure_general.ui | 20 | ||||
| -rw-r--r-- | src/common/microprofile.h | 2 | ||||
| -rw-r--r-- | src/core/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | src/core/arm/arm_interface.h | 9 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic.cpp | 174 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic.h | 50 | ||||
| -rw-r--r-- | src/core/arm/dyncom/arm_dyncom.cpp | 17 | ||||
| -rw-r--r-- | src/core/arm/dyncom/arm_dyncom.h | 3 | ||||
| -rw-r--r-- | src/core/core.cpp | 19 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 18 | ||||
| -rw-r--r-- | src/core/settings.h | 1 |
15 files changed, 298 insertions, 33 deletions
diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 110b883fb..1a09f0e55 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp | |||
| @@ -65,6 +65,7 @@ void Config::ReadValues() { | |||
| 65 | Settings::values.pad_circle_modifier_scale = (float)sdl2_config->GetReal("Controls", "pad_circle_modifier_scale", 0.5); | 65 | Settings::values.pad_circle_modifier_scale = (float)sdl2_config->GetReal("Controls", "pad_circle_modifier_scale", 0.5); |
| 66 | 66 | ||
| 67 | // Core | 67 | // Core |
| 68 | Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true); | ||
| 68 | Settings::values.frame_skip = sdl2_config->GetInteger("Core", "frame_skip", 0); | 69 | Settings::values.frame_skip = sdl2_config->GetInteger("Core", "frame_skip", 0); |
| 69 | 70 | ||
| 70 | // Renderer | 71 | // Renderer |
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 2031620a5..788174508 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h | |||
| @@ -38,6 +38,10 @@ pad_circle_modifier = | |||
| 38 | pad_circle_modifier_scale = | 38 | pad_circle_modifier_scale = |
| 39 | 39 | ||
| 40 | [Core] | 40 | [Core] |
| 41 | # Whether to use the Just-In-Time (JIT) compiler for CPU emulation | ||
| 42 | # 0: Interpreter (slow), 1 (default): JIT (fast) | ||
| 43 | use_cpu_jit = | ||
| 44 | |||
| 41 | # The applied frameskip amount. Must be a power of two. | 45 | # The applied frameskip amount. Must be a power of two. |
| 42 | # 0 (default): No frameskip, 1: x2 frameskip, 2: x4 frameskip, 3: x8 frameskip, etc. | 46 | # 0 (default): No frameskip, 1: x2 frameskip, 2: x4 frameskip, 3: x8 frameskip, etc. |
| 43 | frame_skip = | 47 | frame_skip = |
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index fa3fa210c..cf1c09930 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp | |||
| @@ -41,6 +41,7 @@ void Config::ReadValues() { | |||
| 41 | qt_config->endGroup(); | 41 | qt_config->endGroup(); |
| 42 | 42 | ||
| 43 | qt_config->beginGroup("Core"); | 43 | qt_config->beginGroup("Core"); |
| 44 | Settings::values.use_cpu_jit = qt_config->value("use_cpu_jit", true).toBool(); | ||
| 44 | Settings::values.frame_skip = qt_config->value("frame_skip", 0).toInt(); | 45 | Settings::values.frame_skip = qt_config->value("frame_skip", 0).toInt(); |
| 45 | qt_config->endGroup(); | 46 | qt_config->endGroup(); |
| 46 | 47 | ||
| @@ -134,6 +135,7 @@ void Config::SaveValues() { | |||
| 134 | qt_config->endGroup(); | 135 | qt_config->endGroup(); |
| 135 | 136 | ||
| 136 | qt_config->beginGroup("Core"); | 137 | qt_config->beginGroup("Core"); |
| 138 | qt_config->setValue("use_cpu_jit", Settings::values.use_cpu_jit); | ||
| 137 | qt_config->setValue("frame_skip", Settings::values.frame_skip); | 139 | qt_config->setValue("frame_skip", Settings::values.frame_skip); |
| 138 | qt_config->endGroup(); | 140 | qt_config->endGroup(); |
| 139 | 141 | ||
diff --git a/src/citra_qt/configure_general.cpp b/src/citra_qt/configure_general.cpp index 95aab9f2e..e6832341a 100644 --- a/src/citra_qt/configure_general.cpp +++ b/src/citra_qt/configure_general.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "ui_configure_general.h" | 7 | #include "ui_configure_general.h" |
| 8 | 8 | ||
| 9 | #include "core/settings.h" | 9 | #include "core/settings.h" |
| 10 | #include "core/system.h" | ||
| 10 | 11 | ||
| 11 | ConfigureGeneral::ConfigureGeneral(QWidget *parent) : | 12 | ConfigureGeneral::ConfigureGeneral(QWidget *parent) : |
| 12 | QWidget(parent), | 13 | QWidget(parent), |
| @@ -14,6 +15,8 @@ ConfigureGeneral::ConfigureGeneral(QWidget *parent) : | |||
| 14 | { | 15 | { |
| 15 | ui->setupUi(this); | 16 | ui->setupUi(this); |
| 16 | this->setConfiguration(); | 17 | this->setConfiguration(); |
| 18 | |||
| 19 | ui->toggle_cpu_jit->setEnabled(!System::IsPoweredOn()); | ||
| 17 | } | 20 | } |
| 18 | 21 | ||
| 19 | ConfigureGeneral::~ConfigureGeneral() { | 22 | ConfigureGeneral::~ConfigureGeneral() { |
| @@ -22,6 +25,7 @@ ConfigureGeneral::~ConfigureGeneral() { | |||
| 22 | void ConfigureGeneral::setConfiguration() { | 25 | void ConfigureGeneral::setConfiguration() { |
| 23 | ui->toggle_deepscan->setChecked(UISettings::values.gamedir_deepscan); | 26 | ui->toggle_deepscan->setChecked(UISettings::values.gamedir_deepscan); |
| 24 | ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); | 27 | ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); |
| 28 | ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit); | ||
| 25 | ui->region_combobox->setCurrentIndex(Settings::values.region_value); | 29 | ui->region_combobox->setCurrentIndex(Settings::values.region_value); |
| 26 | } | 30 | } |
| 27 | 31 | ||
| @@ -29,5 +33,6 @@ void ConfigureGeneral::applyConfiguration() { | |||
| 29 | UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked(); | 33 | UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked(); |
| 30 | UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); | 34 | UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); |
| 31 | Settings::values.region_value = ui->region_combobox->currentIndex(); | 35 | Settings::values.region_value = ui->region_combobox->currentIndex(); |
| 36 | Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked(); | ||
| 32 | Settings::Apply(); | 37 | Settings::Apply(); |
| 33 | } | 38 | } |
diff --git a/src/citra_qt/configure_general.ui b/src/citra_qt/configure_general.ui index 343f804c0..81688113f 100644 --- a/src/citra_qt/configure_general.ui +++ b/src/citra_qt/configure_general.ui | |||
| @@ -43,6 +43,26 @@ | |||
| 43 | </layout> | 43 | </layout> |
| 44 | </widget> | 44 | </widget> |
| 45 | </item> | 45 | </item> |
| 46 | <item> | ||
| 47 | <widget class="QGroupBox" name="groupBox_2"> | ||
| 48 | <property name="title"> | ||
| 49 | <string>Performance</string> | ||
| 50 | </property> | ||
| 51 | <layout class="QHBoxLayout" name="horizontalLayout_7"> | ||
| 52 | <item> | ||
| 53 | <layout class="QVBoxLayout" name="verticalLayout_5"> | ||
| 54 | <item> | ||
| 55 | <widget class="QCheckBox" name="toggle_cpu_jit"> | ||
| 56 | <property name="text"> | ||
| 57 | <string>Enable CPU JIT</string> | ||
| 58 | </property> | ||
| 59 | </widget> | ||
| 60 | </item> | ||
| 61 | </layout> | ||
| 62 | </item> | ||
| 63 | </layout> | ||
| 64 | </widget> | ||
| 65 | </item> | ||
| 46 | <item> | 66 | <item> |
| 47 | <widget class="QGroupBox" name="groupBox_4"> | 67 | <widget class="QGroupBox" name="groupBox_4"> |
| 48 | <property name="title"> | 68 | <property name="title"> |
diff --git a/src/common/microprofile.h b/src/common/microprofile.h index ef312c6e1..670a58fe5 100644 --- a/src/common/microprofile.h +++ b/src/common/microprofile.h | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | #define MICROPROFILE_WEBSERVER 0 | 13 | #define MICROPROFILE_WEBSERVER 0 |
| 14 | #define MICROPROFILE_GPU_TIMERS 0 // TODO: Implement timer queries when we upgrade to OpenGL 3.3 | 14 | #define MICROPROFILE_GPU_TIMERS 0 // TODO: Implement timer queries when we upgrade to OpenGL 3.3 |
| 15 | #define MICROPROFILE_CONTEXT_SWITCH_TRACE 0 | 15 | #define MICROPROFILE_CONTEXT_SWITCH_TRACE 0 |
| 16 | #define MICROPROFILE_PER_THREAD_BUFFER_SIZE (2048<<12) // 8 MB | 16 | #define MICROPROFILE_PER_THREAD_BUFFER_SIZE (2048<<13) // 16 MB |
| 17 | 17 | ||
| 18 | #ifdef _WIN32 | 18 | #ifdef _WIN32 |
| 19 | // This isn't defined by the standard library in MSVC2015 | 19 | // This isn't defined by the standard library in MSVC2015 |
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 @@ | |||
| 1 | set(SRCS | 1 | set(SRCS |
| 2 | arm/disassembler/arm_disasm.cpp | 2 | arm/disassembler/arm_disasm.cpp |
| 3 | arm/disassembler/load_symbol_map.cpp | 3 | arm/disassembler/load_symbol_map.cpp |
| 4 | arm/dynarmic/arm_dynarmic.cpp | ||
| 4 | arm/dyncom/arm_dyncom.cpp | 5 | arm/dyncom/arm_dyncom.cpp |
| 5 | arm/dyncom/arm_dyncom_dec.cpp | 6 | arm/dyncom/arm_dyncom_dec.cpp |
| 6 | arm/dyncom/arm_dyncom_interpreter.cpp | 7 | arm/dyncom/arm_dyncom_interpreter.cpp |
| @@ -141,6 +142,7 @@ set(HEADERS | |||
| 141 | arm/arm_interface.h | 142 | arm/arm_interface.h |
| 142 | arm/disassembler/arm_disasm.h | 143 | arm/disassembler/arm_disasm.h |
| 143 | arm/disassembler/load_symbol_map.h | 144 | arm/disassembler/load_symbol_map.h |
| 145 | arm/dynarmic/arm_dynarmic.h | ||
| 144 | arm/dyncom/arm_dyncom.h | 146 | arm/dyncom/arm_dyncom.h |
| 145 | arm/dyncom/arm_dyncom_dec.h | 147 | arm/dyncom/arm_dyncom_dec.h |
| 146 | arm/dyncom/arm_dyncom_interpreter.h | 148 | arm/dyncom/arm_dyncom_interpreter.h |
| @@ -285,6 +287,10 @@ set(HEADERS | |||
| 285 | system.h | 287 | system.h |
| 286 | ) | 288 | ) |
| 287 | 289 | ||
| 290 | include_directories(../../externals/dynarmic/include) | ||
| 291 | |||
| 288 | create_directory_groups(${SRCS} ${HEADERS}) | 292 | create_directory_groups(${SRCS} ${HEADERS}) |
| 289 | 293 | ||
| 290 | add_library(core STATIC ${SRCS} ${HEADERS}) | 294 | add_library(core STATIC ${SRCS} ${HEADERS}) |
| 295 | |||
| 296 | 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: | |||
| 122 | virtual void AddTicks(u64 ticks) = 0; | 122 | virtual void AddTicks(u64 ticks) = 0; |
| 123 | 123 | ||
| 124 | /** | 124 | /** |
| 125 | * Initializes a CPU context for use on this CPU | ||
| 126 | * @param context Thread context to reset | ||
| 127 | * @param stack_top Pointer to the top of the stack | ||
| 128 | * @param entry_point Entry point for execution | ||
| 129 | * @param arg User argument for thread | ||
| 130 | */ | ||
| 131 | virtual void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) = 0; | ||
| 132 | |||
| 133 | /** | ||
| 134 | * Saves the current CPU context | 125 | * Saves the current CPU context |
| 135 | * @param ctx Thread context to save | 126 | * @param ctx Thread context to save |
| 136 | */ | 127 | */ |
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 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "common/microprofile.h" | ||
| 7 | |||
| 8 | #include <dynarmic/dynarmic.h> | ||
| 9 | |||
| 10 | #include "core/arm/dynarmic/arm_dynarmic.h" | ||
| 11 | #include "core/arm/dyncom/arm_dyncom_interpreter.h" | ||
| 12 | #include "core/core.h" | ||
| 13 | #include "core/core_timing.h" | ||
| 14 | #include "core/hle/svc.h" | ||
| 15 | #include "core/memory.h" | ||
| 16 | |||
| 17 | static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void* user_arg) { | ||
| 18 | ARMul_State* state = static_cast<ARMul_State*>(user_arg); | ||
| 19 | |||
| 20 | state->Reg = jit->Regs(); | ||
| 21 | state->Cpsr = jit->Cpsr(); | ||
| 22 | state->Reg[15] = pc; | ||
| 23 | state->ExtReg = jit->ExtRegs(); | ||
| 24 | state->VFP[VFP_FPSCR] = jit->Fpscr(); | ||
| 25 | state->NumInstrsToExecute = 1; | ||
| 26 | |||
| 27 | InterpreterMainLoop(state); | ||
| 28 | |||
| 29 | bool is_thumb = (state->Cpsr & (1 << 5)) != 0; | ||
| 30 | state->Reg[15] &= (is_thumb ? 0xFFFFFFFE : 0xFFFFFFFC); | ||
| 31 | |||
| 32 | jit->Regs() = state->Reg; | ||
| 33 | jit->Cpsr() = state->Cpsr; | ||
| 34 | jit->ExtRegs() = state->ExtReg; | ||
| 35 | jit->SetFpscr(state->VFP[VFP_FPSCR]); | ||
| 36 | } | ||
| 37 | |||
| 38 | static bool IsReadOnlyMemory(u32 vaddr) { | ||
| 39 | // TODO(bunnei): ImplementMe | ||
| 40 | return false; | ||
| 41 | } | ||
| 42 | |||
| 43 | static Dynarmic::UserCallbacks GetUserCallbacks(ARMul_State* interpeter_state) { | ||
| 44 | Dynarmic::UserCallbacks user_callbacks{}; | ||
| 45 | user_callbacks.InterpreterFallback = &InterpreterFallback; | ||
| 46 | user_callbacks.user_arg = static_cast<void*>(interpeter_state); | ||
| 47 | user_callbacks.CallSVC = &SVC::CallSVC; | ||
| 48 | user_callbacks.IsReadOnlyMemory = &IsReadOnlyMemory; | ||
| 49 | user_callbacks.MemoryRead8 = &Memory::Read8; | ||
| 50 | user_callbacks.MemoryRead16 = &Memory::Read16; | ||
| 51 | user_callbacks.MemoryRead32 = &Memory::Read32; | ||
| 52 | user_callbacks.MemoryRead64 = &Memory::Read64; | ||
| 53 | user_callbacks.MemoryWrite8 = &Memory::Write8; | ||
| 54 | user_callbacks.MemoryWrite16 = &Memory::Write16; | ||
| 55 | user_callbacks.MemoryWrite32 = &Memory::Write32; | ||
| 56 | user_callbacks.MemoryWrite64 = &Memory::Write64; | ||
| 57 | return user_callbacks; | ||
| 58 | } | ||
| 59 | |||
| 60 | ARM_Dynarmic::ARM_Dynarmic(PrivilegeMode initial_mode) { | ||
| 61 | interpreter_state = std::make_unique<ARMul_State>(initial_mode); | ||
| 62 | jit = std::make_unique<Dynarmic::Jit>(GetUserCallbacks(interpreter_state.get())); | ||
| 63 | } | ||
| 64 | |||
| 65 | void ARM_Dynarmic::SetPC(u32 pc) { | ||
| 66 | jit->Regs()[15] = pc; | ||
| 67 | } | ||
| 68 | |||
| 69 | u32 ARM_Dynarmic::GetPC() const { | ||
| 70 | return jit->Regs()[15]; | ||
| 71 | } | ||
| 72 | |||
| 73 | u32 ARM_Dynarmic::GetReg(int index) const { | ||
| 74 | return jit->Regs()[index]; | ||
| 75 | } | ||
| 76 | |||
| 77 | void ARM_Dynarmic::SetReg(int index, u32 value) { | ||
| 78 | jit->Regs()[index] = value; | ||
| 79 | } | ||
| 80 | |||
| 81 | u32 ARM_Dynarmic::GetVFPReg(int index) const { | ||
| 82 | return jit->ExtRegs()[index]; | ||
| 83 | } | ||
| 84 | |||
| 85 | void ARM_Dynarmic::SetVFPReg(int index, u32 value) { | ||
| 86 | jit->ExtRegs()[index] = value; | ||
| 87 | } | ||
| 88 | |||
| 89 | u32 ARM_Dynarmic::GetVFPSystemReg(VFPSystemRegister reg) const { | ||
| 90 | if (reg == VFP_FPSCR) { | ||
| 91 | return jit->Fpscr(); | ||
| 92 | } | ||
| 93 | |||
| 94 | // Dynarmic does not implement and/or expose other VFP registers, fallback to interpreter state | ||
| 95 | return interpreter_state->VFP[reg]; | ||
| 96 | } | ||
| 97 | |||
| 98 | void ARM_Dynarmic::SetVFPSystemReg(VFPSystemRegister reg, u32 value) { | ||
| 99 | if (reg == VFP_FPSCR) { | ||
| 100 | jit->SetFpscr(value); | ||
| 101 | } | ||
| 102 | |||
| 103 | // Dynarmic does not implement and/or expose other VFP registers, fallback to interpreter state | ||
| 104 | interpreter_state->VFP[reg] = value; | ||
| 105 | } | ||
| 106 | |||
| 107 | u32 ARM_Dynarmic::GetCPSR() const { | ||
| 108 | return jit->Cpsr(); | ||
| 109 | } | ||
| 110 | |||
| 111 | void ARM_Dynarmic::SetCPSR(u32 cpsr) { | ||
| 112 | jit->Cpsr() = cpsr; | ||
| 113 | } | ||
| 114 | |||
| 115 | u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) { | ||
| 116 | return interpreter_state->CP15[reg]; | ||
| 117 | } | ||
| 118 | |||
| 119 | void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) { | ||
| 120 | interpreter_state->CP15[reg] = value; | ||
| 121 | } | ||
| 122 | |||
| 123 | void ARM_Dynarmic::AddTicks(u64 ticks) { | ||
| 124 | down_count -= ticks; | ||
| 125 | if (down_count < 0) { | ||
| 126 | CoreTiming::Advance(); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64)); | ||
| 131 | |||
| 132 | void ARM_Dynarmic::ExecuteInstructions(int num_instructions) { | ||
| 133 | MICROPROFILE_SCOPE(ARM_Jit); | ||
| 134 | |||
| 135 | jit->Run(static_cast<unsigned>(num_instructions)); | ||
| 136 | |||
| 137 | AddTicks(num_instructions); | ||
| 138 | } | ||
| 139 | |||
| 140 | void ARM_Dynarmic::SaveContext(Core::ThreadContext& ctx) { | ||
| 141 | memcpy(ctx.cpu_registers, jit->Regs().data(), sizeof(ctx.cpu_registers)); | ||
| 142 | memcpy(ctx.fpu_registers, jit->ExtRegs().data(), sizeof(ctx.fpu_registers)); | ||
| 143 | |||
| 144 | ctx.sp = jit->Regs()[13]; | ||
| 145 | ctx.lr = jit->Regs()[14]; | ||
| 146 | ctx.pc = jit->Regs()[15]; | ||
| 147 | ctx.cpsr = jit->Cpsr(); | ||
| 148 | |||
| 149 | ctx.fpscr = jit->Fpscr(); | ||
| 150 | ctx.fpexc = interpreter_state->VFP[VFP_FPEXC]; | ||
| 151 | } | ||
| 152 | |||
| 153 | void ARM_Dynarmic::LoadContext(const Core::ThreadContext& ctx) { | ||
| 154 | memcpy(jit->Regs().data(), ctx.cpu_registers, sizeof(ctx.cpu_registers)); | ||
| 155 | memcpy(jit->ExtRegs().data(), ctx.fpu_registers, sizeof(ctx.fpu_registers)); | ||
| 156 | |||
| 157 | jit->Regs()[13] = ctx.sp; | ||
| 158 | jit->Regs()[14] = ctx.lr; | ||
| 159 | jit->Regs()[15] = ctx.pc; | ||
| 160 | jit->Cpsr() = ctx.cpsr; | ||
| 161 | |||
| 162 | jit->SetFpscr(ctx.fpscr); | ||
| 163 | interpreter_state->VFP[VFP_FPEXC] = ctx.fpexc; | ||
| 164 | } | ||
| 165 | |||
| 166 | void ARM_Dynarmic::PrepareReschedule() { | ||
| 167 | if (jit->IsExecuting()) { | ||
| 168 | jit->HaltExecution(); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | void ARM_Dynarmic::ClearInstructionCache() { | ||
| 173 | jit->ClearCache(); | ||
| 174 | } | ||
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 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | |||
| 9 | #include <dynarmic/dynarmic.h> | ||
| 10 | |||
| 11 | #include "common/common_types.h" | ||
| 12 | |||
| 13 | #include "core/arm/arm_interface.h" | ||
| 14 | #include "core/arm/skyeye_common/armstate.h" | ||
| 15 | |||
| 16 | namespace Core { | ||
| 17 | struct ThreadContext; | ||
| 18 | } | ||
| 19 | |||
| 20 | class ARM_Dynarmic final : public ARM_Interface { | ||
| 21 | public: | ||
| 22 | ARM_Dynarmic(PrivilegeMode initial_mode); | ||
| 23 | |||
| 24 | void SetPC(u32 pc) override; | ||
| 25 | u32 GetPC() const override; | ||
| 26 | u32 GetReg(int index) const override; | ||
| 27 | void SetReg(int index, u32 value) override; | ||
| 28 | u32 GetVFPReg(int index) const override; | ||
| 29 | void SetVFPReg(int index, u32 value) override; | ||
| 30 | u32 GetVFPSystemReg(VFPSystemRegister reg) const override; | ||
| 31 | void SetVFPSystemReg(VFPSystemRegister reg, u32 value) override; | ||
| 32 | u32 GetCPSR() const override; | ||
| 33 | void SetCPSR(u32 cpsr) override; | ||
| 34 | u32 GetCP15Register(CP15Register reg) override; | ||
| 35 | void SetCP15Register(CP15Register reg, u32 value) override; | ||
| 36 | |||
| 37 | void AddTicks(u64 ticks) override; | ||
| 38 | |||
| 39 | void SaveContext(Core::ThreadContext& ctx) override; | ||
| 40 | void LoadContext(const Core::ThreadContext& ctx) override; | ||
| 41 | |||
| 42 | void PrepareReschedule() override; | ||
| 43 | void ExecuteInstructions(int num_instructions) override; | ||
| 44 | |||
| 45 | void ClearInstructionCache() override; | ||
| 46 | |||
| 47 | private: | ||
| 48 | std::unique_ptr<Dynarmic::Jit> jit; | ||
| 49 | std::unique_ptr<ARMul_State> interpreter_state; | ||
| 50 | }; | ||
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) { | |||
| 93 | AddTicks(ticks_executed); | 93 | AddTicks(ticks_executed); |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | void ARM_DynCom::ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) { | ||
| 97 | memset(&context, 0, sizeof(Core::ThreadContext)); | ||
| 98 | |||
| 99 | context.cpu_registers[0] = arg; | ||
| 100 | context.pc = entry_point; | ||
| 101 | context.sp = stack_top; | ||
| 102 | context.cpsr = USER32MODE | ((entry_point & 1) << 5); // Usermode and THUMB mode | ||
| 103 | } | ||
| 104 | |||
| 105 | void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { | 96 | void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { |
| 106 | memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers)); | 97 | memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers)); |
| 107 | memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers)); | 98 | memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers)); |
| @@ -111,8 +102,8 @@ void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { | |||
| 111 | ctx.pc = state->Reg[15]; | 102 | ctx.pc = state->Reg[15]; |
| 112 | ctx.cpsr = state->Cpsr; | 103 | ctx.cpsr = state->Cpsr; |
| 113 | 104 | ||
| 114 | ctx.fpscr = state->VFP[1]; | 105 | ctx.fpscr = state->VFP[VFP_FPSCR]; |
| 115 | ctx.fpexc = state->VFP[2]; | 106 | ctx.fpexc = state->VFP[VFP_FPEXC]; |
| 116 | } | 107 | } |
| 117 | 108 | ||
| 118 | void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) { | 109 | void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) { |
| @@ -124,8 +115,8 @@ void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) { | |||
| 124 | state->Reg[15] = ctx.pc; | 115 | state->Reg[15] = ctx.pc; |
| 125 | state->Cpsr = ctx.cpsr; | 116 | state->Cpsr = ctx.cpsr; |
| 126 | 117 | ||
| 127 | state->VFP[1] = ctx.fpscr; | 118 | state->VFP[VFP_FPSCR] = ctx.fpscr; |
| 128 | state->VFP[2] = ctx.fpexc; | 119 | state->VFP[VFP_FPEXC] = ctx.fpexc; |
| 129 | } | 120 | } |
| 130 | 121 | ||
| 131 | void ARM_DynCom::PrepareReschedule() { | 122 | 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 { | |||
| 16 | struct ThreadContext; | 16 | struct ThreadContext; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | class ARM_DynCom final : virtual public ARM_Interface { | 19 | class ARM_DynCom final : public ARM_Interface { |
| 20 | public: | 20 | public: |
| 21 | ARM_DynCom(PrivilegeMode initial_mode); | 21 | ARM_DynCom(PrivilegeMode initial_mode); |
| 22 | ~ARM_DynCom(); | 22 | ~ARM_DynCom(); |
| @@ -38,7 +38,6 @@ public: | |||
| 38 | 38 | ||
| 39 | void AddTicks(u64 ticks) override; | 39 | void AddTicks(u64 ticks) override; |
| 40 | 40 | ||
| 41 | void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) override; | ||
| 42 | void SaveContext(Core::ThreadContext& ctx) override; | 41 | void SaveContext(Core::ThreadContext& ctx) override; |
| 43 | void LoadContext(const Core::ThreadContext& ctx) override; | 42 | void LoadContext(const Core::ThreadContext& ctx) override; |
| 44 | 43 | ||
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 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | 8 | ||
| 9 | #include "core/core.h" | ||
| 10 | #include "core/core_timing.h" | ||
| 11 | |||
| 12 | #include "core/arm/arm_interface.h" | 9 | #include "core/arm/arm_interface.h" |
| 10 | #include "core/arm/dynarmic/arm_dynarmic.h" | ||
| 13 | #include "core/arm/dyncom/arm_dyncom.h" | 11 | #include "core/arm/dyncom/arm_dyncom.h" |
| 12 | #include "core/core.h" | ||
| 13 | #include "core/core_timing.h" | ||
| 14 | #include "core/gdbstub/gdbstub.h" | ||
| 14 | #include "core/hle/hle.h" | 15 | #include "core/hle/hle.h" |
| 15 | #include "core/hle/kernel/thread.h" | 16 | #include "core/hle/kernel/thread.h" |
| 16 | #include "core/hw/hw.h" | 17 | #include "core/hw/hw.h" |
| 17 | 18 | #include "core/settings.h" | |
| 18 | #include "core/gdbstub/gdbstub.h" | ||
| 19 | 19 | ||
| 20 | namespace Core { | 20 | namespace Core { |
| 21 | 21 | ||
| @@ -73,8 +73,13 @@ void Stop() { | |||
| 73 | 73 | ||
| 74 | /// Initialize the core | 74 | /// Initialize the core |
| 75 | void Init() { | 75 | void Init() { |
| 76 | g_sys_core = std::make_unique<ARM_DynCom>(USER32MODE); | 76 | if (Settings::values.use_cpu_jit) { |
| 77 | g_app_core = std::make_unique<ARM_DynCom>(USER32MODE); | 77 | g_sys_core = std::make_unique<ARM_Dynarmic>(USER32MODE); |
| 78 | g_app_core = std::make_unique<ARM_Dynarmic>(USER32MODE); | ||
| 79 | } else { | ||
| 80 | g_sys_core = std::make_unique<ARM_DynCom>(USER32MODE); | ||
| 81 | g_app_core = std::make_unique<ARM_DynCom>(USER32MODE); | ||
| 82 | } | ||
| 78 | 83 | ||
| 79 | LOG_DEBUG(Core, "Initialized OK"); | 84 | LOG_DEBUG(Core, "Initialized OK"); |
| 80 | } | 85 | } |
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 | |||
| 441 | return std::make_tuple(0, 0, true); | 441 | return std::make_tuple(0, 0, true); |
| 442 | } | 442 | } |
| 443 | 443 | ||
| 444 | /** | ||
| 445 | * Resets a thread context, making it ready to be scheduled and run by the CPU | ||
| 446 | * @param context Thread context to reset | ||
| 447 | * @param stack_top Address of the top of the stack | ||
| 448 | * @param entry_point Address of entry point for execution | ||
| 449 | * @param arg User argument for thread | ||
| 450 | */ | ||
| 451 | static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) { | ||
| 452 | memset(&context, 0, sizeof(Core::ThreadContext)); | ||
| 453 | |||
| 454 | context.cpu_registers[0] = arg; | ||
| 455 | context.pc = entry_point; | ||
| 456 | context.sp = stack_top; | ||
| 457 | context.cpsr = USER32MODE | ((entry_point & 1) << 5); // Usermode and THUMB mode | ||
| 458 | } | ||
| 459 | |||
| 444 | ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority, | 460 | ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority, |
| 445 | u32 arg, s32 processor_id, VAddr stack_top) { | 461 | u32 arg, s32 processor_id, VAddr stack_top) { |
| 446 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { | 462 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { |
| @@ -525,7 +541,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 525 | 541 | ||
| 526 | // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used | 542 | // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used |
| 527 | // to initialize the context | 543 | // to initialize the context |
| 528 | Core::g_app_core->ResetContext(thread->context, stack_top, entry_point, arg); | 544 | ResetThreadContext(thread->context, stack_top, entry_point, arg); |
| 529 | 545 | ||
| 530 | ready_queue.push_back(thread->current_priority, thread.get()); | 546 | ready_queue.push_back(thread->current_priority, thread.get()); |
| 531 | thread->status = THREADSTATUS_READY; | 547 | 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 { | |||
| 60 | float pad_circle_modifier_scale; | 60 | float pad_circle_modifier_scale; |
| 61 | 61 | ||
| 62 | // Core | 62 | // Core |
| 63 | bool use_cpu_jit; | ||
| 63 | int frame_skip; | 64 | int frame_skip; |
| 64 | 65 | ||
| 65 | // Data Storage | 66 | // Data Storage |