mirror of
https://github.com/yuzu-emu/yuzu-android.git
synced 2024-12-26 12:45:39 +00:00
Merge pull request #3353 from FernandoS27/aries
System: Refactor CPU Core management and move ARMInterface and Schedulers to Kernel
This commit is contained in:
commit
985d0f35e5
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
|
@ -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
src/core/core_manager.cpp
Normal file
70
src/core/core_manager.cpp
Normal file
|
@ -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
src/core/core_manager.h
Normal file
63
src/core/core_manager.h
Normal file
|
@ -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
|
|
@ -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
|
|
@ -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
src/core/cpu_manager.cpp
Normal file
83
src/core/cpu_manager.cpp
Normal file
|
@ -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
src/core/cpu_manager.h
Normal file
50
src/core/cpu_manager.h
Normal file
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
src/core/hle/kernel/physical_core.cpp
Normal file
52
src/core/hle/kernel/physical_core.cpp
Normal file
|
@ -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
src/core/hle/kernel/physical_core.h
Normal file
74
src/core/hle/kernel/physical_core.h
Normal file
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue