diff options
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/core.cpp | 119 | ||||
| -rw-r--r-- | src/core/cpu_core_manager.cpp | 142 | ||||
| -rw-r--r-- | src/core/cpu_core_manager.h | 59 |
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 | ||
| 76 | void 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 | ||
| 83 | struct System::Impl { | 76 | struct 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 | ||
| 336 | void System::InvalidateCpuInstructionCaches() { | 264 | void System::InvalidateCpuInstructionCaches() { |
| 337 | for (auto& cpu : impl->cpu_cores) { | 265 | impl->cpu_core_manager.InvalidateAllInstructionCaches(); |
| 338 | cpu->ArmInterface().ClearInstructionCache(); | ||
| 339 | } | ||
| 340 | } | 266 | } |
| 341 | 267 | ||
| 342 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { | 268 | System::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 | ||
| 346 | bool System::IsPoweredOn() const { | 272 | bool System::IsPoweredOn() const { |
| 347 | return impl->cpu_barrier && impl->cpu_barrier->IsAlive(); | 273 | return impl->is_powered_on; |
| 348 | } | 274 | } |
| 349 | 275 | ||
| 350 | void System::PrepareReschedule() { | 276 | void System::PrepareReschedule() { |
| @@ -408,21 +334,20 @@ const ARM_Interface& System::ArmInterface(std::size_t core_index) const { | |||
| 408 | } | 334 | } |
| 409 | 335 | ||
| 410 | Cpu& System::CpuCore(std::size_t core_index) { | 336 | Cpu& 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 | ||
| 415 | const Cpu& System::CpuCore(std::size_t core_index) const { | 340 | const 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 | ||
| 420 | ExclusiveMonitor& System::Monitor() { | 345 | ExclusiveMonitor& System::Monitor() { |
| 421 | return *impl->cpu_exclusive_monitor; | 346 | return impl->cpu_core_manager.GetExclusiveMonitor(); |
| 422 | } | 347 | } |
| 423 | 348 | ||
| 424 | const ExclusiveMonitor& System::Monitor() const { | 349 | const ExclusiveMonitor& System::Monitor() const { |
| 425 | return *impl->cpu_exclusive_monitor; | 350 | return impl->cpu_core_manager.GetExclusiveMonitor(); |
| 426 | } | 351 | } |
| 427 | 352 | ||
| 428 | Tegra::GPU& System::GPU() { | 353 | Tegra::GPU& System::GPU() { |
| @@ -506,7 +431,7 @@ const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() cons | |||
| 506 | } | 431 | } |
| 507 | 432 | ||
| 508 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | 433 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { |
| 509 | return impl->Init(emu_window); | 434 | return impl->Init(*this, emu_window); |
| 510 | } | 435 | } |
| 511 | 436 | ||
| 512 | void System::Shutdown() { | 437 | void 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 | |||
| 13 | namespace Core { | ||
| 14 | namespace { | ||
| 15 | void RunCpuCore(const System& system, Cpu& cpu_state) { | ||
| 16 | while (system.IsPoweredOn()) { | ||
| 17 | cpu_state.RunLoop(true); | ||
| 18 | } | ||
| 19 | } | ||
| 20 | } // Anonymous namespace | ||
| 21 | |||
| 22 | CpuCoreManager::CpuCoreManager() = default; | ||
| 23 | CpuCoreManager::~CpuCoreManager() = default; | ||
| 24 | |||
| 25 | void 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 | |||
| 47 | void 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 | |||
| 65 | Cpu& CpuCoreManager::GetCore(std::size_t index) { | ||
| 66 | return *cores.at(index); | ||
| 67 | } | ||
| 68 | |||
| 69 | const Cpu& CpuCoreManager::GetCore(std::size_t index) const { | ||
| 70 | return *cores.at(index); | ||
| 71 | } | ||
| 72 | |||
| 73 | ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() { | ||
| 74 | return *exclusive_monitor; | ||
| 75 | } | ||
| 76 | |||
| 77 | const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const { | ||
| 78 | return *exclusive_monitor; | ||
| 79 | } | ||
| 80 | |||
| 81 | Cpu& 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 | |||
| 93 | const 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 | |||
| 105 | void 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 | |||
| 136 | void 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 | |||
| 12 | namespace Core { | ||
| 13 | |||
| 14 | class Cpu; | ||
| 15 | class CpuBarrier; | ||
| 16 | class ExclusiveMonitor; | ||
| 17 | class System; | ||
| 18 | |||
| 19 | class CpuCoreManager { | ||
| 20 | public: | ||
| 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 | |||
| 46 | private: | ||
| 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 | ||