summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/core.cpp119
-rw-r--r--src/core/cpu_core_manager.cpp142
-rw-r--r--src/core/cpu_core_manager.h59
4 files changed, 225 insertions, 97 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index a355eaca6..3d2e0767a 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -12,6 +12,8 @@ add_library(core STATIC
12 core_timing.h 12 core_timing.h
13 core_timing_util.cpp 13 core_timing_util.cpp
14 core_timing_util.h 14 core_timing_util.h
15 cpu_core_manager.cpp
16 cpu_core_manager.h
15 crypto/aes_util.cpp 17 crypto/aes_util.cpp
16 crypto/aes_util.h 18 crypto/aes_util.h
17 crypto/encryption_layer.cpp 19 crypto/encryption_layer.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 6c72fdf4a..795fabc65 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -14,6 +14,7 @@
14#include "core/core.h" 14#include "core/core.h"
15#include "core/core_cpu.h" 15#include "core/core_cpu.h"
16#include "core/core_timing.h" 16#include "core/core_timing.h"
17#include "core/cpu_core_manager.h"
17#include "core/file_sys/mode.h" 18#include "core/file_sys/mode.h"
18#include "core/file_sys/vfs_concat.h" 19#include "core/file_sys/vfs_concat.h"
19#include "core/file_sys/vfs_real.h" 20#include "core/file_sys/vfs_real.h"
@@ -28,7 +29,6 @@
28#include "core/hle/service/sm/sm.h" 29#include "core/hle/service/sm/sm.h"
29#include "core/loader/loader.h" 30#include "core/loader/loader.h"
30#include "core/perf_stats.h" 31#include "core/perf_stats.h"
31#include "core/settings.h"
32#include "core/telemetry_session.h" 32#include "core/telemetry_session.h"
33#include "frontend/applets/software_keyboard.h" 33#include "frontend/applets/software_keyboard.h"
34#include "video_core/debug_utils/debug_utils.h" 34#include "video_core/debug_utils/debug_utils.h"
@@ -71,64 +71,22 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
71 71
72 return vfs->OpenFile(path, FileSys::Mode::Read); 72 return vfs->OpenFile(path, FileSys::Mode::Read);
73} 73}
74
75/// Runs a CPU core while the system is powered on
76void RunCpuCore(Cpu& cpu_state) {
77 while (Core::System::GetInstance().IsPoweredOn()) {
78 cpu_state.RunLoop(true);
79 }
80}
81} // Anonymous namespace 74} // Anonymous namespace
82 75
83struct System::Impl { 76struct System::Impl {
84 Cpu& CurrentCpuCore() { 77 Cpu& CurrentCpuCore() {
85 if (Settings::values.use_multi_core) { 78 return cpu_core_manager.GetCurrentCore();
86 const auto& search = thread_to_cpu.find(std::this_thread::get_id());
87 ASSERT(search != thread_to_cpu.end());
88 ASSERT(search->second);
89 return *search->second;
90 }
91
92 // Otherwise, use single-threaded mode active_core variable
93 return *cpu_cores[active_core];
94 } 79 }
95 80
96 ResultStatus RunLoop(bool tight_loop) { 81 ResultStatus RunLoop(bool tight_loop) {
97 status = ResultStatus::Success; 82 status = ResultStatus::Success;
98 83
99 // Update thread_to_cpu in case Core 0 is run from a different host thread 84 cpu_core_manager.RunLoop(tight_loop);
100 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get();
101
102 if (GDBStub::IsServerEnabled()) {
103 GDBStub::HandlePacket();
104
105 // If the loop is halted and we want to step, use a tiny (1) number of instructions to
106 // execute. Otherwise, get out of the loop function.
107 if (GDBStub::GetCpuHaltFlag()) {
108 if (GDBStub::GetCpuStepFlag()) {
109 tight_loop = false;
110 } else {
111 return ResultStatus::Success;
112 }
113 }
114 }
115
116 for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
117 cpu_cores[active_core]->RunLoop(tight_loop);
118 if (Settings::values.use_multi_core) {
119 // Cores 1-3 are run on other threads in this mode
120 break;
121 }
122 }
123
124 if (GDBStub::IsServerEnabled()) {
125 GDBStub::SetCpuStepFlag(false);
126 }
127 85
128 return status; 86 return status;
129 } 87 }
130 88
131 ResultStatus Init(Frontend::EmuWindow& emu_window) { 89 ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
132 LOG_DEBUG(HW_Memory, "initialized OK"); 90 LOG_DEBUG(HW_Memory, "initialized OK");
133 91
134 CoreTiming::Init(); 92 CoreTiming::Init();
@@ -145,12 +103,6 @@ struct System::Impl {
145 auto main_process = Kernel::Process::Create(kernel, "main"); 103 auto main_process = Kernel::Process::Create(kernel, "main");
146 kernel.MakeCurrentProcess(main_process.get()); 104 kernel.MakeCurrentProcess(main_process.get());
147 105
148 cpu_barrier = std::make_unique<CpuBarrier>();
149 cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size());
150 for (std::size_t index = 0; index < cpu_cores.size(); ++index) {
151 cpu_cores[index] = std::make_unique<Cpu>(*cpu_exclusive_monitor, *cpu_barrier, index);
152 }
153
154 telemetry_session = std::make_unique<Core::TelemetrySession>(); 106 telemetry_session = std::make_unique<Core::TelemetrySession>();
155 service_manager = std::make_shared<Service::SM::ServiceManager>(); 107 service_manager = std::make_shared<Service::SM::ServiceManager>();
156 108
@@ -164,17 +116,8 @@ struct System::Impl {
164 116
165 gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer()); 117 gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer());
166 118
167 // Create threads for CPU cores 1-3, and build thread_to_cpu map 119 cpu_core_manager.Initialize(system);
168 // CPU core 0 is run on the main thread 120 is_powered_on = true;
169 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get();
170 if (Settings::values.use_multi_core) {
171 for (std::size_t index = 0; index < cpu_core_threads.size(); ++index) {
172 cpu_core_threads[index] =
173 std::make_unique<std::thread>(RunCpuCore, std::ref(*cpu_cores[index + 1]));
174 thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1].get();
175 }
176 }
177
178 LOG_DEBUG(Core, "Initialized OK"); 121 LOG_DEBUG(Core, "Initialized OK");
179 122
180 // Reset counters and set time origin to current frame 123 // Reset counters and set time origin to current frame
@@ -184,7 +127,8 @@ struct System::Impl {
184 return ResultStatus::Success; 127 return ResultStatus::Success;
185 } 128 }
186 129
187 ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { 130 ResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
131 const std::string& filepath) {
188 app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); 132 app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath));
189 133
190 if (!app_loader) { 134 if (!app_loader) {
@@ -201,7 +145,7 @@ struct System::Impl {
201 return ResultStatus::ErrorSystemMode; 145 return ResultStatus::ErrorSystemMode;
202 } 146 }
203 147
204 ResultStatus init_result{Init(emu_window)}; 148 ResultStatus init_result{Init(system, emu_window)};
205 if (init_result != ResultStatus::Success) { 149 if (init_result != ResultStatus::Success) {
206 LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", 150 LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
207 static_cast<int>(init_result)); 151 static_cast<int>(init_result));
@@ -231,6 +175,8 @@ struct System::Impl {
231 Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime", 175 Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
232 perf_results.frametime * 1000.0); 176 perf_results.frametime * 1000.0);
233 177
178 is_powered_on = false;
179
234 // Shutdown emulation session 180 // Shutdown emulation session
235 renderer.reset(); 181 renderer.reset();
236 GDBStub::Shutdown(); 182 GDBStub::Shutdown();
@@ -240,19 +186,7 @@ struct System::Impl {
240 gpu_core.reset(); 186 gpu_core.reset();
241 187
242 // Close all CPU/threading state 188 // Close all CPU/threading state
243 cpu_barrier->NotifyEnd(); 189 cpu_core_manager.Shutdown();
244 if (Settings::values.use_multi_core) {
245 for (auto& thread : cpu_core_threads) {
246 thread->join();
247 thread.reset();
248 }
249 }
250 thread_to_cpu.clear();
251 for (auto& cpu_core : cpu_cores) {
252 cpu_core.reset();
253 }
254 cpu_exclusive_monitor.reset();
255 cpu_barrier.reset();
256 190
257 // Shutdown kernel and core timing 191 // Shutdown kernel and core timing
258 kernel.Shutdown(); 192 kernel.Shutdown();
@@ -289,11 +223,8 @@ struct System::Impl {
289 std::unique_ptr<VideoCore::RendererBase> renderer; 223 std::unique_ptr<VideoCore::RendererBase> renderer;
290 std::unique_ptr<Tegra::GPU> gpu_core; 224 std::unique_ptr<Tegra::GPU> gpu_core;
291 std::shared_ptr<Tegra::DebugContext> debug_context; 225 std::shared_ptr<Tegra::DebugContext> debug_context;
292 std::unique_ptr<ExclusiveMonitor> cpu_exclusive_monitor; 226 CpuCoreManager cpu_core_manager;
293 std::unique_ptr<CpuBarrier> cpu_barrier; 227 bool is_powered_on = false;
294 std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cpu_cores;
295 std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads;
296 std::size_t active_core{}; ///< Active core, only used in single thread mode
297 228
298 /// Frontend applets 229 /// Frontend applets
299 std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; 230 std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
@@ -307,9 +238,6 @@ struct System::Impl {
307 ResultStatus status = ResultStatus::Success; 238 ResultStatus status = ResultStatus::Success;
308 std::string status_details = ""; 239 std::string status_details = "";
309 240
310 /// Map of guest threads to CPU cores
311 std::map<std::thread::id, Cpu*> thread_to_cpu;
312
313 Core::PerfStats perf_stats; 241 Core::PerfStats perf_stats;
314 Core::FrameLimiter frame_limiter; 242 Core::FrameLimiter frame_limiter;
315}; 243};
@@ -334,17 +262,15 @@ System::ResultStatus System::SingleStep() {
334} 262}
335 263
336void System::InvalidateCpuInstructionCaches() { 264void System::InvalidateCpuInstructionCaches() {
337 for (auto& cpu : impl->cpu_cores) { 265 impl->cpu_core_manager.InvalidateAllInstructionCaches();
338 cpu->ArmInterface().ClearInstructionCache();
339 }
340} 266}
341 267
342System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { 268System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
343 return impl->Load(emu_window, filepath); 269 return impl->Load(*this, emu_window, filepath);
344} 270}
345 271
346bool System::IsPoweredOn() const { 272bool System::IsPoweredOn() const {
347 return impl->cpu_barrier && impl->cpu_barrier->IsAlive(); 273 return impl->is_powered_on;
348} 274}
349 275
350void System::PrepareReschedule() { 276void System::PrepareReschedule() {
@@ -408,21 +334,20 @@ const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
408} 334}
409 335
410Cpu& System::CpuCore(std::size_t core_index) { 336Cpu& System::CpuCore(std::size_t core_index) {
411 ASSERT(core_index < NUM_CPU_CORES); 337 return impl->cpu_core_manager.GetCore(core_index);
412 return *impl->cpu_cores[core_index];
413} 338}
414 339
415const Cpu& System::CpuCore(std::size_t core_index) const { 340const Cpu& System::CpuCore(std::size_t core_index) const {
416 ASSERT(core_index < NUM_CPU_CORES); 341 ASSERT(core_index < NUM_CPU_CORES);
417 return *impl->cpu_cores[core_index]; 342 return impl->cpu_core_manager.GetCore(core_index);
418} 343}
419 344
420ExclusiveMonitor& System::Monitor() { 345ExclusiveMonitor& System::Monitor() {
421 return *impl->cpu_exclusive_monitor; 346 return impl->cpu_core_manager.GetExclusiveMonitor();
422} 347}
423 348
424const ExclusiveMonitor& System::Monitor() const { 349const ExclusiveMonitor& System::Monitor() const {
425 return *impl->cpu_exclusive_monitor; 350 return impl->cpu_core_manager.GetExclusiveMonitor();
426} 351}
427 352
428Tegra::GPU& System::GPU() { 353Tegra::GPU& System::GPU() {
@@ -506,7 +431,7 @@ const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() cons
506} 431}
507 432
508System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { 433System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
509 return impl->Init(emu_window); 434 return impl->Init(*this, emu_window);
510} 435}
511 436
512void System::Shutdown() { 437void System::Shutdown() {
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp
new file mode 100644
index 000000000..769a6fefa
--- /dev/null
+++ b/src/core/cpu_core_manager.cpp
@@ -0,0 +1,142 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "core/arm/exclusive_monitor.h"
7#include "core/core.h"
8#include "core/core_cpu.h"
9#include "core/cpu_core_manager.h"
10#include "core/gdbstub/gdbstub.h"
11#include "core/settings.h"
12
13namespace Core {
14namespace {
15void RunCpuCore(const System& system, Cpu& cpu_state) {
16 while (system.IsPoweredOn()) {
17 cpu_state.RunLoop(true);
18 }
19}
20} // Anonymous namespace
21
22CpuCoreManager::CpuCoreManager() = default;
23CpuCoreManager::~CpuCoreManager() = default;
24
25void CpuCoreManager::Initialize(System& system) {
26 barrier = std::make_unique<CpuBarrier>();
27 exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
28
29 for (std::size_t index = 0; index < cores.size(); ++index) {
30 cores[index] = std::make_unique<Cpu>(*exclusive_monitor, *barrier, index);
31 }
32
33 // Create threads for CPU cores 1-3, and build thread_to_cpu map
34 // CPU core 0 is run on the main thread
35 thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
36 if (!Settings::values.use_multi_core) {
37 return;
38 }
39
40 for (std::size_t index = 0; index < core_threads.size(); ++index) {
41 core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system),
42 std::ref(*cores[index + 1]));
43 thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get();
44 }
45}
46
47void CpuCoreManager::Shutdown() {
48 barrier->NotifyEnd();
49 if (Settings::values.use_multi_core) {
50 for (auto& thread : core_threads) {
51 thread->join();
52 thread.reset();
53 }
54 }
55
56 thread_to_cpu.clear();
57 for (auto& cpu_core : cores) {
58 cpu_core.reset();
59 }
60
61 exclusive_monitor.reset();
62 barrier.reset();
63}
64
65Cpu& CpuCoreManager::GetCore(std::size_t index) {
66 return *cores.at(index);
67}
68
69const Cpu& CpuCoreManager::GetCore(std::size_t index) const {
70 return *cores.at(index);
71}
72
73ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() {
74 return *exclusive_monitor;
75}
76
77const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const {
78 return *exclusive_monitor;
79}
80
81Cpu& CpuCoreManager::GetCurrentCore() {
82 if (Settings::values.use_multi_core) {
83 const auto& search = thread_to_cpu.find(std::this_thread::get_id());
84 ASSERT(search != thread_to_cpu.end());
85 ASSERT(search->second);
86 return *search->second;
87 }
88
89 // Otherwise, use single-threaded mode active_core variable
90 return *cores[active_core];
91}
92
93const Cpu& CpuCoreManager::GetCurrentCore() const {
94 if (Settings::values.use_multi_core) {
95 const auto& search = thread_to_cpu.find(std::this_thread::get_id());
96 ASSERT(search != thread_to_cpu.end());
97 ASSERT(search->second);
98 return *search->second;
99 }
100
101 // Otherwise, use single-threaded mode active_core variable
102 return *cores[active_core];
103}
104
105void CpuCoreManager::RunLoop(bool tight_loop) {
106 // Update thread_to_cpu in case Core 0 is run from a different host thread
107 thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
108
109 if (GDBStub::IsServerEnabled()) {
110 GDBStub::HandlePacket();
111
112 // If the loop is halted and we want to step, use a tiny (1) number of instructions to
113 // execute. Otherwise, get out of the loop function.
114 if (GDBStub::GetCpuHaltFlag()) {
115 if (GDBStub::GetCpuStepFlag()) {
116 tight_loop = false;
117 } else {
118 return;
119 }
120 }
121 }
122
123 for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
124 cores[active_core]->RunLoop(tight_loop);
125 if (Settings::values.use_multi_core) {
126 // Cores 1-3 are run on other threads in this mode
127 break;
128 }
129 }
130
131 if (GDBStub::IsServerEnabled()) {
132 GDBStub::SetCpuStepFlag(false);
133 }
134}
135
136void CpuCoreManager::InvalidateAllInstructionCaches() {
137 for (auto& cpu : cores) {
138 cpu->ArmInterface().ClearInstructionCache();
139 }
140}
141
142} // namespace Core
diff --git a/src/core/cpu_core_manager.h b/src/core/cpu_core_manager.h
new file mode 100644
index 000000000..a4d70ec56
--- /dev/null
+++ b/src/core/cpu_core_manager.h
@@ -0,0 +1,59 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <map>
9#include <memory>
10#include <thread>
11
12namespace Core {
13
14class Cpu;
15class CpuBarrier;
16class ExclusiveMonitor;
17class System;
18
19class CpuCoreManager {
20public:
21 CpuCoreManager();
22 CpuCoreManager(const CpuCoreManager&) = delete;
23 CpuCoreManager(CpuCoreManager&&) = delete;
24
25 ~CpuCoreManager();
26
27 CpuCoreManager& operator=(const CpuCoreManager&) = delete;
28 CpuCoreManager& operator=(CpuCoreManager&&) = delete;
29
30 void Initialize(System& system);
31 void Shutdown();
32
33 Cpu& GetCore(std::size_t index);
34 const Cpu& GetCore(std::size_t index) const;
35
36 Cpu& GetCurrentCore();
37 const Cpu& GetCurrentCore() const;
38
39 ExclusiveMonitor& GetExclusiveMonitor();
40 const ExclusiveMonitor& GetExclusiveMonitor() const;
41
42 void RunLoop(bool tight_loop);
43
44 void InvalidateAllInstructionCaches();
45
46private:
47 static constexpr std::size_t NUM_CPU_CORES = 4;
48
49 std::unique_ptr<ExclusiveMonitor> exclusive_monitor;
50 std::unique_ptr<CpuBarrier> barrier;
51 std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cores;
52 std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> core_threads;
53 std::size_t active_core{}; ///< Active core, only used in single thread mode
54
55 /// Map of guest threads to CPU cores
56 std::map<std::thread::id, Cpu*> thread_to_cpu;
57};
58
59} // namespace Core