summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/core.cpp30
-rw-r--r--src/core/core.h24
-rw-r--r--src/core/core_cpu.cpp25
-rw-r--r--src/core/core_cpu.h33
4 files changed, 94 insertions, 18 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 0af78c18c..066423f23 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -27,6 +27,13 @@ namespace Core {
27 27
28System::~System() = default; 28System::~System() = default;
29 29
30/// Runs a CPU core while the system is powered on
31static void RunCpuCore(std::shared_ptr<Cpu> cpu_state) {
32 while (Core::System().GetInstance().IsPoweredOn()) {
33 cpu_state->RunLoop(true);
34 }
35}
36
30System::ResultStatus System::RunLoop(bool tight_loop) { 37System::ResultStatus System::RunLoop(bool tight_loop) {
31 status = ResultStatus::Success; 38 status = ResultStatus::Success;
32 39
@@ -109,7 +116,7 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
109} 116}
110 117
111void System::PrepareReschedule() { 118void System::PrepareReschedule() {
112 cpu_cores[0]->PrepareReschedule(); 119 CurrentCpuCore().PrepareReschedule();
113} 120}
114 121
115PerfStats::Results System::GetAndResetPerfStats() { 122PerfStats::Results System::GetAndResetPerfStats() {
@@ -123,14 +130,13 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
123 130
124 current_process = Kernel::Process::Create("main"); 131 current_process = Kernel::Process::Create("main");
125 132
126 for (auto& cpu_core : cpu_cores) { 133 cpu_barrier = std::make_shared<CpuBarrier>();
127 cpu_core = std::make_unique<Cpu>(); 134 for (size_t index = 0; index < cpu_cores.size(); ++index) {
135 cpu_cores[index] = std::make_shared<Cpu>(cpu_barrier, index);
128 } 136 }
129 137
130 gpu_core = std::make_unique<Tegra::GPU>(); 138 gpu_core = std::make_unique<Tegra::GPU>();
131
132 telemetry_session = std::make_unique<Core::TelemetrySession>(); 139 telemetry_session = std::make_unique<Core::TelemetrySession>();
133
134 service_manager = std::make_shared<Service::SM::ServiceManager>(); 140 service_manager = std::make_shared<Service::SM::ServiceManager>();
135 141
136 HW::Init(); 142 HW::Init();
@@ -142,6 +148,14 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
142 return ResultStatus::ErrorVideoCore; 148 return ResultStatus::ErrorVideoCore;
143 } 149 }
144 150
151 // Create threads for CPU cores 1-3, and build thread_to_cpu map
152 // CPU core 0 is run on the main thread
153 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0];
154 for (size_t index = 0; index < cpu_core_threads.size(); ++index) {
155 cpu_core_threads[index] = std::make_unique<std::thread>(RunCpuCore, cpu_cores[index + 1]);
156 thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1];
157 }
158
145 NGLOG_DEBUG(Core, "Initialized OK"); 159 NGLOG_DEBUG(Core, "Initialized OK");
146 160
147 // Reset counters and set time origin to current frame 161 // Reset counters and set time origin to current frame
@@ -171,9 +185,15 @@ void System::Shutdown() {
171 telemetry_session.reset(); 185 telemetry_session.reset();
172 gpu_core.reset(); 186 gpu_core.reset();
173 187
188 // Close all CPU/threading state
189 thread_to_cpu.clear();
174 for (auto& cpu_core : cpu_cores) { 190 for (auto& cpu_core : cpu_cores) {
175 cpu_core.reset(); 191 cpu_core.reset();
176 } 192 }
193 for (auto& thread : cpu_core_threads) {
194 thread->join();
195 thread.reset();
196 }
177 197
178 CoreTiming::Shutdown(); 198 CoreTiming::Shutdown();
179 199
diff --git a/src/core/core.h b/src/core/core.h
index 6e6cc7579..21a0b074b 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -7,6 +7,7 @@
7#include <array> 7#include <array>
8#include <memory> 8#include <memory>
9#include <string> 9#include <string>
10#include <thread>
10#include "common/common_types.h" 11#include "common/common_types.h"
11#include "core/core_cpu.h" 12#include "core/core_cpu.h"
12#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
@@ -112,7 +113,7 @@ public:
112 * @returns A reference to the emulated CPU. 113 * @returns A reference to the emulated CPU.
113 */ 114 */
114 ARM_Interface& CPU() { 115 ARM_Interface& CPU() {
115 return cpu_cores[0]->CPU(); 116 return CurrentCpuCore().CPU();
116 } 117 }
117 118
118 Tegra::GPU& GPU() { 119 Tegra::GPU& GPU() {
@@ -120,7 +121,7 @@ public:
120 } 121 }
121 122
122 Kernel::Scheduler& Scheduler() { 123 Kernel::Scheduler& Scheduler() {
123 return cpu_cores[0]->Scheduler(); 124 return CurrentCpuCore().Scheduler();
124 } 125 }
125 126
126 Kernel::SharedPtr<Kernel::Process>& CurrentProcess() { 127 Kernel::SharedPtr<Kernel::Process>& CurrentProcess() {
@@ -157,6 +158,14 @@ public:
157 } 158 }
158 159
159private: 160private:
161 /// Returns the current CPU core based on the calling host thread
162 Cpu& CurrentCpuCore() {
163 const auto& search = thread_to_cpu.find(std::this_thread::get_id());
164 ASSERT(search != thread_to_cpu.end());
165 ASSERT(search->second);
166 return *search->second;
167 }
168
160 /** 169 /**
161 * Initialize the emulated system. 170 * Initialize the emulated system.
162 * @param emu_window Pointer to the host-system window used for video output and keyboard input. 171 * @param emu_window Pointer to the host-system window used for video output and keyboard input.
@@ -167,14 +176,12 @@ private:
167 176
168 /// AppLoader used to load the current executing application 177 /// AppLoader used to load the current executing application
169 std::unique_ptr<Loader::AppLoader> app_loader; 178 std::unique_ptr<Loader::AppLoader> app_loader;
170
171 std::array<std::unique_ptr<Cpu>, 4> cpu_cores;
172 std::unique_ptr<Tegra::GPU> gpu_core; 179 std::unique_ptr<Tegra::GPU> gpu_core;
173 std::shared_ptr<Tegra::DebugContext> debug_context; 180 std::shared_ptr<Tegra::DebugContext> debug_context;
174 Kernel::SharedPtr<Kernel::Process> current_process; 181 Kernel::SharedPtr<Kernel::Process> current_process;
175 182 std::shared_ptr<CpuBarrier> cpu_barrier;
176 /// When true, signals that a reschedule should happen 183 std::array<std::shared_ptr<Cpu>, NUM_CPU_CORES> cpu_cores;
177 bool reschedule_pending{}; 184 std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads;
178 185
179 /// Service manager 186 /// Service manager
180 std::shared_ptr<Service::SM::ServiceManager> service_manager; 187 std::shared_ptr<Service::SM::ServiceManager> service_manager;
@@ -186,6 +193,9 @@ private:
186 193
187 ResultStatus status = ResultStatus::Success; 194 ResultStatus status = ResultStatus::Success;
188 std::string status_details = ""; 195 std::string status_details = "";
196
197 /// Map of guest threads to CPU cores
198 std::map<std::thread::id, std::shared_ptr<Cpu>> thread_to_cpu;
189}; 199};
190 200
191inline ARM_Interface& CPU() { 201inline ARM_Interface& CPU() {
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index 81c0e212d..6bdfdd7df 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -2,6 +2,9 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <condition_variable>
6#include <mutex>
7
5#include "common/logging/log.h" 8#include "common/logging/log.h"
6#ifdef ARCHITECTURE_x86_64 9#ifdef ARCHITECTURE_x86_64
7#include "core/arm/dynarmic/arm_dynarmic.h" 10#include "core/arm/dynarmic/arm_dynarmic.h"
@@ -16,7 +19,9 @@
16 19
17namespace Core { 20namespace Core {
18 21
19Cpu::Cpu() { 22Cpu::Cpu(std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index)
23 : cpu_barrier{std::move(cpu_barrier)}, core_index{core_index} {
24
20 if (Settings::values.use_cpu_jit) { 25 if (Settings::values.use_cpu_jit) {
21#ifdef ARCHITECTURE_x86_64 26#ifdef ARCHITECTURE_x86_64
22 arm_interface = std::make_shared<ARM_Dynarmic>(); 27 arm_interface = std::make_shared<ARM_Dynarmic>();
@@ -32,15 +37,25 @@ Cpu::Cpu() {
32} 37}
33 38
34void Cpu::RunLoop(bool tight_loop) { 39void Cpu::RunLoop(bool tight_loop) {
40 // Wait for all other CPU cores to complete the previous slice, such that they run in lock-step
41 cpu_barrier->Rendezvous();
42
35 // If we don't have a currently active thread then don't execute instructions, 43 // If we don't have a currently active thread then don't execute instructions,
36 // instead advance to the next event and try to yield to the next thread 44 // instead advance to the next event and try to yield to the next thread
37 if (Kernel::GetCurrentThread() == nullptr) { 45 if (Kernel::GetCurrentThread() == nullptr) {
38 NGLOG_TRACE(Core, "Idling"); 46 NGLOG_TRACE(Core, "Core-{} idling", core_index);
39 CoreTiming::Idle(); 47
40 CoreTiming::Advance(); 48 if (IsMainCore()) {
49 CoreTiming::Idle();
50 CoreTiming::Advance();
51 }
52
41 PrepareReschedule(); 53 PrepareReschedule();
42 } else { 54 } else {
43 CoreTiming::Advance(); 55 if (IsMainCore()) {
56 CoreTiming::Advance();
57 }
58
44 if (tight_loop) { 59 if (tight_loop) {
45 arm_interface->Run(); 60 arm_interface->Run();
46 } else { 61 } else {
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h
index 312db1655..e6ed698cc 100644
--- a/src/core/core_cpu.h
+++ b/src/core/core_cpu.h
@@ -4,7 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <condition_variable>
7#include <memory> 8#include <memory>
9#include <mutex>
8#include <string> 10#include <string>
9#include "common/common_types.h" 11#include "common/common_types.h"
10 12
@@ -16,9 +18,32 @@ class Scheduler;
16 18
17namespace Core { 19namespace Core {
18 20
21constexpr unsigned NUM_CPU_CORES{4};
22
23class CpuBarrier {
24public:
25 void Rendezvous() {
26 std::unique_lock<std::mutex> lock(mutex);
27
28 --cores_waiting;
29 if (!cores_waiting) {
30 cores_waiting = NUM_CPU_CORES;
31 condition.notify_all();
32 return;
33 }
34
35 condition.wait(lock);
36 }
37
38private:
39 unsigned cores_waiting{NUM_CPU_CORES};
40 std::mutex mutex;
41 std::condition_variable condition;
42};
43
19class Cpu { 44class Cpu {
20public: 45public:
21 Cpu(); 46 Cpu(std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index);
22 47
23 void RunLoop(bool tight_loop = true); 48 void RunLoop(bool tight_loop = true);
24 49
@@ -34,13 +59,19 @@ public:
34 return *scheduler; 59 return *scheduler;
35 } 60 }
36 61
62 bool IsMainCore() const {
63 return core_index == 0;
64 }
65
37private: 66private:
38 void Reschedule(); 67 void Reschedule();
39 68
40 std::shared_ptr<ARM_Interface> arm_interface; 69 std::shared_ptr<ARM_Interface> arm_interface;
70 std::shared_ptr<CpuBarrier> cpu_barrier;
41 std::unique_ptr<Kernel::Scheduler> scheduler; 71 std::unique_ptr<Kernel::Scheduler> scheduler;
42 72
43 bool reschedule_pending{}; 73 bool reschedule_pending{};
74 size_t core_index;
44}; 75};
45 76
46} // namespace Core 77} // namespace Core