diff options
Diffstat (limited to 'src/core/core.cpp')
| -rw-r--r-- | src/core/core.cpp | 172 |
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 |
