aboutsummaryrefslogtreecommitdiff
path: root/src/core/core.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/core.cpp')
-rw-r--r--src/core/core.cpp172
1 files changed, 111 insertions, 61 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 4fb035556..84ab876cc 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -5,17 +5,16 @@
#include <memory>
#include <utility>
#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_timing.h"
#include "core/gdbstub/gdbstub.h"
+#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/service/service.h"
+#include "core/hle/service/sm/controller.h"
+#include "core/hle/service/sm/sm.h"
#include "core/hw/hw.h"
#include "core/loader/loader.h"
#include "core/memory_setup.h"
@@ -26,12 +25,34 @@ namespace Core {
/*static*/ System System::s_instance;
-System::ResultStatus System::RunLoop(int tight_loop) {
- status = ResultStatus::Success;
- if (!cpu_core) {
- return ResultStatus::ErrorNotInitialized;
+System::~System() = default;
+
+/// Runs a CPU core while the system is powered on
+static void RunCpuCore(std::shared_ptr<Cpu> cpu_state) {
+ while (Core::System().GetInstance().IsPoweredOn()) {
+ cpu_state->RunLoop(true);
+ }
+}
+
+Cpu& System::CurrentCpuCore() {
+ // If multicore is enabled, use host thread to figure out the current CPU core
+ 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 *cpu_cores[active_core];
+}
+
+System::ResultStatus System::RunLoop(bool tight_loop) {
+ status = ResultStatus::Success;
+
+ // Update thread_to_cpu in case Core 0 is run from a different host thread
+ thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0];
+
if (GDBStub::IsServerEnabled()) {
GDBStub::HandlePacket();
@@ -40,54 +61,49 @@ System::ResultStatus System::RunLoop(int tight_loop) {
if (GDBStub::GetCpuHaltFlag()) {
if (GDBStub::GetCpuStepFlag()) {
GDBStub::SetCpuStepFlag(false);
- tight_loop = 1;
+ tight_loop = false;
} else {
return ResultStatus::Success;
}
}
}
- // 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_ARM, "Idling");
- CoreTiming::Idle();
- CoreTiming::Advance();
- PrepareReschedule();
- } else {
- CoreTiming::Advance();
- cpu_core->Run(tight_loop);
+ for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
+ cpu_cores[active_core]->RunLoop(tight_loop);
+ if (Settings::values.use_multi_core) {
+ // Cores 1-3 are run on other threads in this mode
+ break;
+ }
}
- HW::Update();
- Reschedule();
-
return status;
}
System::ResultStatus System::SingleStep() {
- return RunLoop(1);
+ return RunLoop(false);
}
System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& filepath) {
app_loader = Loader::GetLoader(filepath);
if (!app_loader) {
- LOG_CRITICAL(Core, "Failed to obtain loader for %s!", filepath.c_str());
+ NGLOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
return ResultStatus::ErrorGetLoader;
}
std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode =
app_loader->LoadKernelSystemMode();
if (system_mode.second != Loader::ResultStatus::Success) {
- LOG_CRITICAL(Core, "Failed to determine system mode (Error %i)!",
- static_cast<int>(system_mode.second));
+ NGLOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
+ static_cast<int>(system_mode.second));
switch (system_mode.second) {
case Loader::ResultStatus::ErrorEncrypted:
return ResultStatus::ErrorLoader_ErrorEncrypted;
case Loader::ResultStatus::ErrorInvalidFormat:
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
+ case Loader::ResultStatus::ErrorUnsupportedArch:
+ return ResultStatus::ErrorUnsupportedArch;
default:
return ResultStatus::ErrorSystemMode;
}
@@ -95,14 +111,15 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
ResultStatus init_result{Init(emu_window, system_mode.first.get())};
if (init_result != ResultStatus::Success) {
- LOG_CRITICAL(Core, "Failed to initialize system (Error %i)!", init_result);
+ NGLOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
+ static_cast<int>(init_result));
System::Shutdown();
return init_result;
}
- const Loader::ResultStatus load_result{app_loader->Load(Kernel::g_current_process)};
+ const Loader::ResultStatus load_result{app_loader->Load(current_process)};
if (Loader::ResultStatus::Success != load_result) {
- LOG_CRITICAL(Core, "Failed to load ROM (Error %i)!", load_result);
+ NGLOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
System::Shutdown();
switch (load_result) {
@@ -110,6 +127,8 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
return ResultStatus::ErrorLoader_ErrorEncrypted;
case Loader::ResultStatus::ErrorInvalidFormat:
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
+ case Loader::ResultStatus::ErrorUnsupportedArch:
+ return ResultStatus::ErrorUnsupportedArch;
default:
return ResultStatus::ErrorLoader;
}
@@ -119,58 +138,65 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
}
void System::PrepareReschedule() {
- cpu_core->PrepareReschedule();
- reschedule_pending = true;
+ CurrentCpuCore().PrepareReschedule();
}
PerfStats::Results System::GetAndResetPerfStats() {
return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs());
}
-void System::Reschedule() {
- if (!reschedule_pending) {
- return;
- }
+const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(size_t core_index) {
+ ASSERT(core_index < NUM_CPU_CORES);
+ return cpu_cores[core_index]->Scheduler();
+}
- reschedule_pending = false;
- Core::System::GetInstance().Scheduler().Reschedule();
+ARM_Interface& System::ArmInterface(size_t core_index) {
+ ASSERT(core_index < NUM_CPU_CORES);
+ return cpu_cores[core_index]->ArmInterface();
+}
+
+Cpu& System::CpuCore(size_t core_index) {
+ ASSERT(core_index < NUM_CPU_CORES);
+ return *cpu_cores[core_index];
}
System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
- LOG_DEBUG(HW_Memory, "initialized OK");
+ NGLOG_DEBUG(HW_Memory, "initialized OK");
CoreTiming::Init();
- switch (Settings::values.cpu_core) {
- case Settings::CpuCore::Unicorn:
- cpu_core = std::make_shared<ARM_Unicorn>();
- break;
- case Settings::CpuCore::Dynarmic:
- default:
-#ifdef ARCHITECTURE_x86_64
- cpu_core = std::make_shared<ARM_Dynarmic>();
-#else
- cpu_core = std::make_shared<ARM_Unicorn>();
- LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
-#endif
- break;
+ current_process = Kernel::Process::Create("main");
+
+ cpu_barrier = std::make_shared<CpuBarrier>();
+ for (size_t index = 0; index < cpu_cores.size(); ++index) {
+ cpu_cores[index] = std::make_shared<Cpu>(cpu_barrier, index);
}
gpu_core = std::make_unique<Tegra::GPU>();
-
telemetry_session = std::make_unique<Core::TelemetrySession>();
+ service_manager = std::make_shared<Service::SM::ServiceManager>();
HW::Init();
Kernel::Init(system_mode);
- scheduler = std::make_unique<Kernel::Scheduler>(cpu_core.get());
- Service::Init();
+ Service::Init(service_manager);
GDBStub::Init();
if (!VideoCore::Init(emu_window)) {
return ResultStatus::ErrorVideoCore;
}
- LOG_DEBUG(Core, "Initialized OK");
+ // 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()] = cpu_cores[0];
+ if (Settings::values.use_multi_core) {
+ for (size_t index = 0; index < cpu_core_threads.size(); ++index) {
+ cpu_core_threads[index] =
+ std::make_unique<std::thread>(RunCpuCore, cpu_cores[index + 1]);
+ thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1];
+ }
+ }
+
+ NGLOG_DEBUG(Core, "Initialized OK");
// Reset counters and set time origin to current frame
GetAndResetPerfStats();
@@ -193,17 +219,41 @@ void System::Shutdown() {
VideoCore::Shutdown();
GDBStub::Shutdown();
Service::Shutdown();
- scheduler = nullptr;
Kernel::Shutdown();
HW::Shutdown();
- telemetry_session = nullptr;
- gpu_core = nullptr;
- cpu_core = nullptr;
+ service_manager.reset();
+ telemetry_session.reset();
+ gpu_core.reset();
+
+ // Close all CPU/threading state
+ cpu_barrier->NotifyEnd();
+ if (Settings::values.use_multi_core) {
+ for (auto& thread : cpu_core_threads) {
+ thread->join();
+ thread.reset();
+ }
+ }
+ thread_to_cpu.clear();
+ for (auto& cpu_core : cpu_cores) {
+ cpu_core.reset();
+ }
+ cpu_barrier.reset();
+
+ // Close core timing
CoreTiming::Shutdown();
- app_loader = nullptr;
+ // Close app loader
+ app_loader.reset();
+
+ NGLOG_DEBUG(Core, "Shutdown OK");
+}
+
+Service::SM::ServiceManager& System::ServiceManager() {
+ return *service_manager;
+}
- LOG_DEBUG(Core, "Shutdown OK");
+const Service::SM::ServiceManager& System::ServiceManager() const {
+ return *service_manager;
}
} // namespace Core