Răsfoiți Sursa

Merge pull request #3353 from FernandoS27/aries

System: Refactor CPU Core management and move ARMInterface and Schedulers to Kernel
bunnei 6 ani în urmă
părinte
comite
985d0f35e5

+ 6 - 4
src/core/CMakeLists.txt

@@ -15,14 +15,14 @@ add_library(core STATIC
     constants.h
     core.cpp
     core.h
-    core_cpu.cpp
-    core_cpu.h
+    core_manager.cpp
+    core_manager.h
     core_timing.cpp
     core_timing.h
     core_timing_util.cpp
     core_timing_util.h
-    cpu_core_manager.cpp
-    cpu_core_manager.h
+    cpu_manager.cpp
+    cpu_manager.h
     crypto/aes_util.cpp
     crypto/aes_util.h
     crypto/encryption_layer.cpp
@@ -158,6 +158,8 @@ add_library(core STATIC
     hle/kernel/mutex.h
     hle/kernel/object.cpp
     hle/kernel/object.h
+    hle/kernel/physical_core.cpp
+    hle/kernel/physical_core.h
     hle/kernel/process.cpp
     hle/kernel/process.h
     hle/kernel/process_capability.cpp

+ 1 - 1
src/core/arm/dynarmic/arm_dynarmic.cpp

@@ -10,7 +10,7 @@
 #include "common/microprofile.h"
 #include "core/arm/dynarmic/arm_dynarmic.h"
 #include "core/core.h"
-#include "core/core_cpu.h"
+#include "core/core_manager.h"
 #include "core/core_timing.h"
 #include "core/core_timing_util.h"
 #include "core/gdbstub/gdbstub.h"

+ 14 - 0
src/core/arm/exclusive_monitor.cpp

@@ -2,10 +2,24 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#ifdef ARCHITECTURE_x86_64
+#include "core/arm/dynarmic/arm_dynarmic.h"
+#endif
 #include "core/arm/exclusive_monitor.h"
+#include "core/memory.h"
 
 namespace Core {
 
 ExclusiveMonitor::~ExclusiveMonitor() = default;
 
+std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory,
+                                                             std::size_t num_cores) {
+#ifdef ARCHITECTURE_x86_64
+    return std::make_unique<Core::DynarmicExclusiveMonitor>(memory, num_cores);
+#else
+    // TODO(merry): Passthrough exclusive monitor
+    return nullptr;
+#endif
+}
+
 } // namespace Core

+ 9 - 0
src/core/arm/exclusive_monitor.h

@@ -4,8 +4,14 @@
 
 #pragma once
 
+#include <memory>
+
 #include "common/common_types.h"
 
+namespace Memory {
+class Memory;
+}
+
 namespace Core {
 
 class ExclusiveMonitor {
@@ -22,4 +28,7 @@ public:
     virtual bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) = 0;
 };
 
+std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory,
+                                                             std::size_t num_cores);
+
 } // namespace Core

+ 41 - 34
src/core/core.cpp

@@ -11,9 +11,9 @@
 #include "common/string_util.h"
 #include "core/arm/exclusive_monitor.h"
 #include "core/core.h"
-#include "core/core_cpu.h"
+#include "core/core_manager.h"
 #include "core/core_timing.h"
-#include "core/cpu_core_manager.h"
+#include "core/cpu_manager.h"
 #include "core/file_sys/bis_factory.h"
 #include "core/file_sys/card_image.h"
 #include "core/file_sys/mode.h"
@@ -28,6 +28,7 @@
 #include "core/hardware_interrupt_manager.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/physical_core.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/scheduler.h"
 #include "core/hle/kernel/thread.h"
@@ -113,16 +114,25 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
 struct System::Impl {
     explicit Impl(System& system)
         : kernel{system}, fs_controller{system}, memory{system},
-          cpu_core_manager{system}, reporter{system}, applet_manager{system} {}
+          cpu_manager{system}, reporter{system}, applet_manager{system} {}
 
-    Cpu& CurrentCpuCore() {
-        return cpu_core_manager.GetCurrentCore();
+    CoreManager& CurrentCoreManager() {
+        return cpu_manager.GetCurrentCoreManager();
+    }
+
+    Kernel::PhysicalCore& CurrentPhysicalCore() {
+        const auto index = cpu_manager.GetActiveCoreIndex();
+        return kernel.PhysicalCore(index);
+    }
+
+    Kernel::PhysicalCore& GetPhysicalCore(std::size_t index) {
+        return kernel.PhysicalCore(index);
     }
 
     ResultStatus RunLoop(bool tight_loop) {
         status = ResultStatus::Success;
 
-        cpu_core_manager.RunLoop(tight_loop);
+        cpu_manager.RunLoop(tight_loop);
 
         return status;
     }
@@ -131,8 +141,8 @@ struct System::Impl {
         LOG_DEBUG(HW_Memory, "initialized OK");
 
         core_timing.Initialize();
-        cpu_core_manager.Initialize();
         kernel.Initialize();
+        cpu_manager.Initialize();
 
         const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
             std::chrono::system_clock::now().time_since_epoch());
@@ -205,7 +215,6 @@ struct System::Impl {
         // Main process has been loaded and been made current.
         // Begin GPU and CPU execution.
         gpu_core->Start();
-        cpu_core_manager.StartThreads();
 
         // Initialize cheat engine
         if (cheat_engine) {
@@ -272,7 +281,7 @@ struct System::Impl {
         gpu_core.reset();
 
         // Close all CPU/threading state
-        cpu_core_manager.Shutdown();
+        cpu_manager.Shutdown();
 
         // Shutdown kernel and core timing
         kernel.Shutdown();
@@ -342,7 +351,7 @@ struct System::Impl {
     std::unique_ptr<Tegra::GPU> gpu_core;
     std::unique_ptr<Hardware::InterruptManager> interrupt_manager;
     Memory::Memory memory;
-    CpuCoreManager cpu_core_manager;
+    CpuManager cpu_manager;
     bool is_powered_on = false;
     bool exit_lock = false;
 
@@ -377,12 +386,12 @@ struct System::Impl {
 System::System() : impl{std::make_unique<Impl>(*this)} {}
 System::~System() = default;
 
-Cpu& System::CurrentCpuCore() {
-    return impl->CurrentCpuCore();
+CoreManager& System::CurrentCoreManager() {
+    return impl->CurrentCoreManager();
 }
 
-const Cpu& System::CurrentCpuCore() const {
-    return impl->CurrentCpuCore();
+const CoreManager& System::CurrentCoreManager() const {
+    return impl->CurrentCoreManager();
 }
 
 System::ResultStatus System::RunLoop(bool tight_loop) {
@@ -394,7 +403,7 @@ System::ResultStatus System::SingleStep() {
 }
 
 void System::InvalidateCpuInstructionCaches() {
-    impl->cpu_core_manager.InvalidateAllInstructionCaches();
+    impl->kernel.InvalidateAllInstructionCaches();
 }
 
 System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
@@ -406,13 +415,11 @@ bool System::IsPoweredOn() const {
 }
 
 void System::PrepareReschedule() {
-    CurrentCpuCore().PrepareReschedule();
+    impl->CurrentPhysicalCore().Stop();
 }
 
 void System::PrepareReschedule(const u32 core_index) {
-    if (core_index < GlobalScheduler().CpuCoresCount()) {
-        CpuCore(core_index).PrepareReschedule();
-    }
+    impl->kernel.PrepareReschedule(core_index);
 }
 
 PerfStatsResults System::GetAndResetPerfStats() {
@@ -428,31 +435,31 @@ const TelemetrySession& System::TelemetrySession() const {
 }
 
 ARM_Interface& System::CurrentArmInterface() {
-    return CurrentCpuCore().ArmInterface();
+    return impl->CurrentPhysicalCore().ArmInterface();
 }
 
 const ARM_Interface& System::CurrentArmInterface() const {
-    return CurrentCpuCore().ArmInterface();
+    return impl->CurrentPhysicalCore().ArmInterface();
 }
 
 std::size_t System::CurrentCoreIndex() const {
-    return CurrentCpuCore().CoreIndex();
+    return impl->cpu_manager.GetActiveCoreIndex();
 }
 
 Kernel::Scheduler& System::CurrentScheduler() {
-    return CurrentCpuCore().Scheduler();
+    return impl->CurrentPhysicalCore().Scheduler();
 }
 
 const Kernel::Scheduler& System::CurrentScheduler() const {
-    return CurrentCpuCore().Scheduler();
+    return impl->CurrentPhysicalCore().Scheduler();
 }
 
 Kernel::Scheduler& System::Scheduler(std::size_t core_index) {
-    return CpuCore(core_index).Scheduler();
+    return impl->GetPhysicalCore(core_index).Scheduler();
 }
 
 const Kernel::Scheduler& System::Scheduler(std::size_t core_index) const {
-    return CpuCore(core_index).Scheduler();
+    return impl->GetPhysicalCore(core_index).Scheduler();
 }
 
 /// Gets the global scheduler
@@ -474,28 +481,28 @@ const Kernel::Process* System::CurrentProcess() const {
 }
 
 ARM_Interface& System::ArmInterface(std::size_t core_index) {
-    return CpuCore(core_index).ArmInterface();
+    return impl->GetPhysicalCore(core_index).ArmInterface();
 }
 
 const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
-    return CpuCore(core_index).ArmInterface();
+    return impl->GetPhysicalCore(core_index).ArmInterface();
 }
 
-Cpu& System::CpuCore(std::size_t core_index) {
-    return impl->cpu_core_manager.GetCore(core_index);
+CoreManager& System::GetCoreManager(std::size_t core_index) {
+    return impl->cpu_manager.GetCoreManager(core_index);
 }
 
-const Cpu& System::CpuCore(std::size_t core_index) const {
+const CoreManager& System::GetCoreManager(std::size_t core_index) const {
     ASSERT(core_index < NUM_CPU_CORES);
-    return impl->cpu_core_manager.GetCore(core_index);
+    return impl->cpu_manager.GetCoreManager(core_index);
 }
 
 ExclusiveMonitor& System::Monitor() {
-    return impl->cpu_core_manager.GetExclusiveMonitor();
+    return impl->kernel.GetExclusiveMonitor();
 }
 
 const ExclusiveMonitor& System::Monitor() const {
-    return impl->cpu_core_manager.GetExclusiveMonitor();
+    return impl->kernel.GetExclusiveMonitor();
 }
 
 Memory::Memory& System::Memory() {

+ 5 - 5
src/core/core.h

@@ -93,7 +93,7 @@ class Memory;
 namespace Core {
 
 class ARM_Interface;
-class Cpu;
+class CoreManager;
 class ExclusiveMonitor;
 class FrameLimiter;
 class PerfStats;
@@ -218,10 +218,10 @@ public:
     const ARM_Interface& ArmInterface(std::size_t core_index) const;
 
     /// Gets a CPU interface to the CPU core with the specified index
-    Cpu& CpuCore(std::size_t core_index);
+    CoreManager& GetCoreManager(std::size_t core_index);
 
     /// Gets a CPU interface to the CPU core with the specified index
-    const Cpu& CpuCore(std::size_t core_index) const;
+    const CoreManager& GetCoreManager(std::size_t core_index) const;
 
     /// Gets a reference to the exclusive monitor
     ExclusiveMonitor& Monitor();
@@ -364,10 +364,10 @@ private:
     System();
 
     /// Returns the currently running CPU core
-    Cpu& CurrentCpuCore();
+    CoreManager& CurrentCoreManager();
 
     /// Returns the currently running CPU core
-    const Cpu& CurrentCpuCore() const;
+    const CoreManager& CurrentCoreManager() const;
 
     /**
      * Initialize the emulated system.

+ 0 - 127
src/core/core_cpu.cpp

@@ -1,127 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <condition_variable>
-#include <mutex>
-
-#include "common/logging/log.h"
-#ifdef ARCHITECTURE_x86_64
-#include "core/arm/dynarmic/arm_dynarmic.h"
-#endif
-#include "core/arm/exclusive_monitor.h"
-#include "core/arm/unicorn/arm_unicorn.h"
-#include "core/core.h"
-#include "core/core_cpu.h"
-#include "core/core_timing.h"
-#include "core/hle/kernel/scheduler.h"
-#include "core/hle/kernel/thread.h"
-#include "core/hle/lock.h"
-#include "core/settings.h"
-
-namespace Core {
-
-void CpuBarrier::NotifyEnd() {
-    std::unique_lock lock{mutex};
-    end = true;
-    condition.notify_all();
-}
-
-bool CpuBarrier::Rendezvous() {
-    if (!Settings::values.use_multi_core) {
-        // Meaningless when running in single-core mode
-        return true;
-    }
-
-    if (!end) {
-        std::unique_lock lock{mutex};
-
-        --cores_waiting;
-        if (!cores_waiting) {
-            cores_waiting = NUM_CPU_CORES;
-            condition.notify_all();
-            return true;
-        }
-
-        condition.wait(lock);
-        return true;
-    }
-
-    return false;
-}
-
-Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier,
-         std::size_t core_index)
-    : cpu_barrier{cpu_barrier}, global_scheduler{system.GlobalScheduler()},
-      core_timing{system.CoreTiming()}, core_index{core_index} {
-#ifdef ARCHITECTURE_x86_64
-    arm_interface = std::make_unique<ARM_Dynarmic>(system, exclusive_monitor, core_index);
-#else
-    arm_interface = std::make_unique<ARM_Unicorn>(system);
-    LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
-#endif
-
-    scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface, core_index);
-}
-
-Cpu::~Cpu() = default;
-
-std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(
-    [[maybe_unused]] Memory::Memory& memory, [[maybe_unused]] std::size_t num_cores) {
-#ifdef ARCHITECTURE_x86_64
-    return std::make_unique<DynarmicExclusiveMonitor>(memory, num_cores);
-#else
-    // TODO(merry): Passthrough exclusive monitor
-    return nullptr;
-#endif
-}
-
-void Cpu::RunLoop(bool tight_loop) {
-    // Wait for all other CPU cores to complete the previous slice, such that they run in lock-step
-    if (!cpu_barrier.Rendezvous()) {
-        // If rendezvous failed, session has been killed
-        return;
-    }
-
-    Reschedule();
-
-    // If we don't have a currently active thread then don't execute instructions,
-    // instead advance to the next event and try to yield to the next thread
-    if (Kernel::GetCurrentThread() == nullptr) {
-        LOG_TRACE(Core, "Core-{} idling", core_index);
-        core_timing.Idle();
-    } else {
-        if (tight_loop) {
-            arm_interface->Run();
-        } else {
-            arm_interface->Step();
-        }
-        // We are stopping a run, exclusive state must be cleared
-        arm_interface->ClearExclusiveState();
-    }
-    core_timing.Advance();
-
-    Reschedule();
-}
-
-void Cpu::SingleStep() {
-    return RunLoop(false);
-}
-
-void Cpu::PrepareReschedule() {
-    arm_interface->PrepareReschedule();
-}
-
-void Cpu::Reschedule() {
-    // Lock the global kernel mutex when we manipulate the HLE state
-    std::lock_guard lock(HLE::g_hle_lock);
-
-    global_scheduler.SelectThread(core_index);
-    scheduler->TryDoContextSwitch();
-}
-
-void Cpu::Shutdown() {
-    scheduler->Shutdown();
-}
-
-} // namespace Core

+ 0 - 120
src/core/core_cpu.h

@@ -1,120 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <atomic>
-#include <condition_variable>
-#include <cstddef>
-#include <memory>
-#include <mutex>
-#include "common/common_types.h"
-
-namespace Kernel {
-class GlobalScheduler;
-class Scheduler;
-} // namespace Kernel
-
-namespace Core {
-class System;
-}
-
-namespace Core::Timing {
-class CoreTiming;
-}
-
-namespace Memory {
-class Memory;
-}
-
-namespace Core {
-
-class ARM_Interface;
-class ExclusiveMonitor;
-
-constexpr unsigned NUM_CPU_CORES{4};
-
-class CpuBarrier {
-public:
-    bool IsAlive() const {
-        return !end;
-    }
-
-    void NotifyEnd();
-
-    bool Rendezvous();
-
-private:
-    unsigned cores_waiting{NUM_CPU_CORES};
-    std::mutex mutex;
-    std::condition_variable condition;
-    std::atomic<bool> end{};
-};
-
-class Cpu {
-public:
-    Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier,
-        std::size_t core_index);
-    ~Cpu();
-
-    void RunLoop(bool tight_loop = true);
-
-    void SingleStep();
-
-    void PrepareReschedule();
-
-    ARM_Interface& ArmInterface() {
-        return *arm_interface;
-    }
-
-    const ARM_Interface& ArmInterface() const {
-        return *arm_interface;
-    }
-
-    Kernel::Scheduler& Scheduler() {
-        return *scheduler;
-    }
-
-    const Kernel::Scheduler& Scheduler() const {
-        return *scheduler;
-    }
-
-    bool IsMainCore() const {
-        return core_index == 0;
-    }
-
-    std::size_t CoreIndex() const {
-        return core_index;
-    }
-
-    void Shutdown();
-
-    /**
-     * Creates an exclusive monitor to handle exclusive reads/writes.
-     *
-     * @param memory The current memory subsystem that the monitor may wish
-     *               to keep track of.
-     *
-     * @param num_cores The number of cores to assume about the CPU.
-     *
-     * @returns The constructed exclusive monitor instance, or nullptr if the current
-     *          CPU backend is unable to use an exclusive monitor.
-     */
-    static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory,
-                                                                  std::size_t num_cores);
-
-private:
-    void Reschedule();
-
-    std::unique_ptr<ARM_Interface> arm_interface;
-    CpuBarrier& cpu_barrier;
-    Kernel::GlobalScheduler& global_scheduler;
-    std::unique_ptr<Kernel::Scheduler> scheduler;
-    Timing::CoreTiming& core_timing;
-
-    std::atomic<bool> reschedule_pending = false;
-    std::size_t core_index;
-};
-
-} // namespace Core

+ 70 - 0
src/core/core_manager.cpp

@@ -0,0 +1,70 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <condition_variable>
+#include <mutex>
+
+#include "common/logging/log.h"
+#ifdef ARCHITECTURE_x86_64
+#include "core/arm/dynarmic/arm_dynarmic.h"
+#endif
+#include "core/arm/exclusive_monitor.h"
+#include "core/arm/unicorn/arm_unicorn.h"
+#include "core/core.h"
+#include "core/core_manager.h"
+#include "core/core_timing.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/physical_core.h"
+#include "core/hle/kernel/scheduler.h"
+#include "core/hle/kernel/thread.h"
+#include "core/hle/lock.h"
+#include "core/settings.h"
+
+namespace Core {
+
+CoreManager::CoreManager(System& system, std::size_t core_index)
+    : global_scheduler{system.GlobalScheduler()}, physical_core{system.Kernel().PhysicalCore(
+                                                      core_index)},
+      core_timing{system.CoreTiming()}, core_index{core_index} {}
+
+CoreManager::~CoreManager() = default;
+
+void CoreManager::RunLoop(bool tight_loop) {
+    Reschedule();
+
+    // If we don't have a currently active thread then don't execute instructions,
+    // instead advance to the next event and try to yield to the next thread
+    if (Kernel::GetCurrentThread() == nullptr) {
+        LOG_TRACE(Core, "Core-{} idling", core_index);
+        core_timing.Idle();
+    } else {
+        if (tight_loop) {
+            physical_core.Run();
+        } else {
+            physical_core.Step();
+        }
+    }
+    core_timing.Advance();
+
+    Reschedule();
+}
+
+void CoreManager::SingleStep() {
+    return RunLoop(false);
+}
+
+void CoreManager::PrepareReschedule() {
+    physical_core.Stop();
+}
+
+void CoreManager::Reschedule() {
+    // Lock the global kernel mutex when we manipulate the HLE state
+    std::lock_guard lock(HLE::g_hle_lock);
+
+    global_scheduler.SelectThread(core_index);
+
+    physical_core.Scheduler().TryDoContextSwitch();
+}
+
+} // namespace Core

+ 63 - 0
src/core/core_manager.h

@@ -0,0 +1,63 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <atomic>
+#include <cstddef>
+#include <memory>
+#include "common/common_types.h"
+
+namespace Kernel {
+class GlobalScheduler;
+class PhysicalCore;
+} // namespace Kernel
+
+namespace Core {
+class System;
+}
+
+namespace Core::Timing {
+class CoreTiming;
+}
+
+namespace Memory {
+class Memory;
+}
+
+namespace Core {
+
+constexpr unsigned NUM_CPU_CORES{4};
+
+class CoreManager {
+public:
+    CoreManager(System& system, std::size_t core_index);
+    ~CoreManager();
+
+    void RunLoop(bool tight_loop = true);
+
+    void SingleStep();
+
+    void PrepareReschedule();
+
+    bool IsMainCore() const {
+        return core_index == 0;
+    }
+
+    std::size_t CoreIndex() const {
+        return core_index;
+    }
+
+private:
+    void Reschedule();
+
+    Kernel::GlobalScheduler& global_scheduler;
+    Kernel::PhysicalCore& physical_core;
+    Timing::CoreTiming& core_timing;
+
+    std::atomic<bool> reschedule_pending = false;
+    std::size_t core_index;
+};
+
+} // namespace Core

+ 0 - 152
src/core/cpu_core_manager.cpp

@@ -1,152 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "common/assert.h"
-#include "core/arm/exclusive_monitor.h"
-#include "core/core.h"
-#include "core/core_cpu.h"
-#include "core/core_timing.h"
-#include "core/cpu_core_manager.h"
-#include "core/gdbstub/gdbstub.h"
-#include "core/settings.h"
-
-namespace Core {
-namespace {
-void RunCpuCore(const System& system, Cpu& cpu_state) {
-    while (system.IsPoweredOn()) {
-        cpu_state.RunLoop(true);
-    }
-}
-} // Anonymous namespace
-
-CpuCoreManager::CpuCoreManager(System& system) : system{system} {}
-CpuCoreManager::~CpuCoreManager() = default;
-
-void CpuCoreManager::Initialize() {
-    barrier = std::make_unique<CpuBarrier>();
-    exclusive_monitor = Cpu::MakeExclusiveMonitor(system.Memory(), cores.size());
-
-    for (std::size_t index = 0; index < cores.size(); ++index) {
-        cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index);
-    }
-}
-
-void CpuCoreManager::StartThreads() {
-    // Create threads for CPU cores 1-3, and build thread_to_cpu map
-    // CPU core 0 is run on the main thread
-    thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
-    if (!Settings::values.use_multi_core) {
-        return;
-    }
-
-    for (std::size_t index = 0; index < core_threads.size(); ++index) {
-        core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system),
-                                                            std::ref(*cores[index + 1]));
-        thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get();
-    }
-}
-
-void CpuCoreManager::Shutdown() {
-    barrier->NotifyEnd();
-    if (Settings::values.use_multi_core) {
-        for (auto& thread : core_threads) {
-            thread->join();
-            thread.reset();
-        }
-    }
-
-    thread_to_cpu.clear();
-    for (auto& cpu_core : cores) {
-        cpu_core->Shutdown();
-        cpu_core.reset();
-    }
-
-    exclusive_monitor.reset();
-    barrier.reset();
-}
-
-Cpu& CpuCoreManager::GetCore(std::size_t index) {
-    return *cores.at(index);
-}
-
-const Cpu& CpuCoreManager::GetCore(std::size_t index) const {
-    return *cores.at(index);
-}
-
-ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() {
-    return *exclusive_monitor;
-}
-
-const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const {
-    return *exclusive_monitor;
-}
-
-Cpu& CpuCoreManager::GetCurrentCore() {
-    if (Settings::values.use_multi_core) {
-        const auto& search = thread_to_cpu.find(std::this_thread::get_id());
-        ASSERT(search != thread_to_cpu.end());
-        ASSERT(search->second);
-        return *search->second;
-    }
-
-    // Otherwise, use single-threaded mode active_core variable
-    return *cores[active_core];
-}
-
-const Cpu& CpuCoreManager::GetCurrentCore() const {
-    if (Settings::values.use_multi_core) {
-        const auto& search = thread_to_cpu.find(std::this_thread::get_id());
-        ASSERT(search != thread_to_cpu.end());
-        ASSERT(search->second);
-        return *search->second;
-    }
-
-    // Otherwise, use single-threaded mode active_core variable
-    return *cores[active_core];
-}
-
-void CpuCoreManager::RunLoop(bool tight_loop) {
-    // Update thread_to_cpu in case Core 0 is run from a different host thread
-    thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
-
-    if (GDBStub::IsServerEnabled()) {
-        GDBStub::HandlePacket();
-
-        // If the loop is halted and we want to step, use a tiny (1) number of instructions to
-        // execute. Otherwise, get out of the loop function.
-        if (GDBStub::GetCpuHaltFlag()) {
-            if (GDBStub::GetCpuStepFlag()) {
-                tight_loop = false;
-            } else {
-                return;
-            }
-        }
-    }
-
-    auto& core_timing = system.CoreTiming();
-    core_timing.ResetRun();
-    bool keep_running{};
-    do {
-        keep_running = false;
-        for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
-            core_timing.SwitchContext(active_core);
-            if (core_timing.CanCurrentContextRun()) {
-                cores[active_core]->RunLoop(tight_loop);
-            }
-            keep_running |= core_timing.CanCurrentContextRun();
-        }
-    } while (keep_running);
-
-    if (GDBStub::IsServerEnabled()) {
-        GDBStub::SetCpuStepFlag(false);
-    }
-}
-
-void CpuCoreManager::InvalidateAllInstructionCaches() {
-    for (auto& cpu : cores) {
-        cpu->ArmInterface().ClearInstructionCache();
-    }
-}
-
-} // namespace Core

+ 0 - 62
src/core/cpu_core_manager.h

@@ -1,62 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <array>
-#include <map>
-#include <memory>
-#include <thread>
-
-namespace Core {
-
-class Cpu;
-class CpuBarrier;
-class ExclusiveMonitor;
-class System;
-
-class CpuCoreManager {
-public:
-    explicit CpuCoreManager(System& system);
-    CpuCoreManager(const CpuCoreManager&) = delete;
-    CpuCoreManager(CpuCoreManager&&) = delete;
-
-    ~CpuCoreManager();
-
-    CpuCoreManager& operator=(const CpuCoreManager&) = delete;
-    CpuCoreManager& operator=(CpuCoreManager&&) = delete;
-
-    void Initialize();
-    void StartThreads();
-    void Shutdown();
-
-    Cpu& GetCore(std::size_t index);
-    const Cpu& GetCore(std::size_t index) const;
-
-    Cpu& GetCurrentCore();
-    const Cpu& GetCurrentCore() const;
-
-    ExclusiveMonitor& GetExclusiveMonitor();
-    const ExclusiveMonitor& GetExclusiveMonitor() const;
-
-    void RunLoop(bool tight_loop);
-
-    void InvalidateAllInstructionCaches();
-
-private:
-    static constexpr std::size_t NUM_CPU_CORES = 4;
-
-    std::unique_ptr<ExclusiveMonitor> exclusive_monitor;
-    std::unique_ptr<CpuBarrier> barrier;
-    std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cores;
-    std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> core_threads;
-    std::size_t active_core{}; ///< Active core, only used in single thread mode
-
-    /// Map of guest threads to CPU cores
-    std::map<std::thread::id, Cpu*> thread_to_cpu;
-
-    System& system;
-};
-
-} // namespace Core

+ 83 - 0
src/core/cpu_manager.cpp

@@ -0,0 +1,83 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "core/arm/exclusive_monitor.h"
+#include "core/core.h"
+#include "core/core_manager.h"
+#include "core/core_timing.h"
+#include "core/cpu_manager.h"
+#include "core/gdbstub/gdbstub.h"
+#include "core/settings.h"
+
+namespace Core {
+
+CpuManager::CpuManager(System& system) : system{system} {}
+CpuManager::~CpuManager() = default;
+
+void CpuManager::Initialize() {
+    for (std::size_t index = 0; index < core_managers.size(); ++index) {
+        core_managers[index] = std::make_unique<CoreManager>(system, index);
+    }
+}
+
+void CpuManager::Shutdown() {
+    for (auto& cpu_core : core_managers) {
+        cpu_core.reset();
+    }
+}
+
+CoreManager& CpuManager::GetCoreManager(std::size_t index) {
+    return *core_managers.at(index);
+}
+
+const CoreManager& CpuManager::GetCoreManager(std::size_t index) const {
+    return *core_managers.at(index);
+}
+
+CoreManager& CpuManager::GetCurrentCoreManager() {
+    // Otherwise, use single-threaded mode active_core variable
+    return *core_managers[active_core];
+}
+
+const CoreManager& CpuManager::GetCurrentCoreManager() const {
+    // Otherwise, use single-threaded mode active_core variable
+    return *core_managers[active_core];
+}
+
+void CpuManager::RunLoop(bool tight_loop) {
+    if (GDBStub::IsServerEnabled()) {
+        GDBStub::HandlePacket();
+
+        // If the loop is halted and we want to step, use a tiny (1) number of instructions to
+        // execute. Otherwise, get out of the loop function.
+        if (GDBStub::GetCpuHaltFlag()) {
+            if (GDBStub::GetCpuStepFlag()) {
+                tight_loop = false;
+            } else {
+                return;
+            }
+        }
+    }
+
+    auto& core_timing = system.CoreTiming();
+    core_timing.ResetRun();
+    bool keep_running{};
+    do {
+        keep_running = false;
+        for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
+            core_timing.SwitchContext(active_core);
+            if (core_timing.CanCurrentContextRun()) {
+                core_managers[active_core]->RunLoop(tight_loop);
+            }
+            keep_running |= core_timing.CanCurrentContextRun();
+        }
+    } while (keep_running);
+
+    if (GDBStub::IsServerEnabled()) {
+        GDBStub::SetCpuStepFlag(false);
+    }
+}
+
+} // namespace Core

+ 50 - 0
src/core/cpu_manager.h

@@ -0,0 +1,50 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <memory>
+
+namespace Core {
+
+class CoreManager;
+class System;
+
+class CpuManager {
+public:
+    explicit CpuManager(System& system);
+    CpuManager(const CpuManager&) = delete;
+    CpuManager(CpuManager&&) = delete;
+
+    ~CpuManager();
+
+    CpuManager& operator=(const CpuManager&) = delete;
+    CpuManager& operator=(CpuManager&&) = delete;
+
+    void Initialize();
+    void Shutdown();
+
+    CoreManager& GetCoreManager(std::size_t index);
+    const CoreManager& GetCoreManager(std::size_t index) const;
+
+    CoreManager& GetCurrentCoreManager();
+    const CoreManager& GetCurrentCoreManager() const;
+
+    std::size_t GetActiveCoreIndex() const {
+        return active_core;
+    }
+
+    void RunLoop(bool tight_loop);
+
+private:
+    static constexpr std::size_t NUM_CPU_CORES = 4;
+
+    std::array<std::unique_ptr<CoreManager>, NUM_CPU_CORES> core_managers;
+    std::size_t active_core{}; ///< Active core, only used in single thread mode
+
+    System& system;
+};
+
+} // namespace Core

+ 1 - 1
src/core/gdbstub/gdbstub.cpp

@@ -35,7 +35,7 @@
 #include "common/swap.h"
 #include "core/arm/arm_interface.h"
 #include "core/core.h"
-#include "core/core_cpu.h"
+#include "core/core_manager.h"
 #include "core/gdbstub/gdbstub.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/scheduler.h"

+ 0 - 1
src/core/hle/kernel/address_arbiter.cpp

@@ -8,7 +8,6 @@
 #include "common/assert.h"
 #include "common/common_types.h"
 #include "core/core.h"
-#include "core/core_cpu.h"
 #include "core/hle/kernel/address_arbiter.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/scheduler.h"

+ 51 - 1
src/core/hle/kernel/kernel.cpp

@@ -3,13 +3,15 @@
 // Refer to the license.txt file included.
 
 #include <atomic>
+#include <functional>
 #include <memory>
 #include <mutex>
 #include <utility>
 
 #include "common/assert.h"
 #include "common/logging/log.h"
-
+#include "core/arm/arm_interface.h"
+#include "core/arm/exclusive_monitor.h"
 #include "core/core.h"
 #include "core/core_timing.h"
 #include "core/core_timing_util.h"
@@ -17,6 +19,7 @@
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/physical_core.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/resource_limit.h"
 #include "core/hle/kernel/scheduler.h"
@@ -98,6 +101,7 @@ struct KernelCore::Impl {
     void Initialize(KernelCore& kernel) {
         Shutdown();
 
+        InitializePhysicalCores(kernel);
         InitializeSystemResourceLimit(kernel);
         InitializeThreads();
         InitializePreemption();
@@ -121,6 +125,21 @@ struct KernelCore::Impl {
         global_scheduler.Shutdown();
 
         named_ports.clear();
+
+        for (auto& core : cores) {
+            core.Shutdown();
+        }
+        cores.clear();
+
+        exclusive_monitor.reset(nullptr);
+    }
+
+    void InitializePhysicalCores(KernelCore& kernel) {
+        exclusive_monitor =
+            Core::MakeExclusiveMonitor(system.Memory(), global_scheduler.CpuCoresCount());
+        for (std::size_t i = 0; i < global_scheduler.CpuCoresCount(); i++) {
+            cores.emplace_back(system, kernel, i, *exclusive_monitor);
+        }
     }
 
     // Creates the default system resource limit
@@ -186,6 +205,9 @@ struct KernelCore::Impl {
     /// the ConnectToPort SVC.
     NamedPortTable named_ports;
 
+    std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
+    std::vector<Kernel::PhysicalCore> cores;
+
     // System context
     Core::System& system;
 };
@@ -240,6 +262,34 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const {
     return impl->global_scheduler;
 }
 
+Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) {
+    return impl->cores[id];
+}
+
+const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {
+    return impl->cores[id];
+}
+
+Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
+    return *impl->exclusive_monitor;
+}
+
+const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const {
+    return *impl->exclusive_monitor;
+}
+
+void KernelCore::InvalidateAllInstructionCaches() {
+    for (std::size_t i = 0; i < impl->global_scheduler.CpuCoresCount(); i++) {
+        PhysicalCore(i).ArmInterface().ClearInstructionCache();
+    }
+}
+
+void KernelCore::PrepareReschedule(std::size_t id) {
+    if (id < impl->global_scheduler.CpuCoresCount()) {
+        impl->cores[id].Stop();
+    }
+}
+
 void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) {
     impl->named_ports.emplace(std::move(name), std::move(port));
 }

+ 18 - 1
src/core/hle/kernel/kernel.h

@@ -11,8 +11,9 @@
 #include "core/hle/kernel/object.h"
 
 namespace Core {
+class ExclusiveMonitor;
 class System;
-}
+} // namespace Core
 
 namespace Core::Timing {
 class CoreTiming;
@@ -25,6 +26,7 @@ class AddressArbiter;
 class ClientPort;
 class GlobalScheduler;
 class HandleTable;
+class PhysicalCore;
 class Process;
 class ResourceLimit;
 class Thread;
@@ -84,6 +86,21 @@ public:
     /// Gets the sole instance of the global scheduler
     const Kernel::GlobalScheduler& GlobalScheduler() const;
 
+    /// Gets the an instance of the respective physical CPU core.
+    Kernel::PhysicalCore& PhysicalCore(std::size_t id);
+
+    /// Gets the an instance of the respective physical CPU core.
+    const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const;
+
+    /// Stops execution of 'id' core, in order to reschedule a new thread.
+    void PrepareReschedule(std::size_t id);
+
+    Core::ExclusiveMonitor& GetExclusiveMonitor();
+
+    const Core::ExclusiveMonitor& GetExclusiveMonitor() const;
+
+    void InvalidateAllInstructionCaches();
+
     /// Adds a port to the named port table
     void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port);
 

+ 52 - 0
src/core/hle/kernel/physical_core.cpp

@@ -0,0 +1,52 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+#include "core/arm/arm_interface.h"
+#ifdef ARCHITECTURE_x86_64
+#include "core/arm/dynarmic/arm_dynarmic.h"
+#endif
+#include "core/arm/exclusive_monitor.h"
+#include "core/arm/unicorn/arm_unicorn.h"
+#include "core/core.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/physical_core.h"
+#include "core/hle/kernel/scheduler.h"
+#include "core/hle/kernel/thread.h"
+
+namespace Kernel {
+
+PhysicalCore::PhysicalCore(Core::System& system, KernelCore& kernel, std::size_t id,
+                           Core::ExclusiveMonitor& exclusive_monitor)
+    : core_index{id}, kernel{kernel} {
+#ifdef ARCHITECTURE_x86_64
+    arm_interface = std::make_shared<Core::ARM_Dynarmic>(system, exclusive_monitor, core_index);
+#else
+    arm_interface = std::make_shared<Core::ARM_Unicorn>(system);
+    LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
+#endif
+
+    scheduler = std::make_shared<Kernel::Scheduler>(system, *arm_interface, core_index);
+}
+
+PhysicalCore::~PhysicalCore() = default;
+
+void PhysicalCore::Run() {
+    arm_interface->Run();
+    arm_interface->ClearExclusiveState();
+}
+
+void PhysicalCore::Step() {
+    arm_interface->Step();
+}
+
+void PhysicalCore::Stop() {
+    arm_interface->PrepareReschedule();
+}
+
+void PhysicalCore::Shutdown() {
+    scheduler->Shutdown();
+}
+
+} // namespace Kernel

+ 74 - 0
src/core/hle/kernel/physical_core.h

@@ -0,0 +1,74 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <cstddef>
+#include <memory>
+
+namespace Kernel {
+class Scheduler;
+} // namespace Kernel
+
+namespace Core {
+class ARM_Interface;
+class ExclusiveMonitor;
+class System;
+} // namespace Core
+
+namespace Kernel {
+
+class PhysicalCore {
+public:
+    PhysicalCore(Core::System& system, KernelCore& kernel, std::size_t id,
+                 Core::ExclusiveMonitor& exclusive_monitor);
+
+    ~PhysicalCore();
+
+    /// Execute current jit state
+    void Run();
+    /// Execute a single instruction in current jit.
+    void Step();
+    /// Stop JIT execution/exit
+    void Stop();
+
+    // Shutdown this physical core.
+    void Shutdown();
+
+    Core::ARM_Interface& ArmInterface() {
+        return *arm_interface;
+    }
+
+    const Core::ARM_Interface& ArmInterface() const {
+        return *arm_interface;
+    }
+
+    bool IsMainCore() const {
+        return core_index == 0;
+    }
+
+    bool IsSystemCore() const {
+        return core_index == 3;
+    }
+
+    std::size_t CoreIndex() const {
+        return core_index;
+    }
+
+    Kernel::Scheduler& Scheduler() {
+        return *scheduler;
+    }
+
+    const Kernel::Scheduler& Scheduler() const {
+        return *scheduler;
+    }
+
+private:
+    std::size_t core_index;
+    KernelCore& kernel;
+    std::shared_ptr<Core::ARM_Interface> arm_interface;
+    std::shared_ptr<Kernel::Scheduler> scheduler;
+};
+
+} // namespace Kernel

+ 0 - 1
src/core/hle/kernel/scheduler.cpp

@@ -14,7 +14,6 @@
 #include "common/logging/log.h"
 #include "core/arm/arm_interface.h"
 #include "core/core.h"
-#include "core/core_cpu.h"
 #include "core/core_timing.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/process.h"

+ 1 - 1
src/core/hle/kernel/svc.cpp

@@ -15,7 +15,7 @@
 #include "common/string_util.h"
 #include "core/arm/exclusive_monitor.h"
 #include "core/core.h"
-#include "core/core_cpu.h"
+#include "core/core_manager.h"
 #include "core/core_timing.h"
 #include "core/core_timing_util.h"
 #include "core/hle/kernel/address_arbiter.h"

+ 1 - 2
src/core/hle/kernel/thread.cpp

@@ -13,7 +13,6 @@
 #include "common/thread_queue_list.h"
 #include "core/arm/arm_interface.h"
 #include "core/core.h"
-#include "core/core_cpu.h"
 #include "core/core_timing.h"
 #include "core/core_timing_util.h"
 #include "core/hle/kernel/errors.h"
@@ -356,7 +355,7 @@ void Thread::SetActivity(ThreadActivity value) {
         // Set status if not waiting
         if (status == ThreadStatus::Ready || status == ThreadStatus::Running) {
             SetStatus(ThreadStatus::Paused);
-            Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
+            kernel.PrepareReschedule(processor_id);
         }
     } else if (status == ThreadStatus::Paused) {
         // Ready to reschedule

+ 1 - 2
src/core/hle/kernel/wait_object.cpp

@@ -7,7 +7,6 @@
 #include "common/common_types.h"
 #include "common/logging/log.h"
 #include "core/core.h"
-#include "core/core_cpu.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/process.h"
@@ -96,7 +95,7 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
     }
     if (resume) {
         thread->ResumeFromWait();
-        Core::System::GetInstance().PrepareReschedule(thread->GetProcessorID());
+        kernel.PrepareReschedule(thread->GetProcessorID());
     }
 }