core: Move common CPU core things to its own class.
This commit is contained in:
parent
5e9c547952
commit
5590245930
|
@ -4,6 +4,8 @@ add_library(core STATIC
|
||||||
arm/unicorn/arm_unicorn.h
|
arm/unicorn/arm_unicorn.h
|
||||||
core.cpp
|
core.cpp
|
||||||
core.h
|
core.h
|
||||||
|
core_cpu.cpp
|
||||||
|
core_cpu.h
|
||||||
core_timing.cpp
|
core_timing.cpp
|
||||||
core_timing.h
|
core_timing.h
|
||||||
file_sys/directory.h
|
file_sys/directory.h
|
||||||
|
|
|
@ -5,10 +5,6 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#ifdef ARCHITECTURE_x86_64
|
|
||||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
|
||||||
#endif
|
|
||||||
#include "core/arm/unicorn/arm_unicorn.h"
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/gdbstub/gdbstub.h"
|
#include "core/gdbstub/gdbstub.h"
|
||||||
|
@ -33,9 +29,6 @@ System::~System() = default;
|
||||||
|
|
||||||
System::ResultStatus System::RunLoop(bool tight_loop) {
|
System::ResultStatus System::RunLoop(bool tight_loop) {
|
||||||
status = ResultStatus::Success;
|
status = ResultStatus::Success;
|
||||||
if (!cpu_core) {
|
|
||||||
return ResultStatus::ErrorNotInitialized;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GDBStub::IsServerEnabled()) {
|
if (GDBStub::IsServerEnabled()) {
|
||||||
GDBStub::HandlePacket();
|
GDBStub::HandlePacket();
|
||||||
|
@ -52,24 +45,7 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't have a currently active thread then don't execute instructions,
|
cpu_cores[0]->RunLoop(tight_loop);
|
||||||
// instead advance to the next event and try to yield to the next thread
|
|
||||||
if (Kernel::GetCurrentThread() == nullptr) {
|
|
||||||
NGLOG_TRACE(Core_ARM, "Idling");
|
|
||||||
CoreTiming::Idle();
|
|
||||||
CoreTiming::Advance();
|
|
||||||
PrepareReschedule();
|
|
||||||
} else {
|
|
||||||
CoreTiming::Advance();
|
|
||||||
if (tight_loop) {
|
|
||||||
cpu_core->Run();
|
|
||||||
} else {
|
|
||||||
cpu_core->Step();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HW::Update();
|
|
||||||
Reschedule();
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -133,23 +109,13 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::PrepareReschedule() {
|
void System::PrepareReschedule() {
|
||||||
cpu_core->PrepareReschedule();
|
cpu_cores[0]->PrepareReschedule();
|
||||||
reschedule_pending = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PerfStats::Results System::GetAndResetPerfStats() {
|
PerfStats::Results System::GetAndResetPerfStats() {
|
||||||
return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs());
|
return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs());
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::Reschedule() {
|
|
||||||
if (!reschedule_pending) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
reschedule_pending = false;
|
|
||||||
Core::System::GetInstance().Scheduler().Reschedule();
|
|
||||||
}
|
|
||||||
|
|
||||||
System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
|
System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
|
||||||
NGLOG_DEBUG(HW_Memory, "initialized OK");
|
NGLOG_DEBUG(HW_Memory, "initialized OK");
|
||||||
|
|
||||||
|
@ -157,15 +123,8 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
|
||||||
|
|
||||||
current_process = Kernel::Process::Create("main");
|
current_process = Kernel::Process::Create("main");
|
||||||
|
|
||||||
if (Settings::values.use_cpu_jit) {
|
for (auto& cpu_core : cpu_cores) {
|
||||||
#ifdef ARCHITECTURE_x86_64
|
cpu_core = std::make_unique<Cpu>();
|
||||||
cpu_core = std::make_shared<ARM_Dynarmic>();
|
|
||||||
#else
|
|
||||||
cpu_core = std::make_shared<ARM_Unicorn>();
|
|
||||||
NGLOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
cpu_core = std::make_shared<ARM_Unicorn>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu_core = std::make_unique<Tegra::GPU>();
|
gpu_core = std::make_unique<Tegra::GPU>();
|
||||||
|
@ -176,7 +135,6 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
|
||||||
|
|
||||||
HW::Init();
|
HW::Init();
|
||||||
Kernel::Init(system_mode);
|
Kernel::Init(system_mode);
|
||||||
scheduler = std::make_unique<Kernel::Scheduler>(cpu_core.get());
|
|
||||||
Service::Init(service_manager);
|
Service::Init(service_manager);
|
||||||
GDBStub::Init();
|
GDBStub::Init();
|
||||||
|
|
||||||
|
@ -207,13 +165,16 @@ void System::Shutdown() {
|
||||||
VideoCore::Shutdown();
|
VideoCore::Shutdown();
|
||||||
GDBStub::Shutdown();
|
GDBStub::Shutdown();
|
||||||
Service::Shutdown();
|
Service::Shutdown();
|
||||||
scheduler.reset();
|
|
||||||
Kernel::Shutdown();
|
Kernel::Shutdown();
|
||||||
HW::Shutdown();
|
HW::Shutdown();
|
||||||
service_manager.reset();
|
service_manager.reset();
|
||||||
telemetry_session.reset();
|
telemetry_session.reset();
|
||||||
gpu_core.reset();
|
gpu_core.reset();
|
||||||
|
|
||||||
|
for (auto& cpu_core : cpu_cores) {
|
||||||
cpu_core.reset();
|
cpu_core.reset();
|
||||||
|
}
|
||||||
|
|
||||||
CoreTiming::Shutdown();
|
CoreTiming::Shutdown();
|
||||||
|
|
||||||
app_loader.reset();
|
app_loader.reset();
|
||||||
|
|
|
@ -4,9 +4,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/core_cpu.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/scheduler.h"
|
#include "core/hle/kernel/scheduler.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
|
@ -89,7 +91,7 @@ public:
|
||||||
* @returns True if the emulated system is powered on, otherwise false.
|
* @returns True if the emulated system is powered on, otherwise false.
|
||||||
*/
|
*/
|
||||||
bool IsPoweredOn() const {
|
bool IsPoweredOn() const {
|
||||||
return cpu_core != nullptr;
|
return cpu_cores[0] != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,7 +112,7 @@ public:
|
||||||
* @returns A reference to the emulated CPU.
|
* @returns A reference to the emulated CPU.
|
||||||
*/
|
*/
|
||||||
ARM_Interface& CPU() {
|
ARM_Interface& CPU() {
|
||||||
return *cpu_core;
|
return cpu_cores[0]->CPU();
|
||||||
}
|
}
|
||||||
|
|
||||||
Tegra::GPU& GPU() {
|
Tegra::GPU& GPU() {
|
||||||
|
@ -118,7 +120,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::Scheduler& Scheduler() {
|
Kernel::Scheduler& Scheduler() {
|
||||||
return *scheduler;
|
return cpu_cores[0]->Scheduler();
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::SharedPtr<Kernel::Process>& CurrentProcess() {
|
Kernel::SharedPtr<Kernel::Process>& CurrentProcess() {
|
||||||
|
@ -163,18 +165,12 @@ private:
|
||||||
*/
|
*/
|
||||||
ResultStatus Init(EmuWindow* emu_window, u32 system_mode);
|
ResultStatus Init(EmuWindow* emu_window, u32 system_mode);
|
||||||
|
|
||||||
/// Reschedule the core emulation
|
|
||||||
void Reschedule();
|
|
||||||
|
|
||||||
/// AppLoader used to load the current executing application
|
/// AppLoader used to load the current executing application
|
||||||
std::unique_ptr<Loader::AppLoader> app_loader;
|
std::unique_ptr<Loader::AppLoader> app_loader;
|
||||||
|
|
||||||
std::shared_ptr<ARM_Interface> cpu_core;
|
std::array<std::unique_ptr<Cpu>, 4> cpu_cores;
|
||||||
std::unique_ptr<Kernel::Scheduler> scheduler;
|
|
||||||
std::unique_ptr<Tegra::GPU> gpu_core;
|
std::unique_ptr<Tegra::GPU> gpu_core;
|
||||||
|
|
||||||
std::shared_ptr<Tegra::DebugContext> debug_context;
|
std::shared_ptr<Tegra::DebugContext> debug_context;
|
||||||
|
|
||||||
Kernel::SharedPtr<Kernel::Process> current_process;
|
Kernel::SharedPtr<Kernel::Process> current_process;
|
||||||
|
|
||||||
/// When true, signals that a reschedule should happen
|
/// When true, signals that a reschedule should happen
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright 2018 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#ifdef ARCHITECTURE_x86_64
|
||||||
|
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||||
|
#endif
|
||||||
|
#include "core/arm/unicorn/arm_unicorn.h"
|
||||||
|
#include "core/core_cpu.h"
|
||||||
|
#include "core/core_timing.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
#include "core/hle/kernel/scheduler.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
|
#include "core/settings.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
Cpu::Cpu() {
|
||||||
|
if (Settings::values.use_cpu_jit) {
|
||||||
|
#ifdef ARCHITECTURE_x86_64
|
||||||
|
arm_interface = std::make_shared<ARM_Dynarmic>();
|
||||||
|
#else
|
||||||
|
cpu_core = std::make_shared<ARM_Unicorn>();
|
||||||
|
NGLOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
arm_interface = std::make_shared<ARM_Unicorn>();
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduler = std::make_unique<Kernel::Scheduler>(arm_interface.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::RunLoop(bool tight_loop) {
|
||||||
|
// 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) {
|
||||||
|
NGLOG_TRACE(Core, "Idling");
|
||||||
|
CoreTiming::Idle();
|
||||||
|
CoreTiming::Advance();
|
||||||
|
PrepareReschedule();
|
||||||
|
} else {
|
||||||
|
CoreTiming::Advance();
|
||||||
|
if (tight_loop) {
|
||||||
|
arm_interface->Run();
|
||||||
|
} else {
|
||||||
|
arm_interface->Step();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reschedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::SingleStep() {
|
||||||
|
return RunLoop(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::PrepareReschedule() {
|
||||||
|
arm_interface->PrepareReschedule();
|
||||||
|
reschedule_pending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cpu::Reschedule() {
|
||||||
|
if (!reschedule_pending) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reschedule_pending = false;
|
||||||
|
scheduler->Reschedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2018 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
class ARM_Interface;
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
class Scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
class Cpu {
|
||||||
|
public:
|
||||||
|
Cpu();
|
||||||
|
|
||||||
|
void RunLoop(bool tight_loop = true);
|
||||||
|
|
||||||
|
void SingleStep();
|
||||||
|
|
||||||
|
void PrepareReschedule();
|
||||||
|
|
||||||
|
ARM_Interface& CPU() {
|
||||||
|
return *arm_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kernel::Scheduler& Scheduler() {
|
||||||
|
return *scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Reschedule();
|
||||||
|
|
||||||
|
std::shared_ptr<ARM_Interface> arm_interface;
|
||||||
|
std::unique_ptr<Kernel::Scheduler> scheduler;
|
||||||
|
|
||||||
|
bool reschedule_pending{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core
|
Loading…
Reference in New Issue