General: Initial Setup for Single Core.
This commit is contained in:
		
							parent
							
								
									391f5f360d
								
							
						
					
					
						commit
						ab9aae28bf
					
				@ -149,6 +149,9 @@ struct System::Impl {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        device_memory = std::make_unique<Core::DeviceMemory>(system);
 | 
					        device_memory = std::make_unique<Core::DeviceMemory>(system);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        kernel.SetMulticore(Settings::values.use_multi_core);
 | 
				
			||||||
 | 
					        cpu_manager.SetMulticore(Settings::values.use_multi_core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        core_timing.Initialize([&system]() { system.RegisterHostThread(); });
 | 
					        core_timing.Initialize([&system]() { system.RegisterHostThread(); });
 | 
				
			||||||
        kernel.Initialize();
 | 
					        kernel.Initialize();
 | 
				
			||||||
        cpu_manager.Initialize();
 | 
					        cpu_manager.Initialize();
 | 
				
			||||||
 | 
				
			|||||||
@ -26,9 +26,13 @@ void CpuManager::ThreadStart(CpuManager& cpu_manager, std::size_t core) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void CpuManager::Initialize() {
 | 
					void CpuManager::Initialize() {
 | 
				
			||||||
    running_mode = true;
 | 
					    running_mode = true;
 | 
				
			||||||
    for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
 | 
					    if (is_multicore) {
 | 
				
			||||||
        core_data[core].host_thread =
 | 
					        for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
 | 
				
			||||||
            std::make_unique<std::thread>(ThreadStart, std::ref(*this), core);
 | 
					            core_data[core].host_thread =
 | 
				
			||||||
 | 
					                std::make_unique<std::thread>(ThreadStart, std::ref(*this), core);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        core_data[0].host_thread = std::make_unique<std::thread>(ThreadStart, std::ref(*this), 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -41,26 +45,6 @@ void CpuManager::Shutdown() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CpuManager::GuestThreadFunction(void* cpu_manager_) {
 | 
					 | 
				
			||||||
    CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
 | 
					 | 
				
			||||||
    cpu_manager->RunGuestThread();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void CpuManager::GuestRewindFunction(void* cpu_manager_) {
 | 
					 | 
				
			||||||
    CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
 | 
					 | 
				
			||||||
    cpu_manager->RunGuestLoop();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void CpuManager::IdleThreadFunction(void* cpu_manager_) {
 | 
					 | 
				
			||||||
    CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
 | 
					 | 
				
			||||||
    cpu_manager->RunIdleThread();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void CpuManager::SuspendThreadFunction(void* cpu_manager_) {
 | 
					 | 
				
			||||||
    CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
 | 
					 | 
				
			||||||
    cpu_manager->RunSuspendThread();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
 | 
					std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
 | 
				
			||||||
    return std::function<void(void*)>(GuestThreadFunction);
 | 
					    return std::function<void(void*)>(GuestThreadFunction);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -73,20 +57,60 @@ std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() {
 | 
				
			|||||||
    return std::function<void(void*)>(SuspendThreadFunction);
 | 
					    return std::function<void(void*)>(SuspendThreadFunction);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CpuManager::GuestThreadFunction(void* cpu_manager_) {
 | 
				
			||||||
 | 
					    CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
 | 
				
			||||||
 | 
					    if (cpu_manager->is_multicore) {
 | 
				
			||||||
 | 
					        cpu_manager->MultiCoreRunGuestThread();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        cpu_manager->SingleCoreRunGuestThread();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CpuManager::GuestRewindFunction(void* cpu_manager_) {
 | 
				
			||||||
 | 
					    CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
 | 
				
			||||||
 | 
					    if (cpu_manager->is_multicore) {
 | 
				
			||||||
 | 
					        cpu_manager->MultiCoreRunGuestLoop();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        cpu_manager->SingleCoreRunGuestLoop();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CpuManager::IdleThreadFunction(void* cpu_manager_) {
 | 
				
			||||||
 | 
					    CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
 | 
				
			||||||
 | 
					    if (cpu_manager->is_multicore) {
 | 
				
			||||||
 | 
					        cpu_manager->MultiCoreRunIdleThread();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        cpu_manager->SingleCoreRunIdleThread();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CpuManager::SuspendThreadFunction(void* cpu_manager_) {
 | 
				
			||||||
 | 
					    CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
 | 
				
			||||||
 | 
					    if (cpu_manager->is_multicore) {
 | 
				
			||||||
 | 
					        cpu_manager->MultiCoreRunSuspendThread();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        cpu_manager->SingleCoreRunSuspendThread();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void* CpuManager::GetStartFuncParamater() {
 | 
					void* CpuManager::GetStartFuncParamater() {
 | 
				
			||||||
    return static_cast<void*>(this);
 | 
					    return static_cast<void*>(this);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CpuManager::RunGuestThread() {
 | 
					///////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					///                             MultiCore                                   ///
 | 
				
			||||||
 | 
					///////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CpuManager::MultiCoreRunGuestThread() {
 | 
				
			||||||
    auto& kernel = system.Kernel();
 | 
					    auto& kernel = system.Kernel();
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        auto& sched = kernel.CurrentScheduler();
 | 
					        auto& sched = kernel.CurrentScheduler();
 | 
				
			||||||
        sched.OnThreadStart();
 | 
					        sched.OnThreadStart();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    RunGuestLoop();
 | 
					    MultiCoreRunGuestLoop();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CpuManager::RunGuestLoop() {
 | 
					void CpuManager::MultiCoreRunGuestLoop() {
 | 
				
			||||||
    auto& kernel = system.Kernel();
 | 
					    auto& kernel = system.Kernel();
 | 
				
			||||||
    auto* thread = kernel.CurrentScheduler().GetCurrentThread();
 | 
					    auto* thread = kernel.CurrentScheduler().GetCurrentThread();
 | 
				
			||||||
    auto host_context = thread->GetHostContext();
 | 
					    auto host_context = thread->GetHostContext();
 | 
				
			||||||
@ -103,7 +127,7 @@ void CpuManager::RunGuestLoop() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CpuManager::RunIdleThread() {
 | 
					void CpuManager::MultiCoreRunIdleThread() {
 | 
				
			||||||
    auto& kernel = system.Kernel();
 | 
					    auto& kernel = system.Kernel();
 | 
				
			||||||
    while (true) {
 | 
					    while (true) {
 | 
				
			||||||
        auto& physical_core = kernel.CurrentPhysicalCore();
 | 
					        auto& physical_core = kernel.CurrentPhysicalCore();
 | 
				
			||||||
@ -113,7 +137,7 @@ void CpuManager::RunIdleThread() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CpuManager::RunSuspendThread() {
 | 
					void CpuManager::MultiCoreRunSuspendThread() {
 | 
				
			||||||
    auto& kernel = system.Kernel();
 | 
					    auto& kernel = system.Kernel();
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        auto& sched = kernel.CurrentScheduler();
 | 
					        auto& sched = kernel.CurrentScheduler();
 | 
				
			||||||
@ -130,7 +154,7 @@ void CpuManager::RunSuspendThread() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CpuManager::Pause(bool paused) {
 | 
					void CpuManager::MultiCorePause(bool paused) {
 | 
				
			||||||
    if (!paused) {
 | 
					    if (!paused) {
 | 
				
			||||||
        bool all_not_barrier = false;
 | 
					        bool all_not_barrier = false;
 | 
				
			||||||
        while (!all_not_barrier) {
 | 
					        while (!all_not_barrier) {
 | 
				
			||||||
@ -171,10 +195,120 @@ void CpuManager::Pause(bool paused) {
 | 
				
			|||||||
    paused_state = paused;
 | 
					    paused_state = paused;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					///                             SingleCore                                   ///
 | 
				
			||||||
 | 
					///////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CpuManager::SingleCoreRunGuestThread() {
 | 
				
			||||||
 | 
					    auto& kernel = system.Kernel();
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto& sched = kernel.CurrentScheduler();
 | 
				
			||||||
 | 
					        sched.OnThreadStart();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    SingleCoreRunGuestLoop();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CpuManager::SingleCoreRunGuestLoop() {
 | 
				
			||||||
 | 
					    auto& kernel = system.Kernel();
 | 
				
			||||||
 | 
					    auto* thread = kernel.CurrentScheduler().GetCurrentThread();
 | 
				
			||||||
 | 
					    auto host_context = thread->GetHostContext();
 | 
				
			||||||
 | 
					    host_context->SetRewindPoint(std::function<void(void*)>(GuestRewindFunction), this);
 | 
				
			||||||
 | 
					    host_context.reset();
 | 
				
			||||||
 | 
					    while (true) {
 | 
				
			||||||
 | 
					        auto& physical_core = kernel.CurrentPhysicalCore();
 | 
				
			||||||
 | 
					        while (!physical_core.IsInterrupted()) {
 | 
				
			||||||
 | 
					            physical_core.Run();
 | 
				
			||||||
 | 
					            preemption_count++;
 | 
				
			||||||
 | 
					            if (preemption_count % max_cycle_runs == 0) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        physical_core.ClearExclusive();
 | 
				
			||||||
 | 
					        PreemptSingleCore();
 | 
				
			||||||
 | 
					        auto& scheduler = physical_core.Scheduler();
 | 
				
			||||||
 | 
					        scheduler.TryDoContextSwitch();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CpuManager::SingleCoreRunIdleThread() {
 | 
				
			||||||
 | 
					    auto& kernel = system.Kernel();
 | 
				
			||||||
 | 
					    while (true) {
 | 
				
			||||||
 | 
					        auto& physical_core = kernel.CurrentPhysicalCore();
 | 
				
			||||||
 | 
					        PreemptSingleCore();
 | 
				
			||||||
 | 
					        auto& scheduler = physical_core.Scheduler();
 | 
				
			||||||
 | 
					        scheduler.TryDoContextSwitch();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CpuManager::SingleCoreRunSuspendThread() {
 | 
				
			||||||
 | 
					    auto& kernel = system.Kernel();
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto& sched = kernel.CurrentScheduler();
 | 
				
			||||||
 | 
					        sched.OnThreadStart();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    while (true) {
 | 
				
			||||||
 | 
					        auto core = kernel.GetCurrentHostThreadID();
 | 
				
			||||||
 | 
					        auto& scheduler = kernel.CurrentScheduler();
 | 
				
			||||||
 | 
					        Kernel::Thread* current_thread = scheduler.GetCurrentThread();
 | 
				
			||||||
 | 
					        Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context);
 | 
				
			||||||
 | 
					        ASSERT(scheduler.ContextSwitchPending());
 | 
				
			||||||
 | 
					        ASSERT(core == kernel.GetCurrentHostThreadID());
 | 
				
			||||||
 | 
					        scheduler.TryDoContextSwitch();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CpuManager::PreemptSingleCore() {
 | 
				
			||||||
 | 
					    preemption_count = 0;
 | 
				
			||||||
 | 
					    std::size_t old_core = current_core;
 | 
				
			||||||
 | 
					    current_core = (current_core + 1) % Core::Hardware::NUM_CPU_CORES;
 | 
				
			||||||
 | 
					    auto& scheduler = system.Kernel().Scheduler(old_core);
 | 
				
			||||||
 | 
					    Kernel::Thread* current_thread = system.Kernel().Scheduler(old_core).GetCurrentThread();
 | 
				
			||||||
 | 
					    Kernel::Thread* next_thread = system.Kernel().Scheduler(current_core).GetCurrentThread();
 | 
				
			||||||
 | 
					    Common::Fiber::YieldTo(current_thread->GetHostContext(), next_thread->GetHostContext());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CpuManager::SingleCorePause(bool paused) {
 | 
				
			||||||
 | 
					    if (!paused) {
 | 
				
			||||||
 | 
					        bool all_not_barrier = false;
 | 
				
			||||||
 | 
					        while (!all_not_barrier) {
 | 
				
			||||||
 | 
					            all_not_barrier = !core_data[0].is_running.load() && core_data[0].initialized.load();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        core_data[0].enter_barrier->Set();
 | 
				
			||||||
 | 
					        if (paused_state.load()) {
 | 
				
			||||||
 | 
					            bool all_barrier = false;
 | 
				
			||||||
 | 
					            while (!all_barrier) {
 | 
				
			||||||
 | 
					                all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            core_data[0].exit_barrier->Set();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        /// Wait until all cores are paused.
 | 
				
			||||||
 | 
					        bool all_barrier = false;
 | 
				
			||||||
 | 
					        while (!all_barrier) {
 | 
				
			||||||
 | 
					            all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /// Don't release the barrier
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    paused_state = paused;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CpuManager::Pause(bool paused) {
 | 
				
			||||||
 | 
					    if (is_multicore) {
 | 
				
			||||||
 | 
					        MultiCorePause(paused);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        SingleCorePause(paused);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CpuManager::RunThread(std::size_t core) {
 | 
					void CpuManager::RunThread(std::size_t core) {
 | 
				
			||||||
    /// Initialization
 | 
					    /// Initialization
 | 
				
			||||||
    system.RegisterCoreThread(core);
 | 
					    system.RegisterCoreThread(core);
 | 
				
			||||||
    std::string name = "yuzu:CoreHostThread_" + std::to_string(core);
 | 
					    std::string name;
 | 
				
			||||||
 | 
					    if (is_multicore) {
 | 
				
			||||||
 | 
					        name = "yuzu:CoreCPUThread_" + std::to_string(core);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        name = "yuzu:CPUThread";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    MicroProfileOnThreadCreate(name.c_str());
 | 
					    MicroProfileOnThreadCreate(name.c_str());
 | 
				
			||||||
    Common::SetCurrentThreadName(name.c_str());
 | 
					    Common::SetCurrentThreadName(name.c_str());
 | 
				
			||||||
    auto& data = core_data[core];
 | 
					    auto& data = core_data[core];
 | 
				
			||||||
 | 
				
			|||||||
@ -30,6 +30,10 @@ public:
 | 
				
			|||||||
    CpuManager& operator=(const CpuManager&) = delete;
 | 
					    CpuManager& operator=(const CpuManager&) = delete;
 | 
				
			||||||
    CpuManager& operator=(CpuManager&&) = delete;
 | 
					    CpuManager& operator=(CpuManager&&) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Sets if emulation is multicore or single core, must be set before Initialize
 | 
				
			||||||
 | 
					    void SetMulticore(bool is_multicore) {
 | 
				
			||||||
 | 
					        this->is_multicore = is_multicore;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    void Initialize();
 | 
					    void Initialize();
 | 
				
			||||||
    void Shutdown();
 | 
					    void Shutdown();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -40,21 +44,34 @@ public:
 | 
				
			|||||||
    std::function<void(void*)> GetSuspendThreadStartFunc();
 | 
					    std::function<void(void*)> GetSuspendThreadStartFunc();
 | 
				
			||||||
    void* GetStartFuncParamater();
 | 
					    void* GetStartFuncParamater();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::size_t CurrentCore() const {
 | 
				
			||||||
 | 
					        return current_core;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    static void GuestThreadFunction(void* cpu_manager);
 | 
					    static void GuestThreadFunction(void* cpu_manager);
 | 
				
			||||||
    static void GuestRewindFunction(void* cpu_manager);
 | 
					    static void GuestRewindFunction(void* cpu_manager);
 | 
				
			||||||
    static void IdleThreadFunction(void* cpu_manager);
 | 
					    static void IdleThreadFunction(void* cpu_manager);
 | 
				
			||||||
    static void SuspendThreadFunction(void* cpu_manager);
 | 
					    static void SuspendThreadFunction(void* cpu_manager);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RunGuestThread();
 | 
					    void MultiCoreRunGuestThread();
 | 
				
			||||||
    void RunGuestLoop();
 | 
					    void MultiCoreRunGuestLoop();
 | 
				
			||||||
    void RunIdleThread();
 | 
					    void MultiCoreRunIdleThread();
 | 
				
			||||||
    void RunSuspendThread();
 | 
					    void MultiCoreRunSuspendThread();
 | 
				
			||||||
 | 
					    void MultiCorePause(bool paused);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void SingleCoreRunGuestThread();
 | 
				
			||||||
 | 
					    void SingleCoreRunGuestLoop();
 | 
				
			||||||
 | 
					    void SingleCoreRunIdleThread();
 | 
				
			||||||
 | 
					    void SingleCoreRunSuspendThread();
 | 
				
			||||||
 | 
					    void SingleCorePause(bool paused);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static void ThreadStart(CpuManager& cpu_manager, std::size_t core);
 | 
					    static void ThreadStart(CpuManager& cpu_manager, std::size_t core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RunThread(std::size_t core);
 | 
					    void RunThread(std::size_t core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void PreemptSingleCore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct CoreData {
 | 
					    struct CoreData {
 | 
				
			||||||
        std::shared_ptr<Common::Fiber> host_context;
 | 
					        std::shared_ptr<Common::Fiber> host_context;
 | 
				
			||||||
        std::unique_ptr<Common::Event> enter_barrier;
 | 
					        std::unique_ptr<Common::Event> enter_barrier;
 | 
				
			||||||
@ -70,6 +87,11 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{};
 | 
					    std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool is_multicore{};
 | 
				
			||||||
 | 
					    std::size_t current_core{};
 | 
				
			||||||
 | 
					    std::size_t preemption_count{};
 | 
				
			||||||
 | 
					    static constexpr std::size_t max_cycle_runs = 5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    System& system;
 | 
					    System& system;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -113,6 +113,10 @@ struct KernelCore::Impl {
 | 
				
			|||||||
    explicit Impl(Core::System& system, KernelCore& kernel)
 | 
					    explicit Impl(Core::System& system, KernelCore& kernel)
 | 
				
			||||||
        : global_scheduler{kernel}, synchronization{system}, time_manager{system}, system{system} {}
 | 
					        : global_scheduler{kernel}, synchronization{system}, time_manager{system}, system{system} {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void SetMulticore(bool is_multicore) {
 | 
				
			||||||
 | 
					        this->is_multicore = is_multicore;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void Initialize(KernelCore& kernel) {
 | 
					    void Initialize(KernelCore& kernel) {
 | 
				
			||||||
        Shutdown();
 | 
					        Shutdown();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -237,6 +241,9 @@ struct KernelCore::Impl {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void RegisterCoreThread(std::size_t core_id) {
 | 
					    void RegisterCoreThread(std::size_t core_id) {
 | 
				
			||||||
        std::unique_lock lock{register_thread_mutex};
 | 
					        std::unique_lock lock{register_thread_mutex};
 | 
				
			||||||
 | 
					        if (!is_multicore) {
 | 
				
			||||||
 | 
					            single_core_thread_id = std::this_thread::get_id();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        const std::thread::id this_id = std::this_thread::get_id();
 | 
					        const std::thread::id this_id = std::this_thread::get_id();
 | 
				
			||||||
        const auto it = host_thread_ids.find(this_id);
 | 
					        const auto it = host_thread_ids.find(this_id);
 | 
				
			||||||
        ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
 | 
					        ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
 | 
				
			||||||
@ -258,6 +265,11 @@ struct KernelCore::Impl {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    u32 GetCurrentHostThreadID() const {
 | 
					    u32 GetCurrentHostThreadID() const {
 | 
				
			||||||
        const std::thread::id this_id = std::this_thread::get_id();
 | 
					        const std::thread::id this_id = std::this_thread::get_id();
 | 
				
			||||||
 | 
					        if (!is_multicore) {
 | 
				
			||||||
 | 
					            if (single_core_thread_id == this_id) {
 | 
				
			||||||
 | 
					                return static_cast<u32>(system.GetCpuManager().CurrentCore());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        const auto it = host_thread_ids.find(this_id);
 | 
					        const auto it = host_thread_ids.find(this_id);
 | 
				
			||||||
        if (it == host_thread_ids.end()) {
 | 
					        if (it == host_thread_ids.end()) {
 | 
				
			||||||
            return Core::INVALID_HOST_THREAD_ID;
 | 
					            return Core::INVALID_HOST_THREAD_ID;
 | 
				
			||||||
@ -378,6 +390,9 @@ struct KernelCore::Impl {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
 | 
					    std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool is_multicore{};
 | 
				
			||||||
 | 
					    std::thread::id single_core_thread_id{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // System context
 | 
					    // System context
 | 
				
			||||||
    Core::System& system;
 | 
					    Core::System& system;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -387,6 +402,10 @@ KernelCore::~KernelCore() {
 | 
				
			|||||||
    Shutdown();
 | 
					    Shutdown();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void KernelCore::SetMulticore(bool is_multicore) {
 | 
				
			||||||
 | 
					    impl->SetMulticore(is_multicore);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void KernelCore::Initialize() {
 | 
					void KernelCore::Initialize() {
 | 
				
			||||||
    impl->Initialize(*this);
 | 
					    impl->Initialize(*this);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -65,6 +65,9 @@ public:
 | 
				
			|||||||
    KernelCore(KernelCore&&) = delete;
 | 
					    KernelCore(KernelCore&&) = delete;
 | 
				
			||||||
    KernelCore& operator=(KernelCore&&) = delete;
 | 
					    KernelCore& operator=(KernelCore&&) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Sets if emulation is multicore or single core, must be set before Initialize
 | 
				
			||||||
 | 
					    void SetMulticore(bool is_multicore);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Resets the kernel to a clean slate for use.
 | 
					    /// Resets the kernel to a clean slate for use.
 | 
				
			||||||
    void Initialize();
 | 
					    void Initialize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -715,8 +715,8 @@ struct Memory::Impl {
 | 
				
			|||||||
            ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
 | 
					            ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case Common::PageType::RasterizerCachedMemory: {
 | 
					        case Common::PageType::RasterizerCachedMemory: {
 | 
				
			||||||
            u8* host_ptr{GetPointerFromVMA(vaddr)};
 | 
					            u8* host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)};
 | 
				
			||||||
            system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T));
 | 
					            system.GPU().InvalidateRegion(vaddr, sizeof(T));
 | 
				
			||||||
            T volatile* pointer = reinterpret_cast<T volatile*>(&host_ptr);
 | 
					            T volatile* pointer = reinterpret_cast<T volatile*>(&host_ptr);
 | 
				
			||||||
            return Common::AtomicCompareAndSwap(pointer, data, expected);
 | 
					            return Common::AtomicCompareAndSwap(pointer, data, expected);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -745,8 +745,8 @@ struct Memory::Impl {
 | 
				
			|||||||
            ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
 | 
					            ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case Common::PageType::RasterizerCachedMemory: {
 | 
					        case Common::PageType::RasterizerCachedMemory: {
 | 
				
			||||||
            u8* host_ptr{GetPointerFromVMA(vaddr)};
 | 
					            u8* host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)};
 | 
				
			||||||
            system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(u128));
 | 
					            system.GPU().InvalidateRegion(vaddr, sizeof(u128));
 | 
				
			||||||
            u64 volatile* pointer = reinterpret_cast<u64 volatile*>(&host_ptr);
 | 
					            u64 volatile* pointer = reinterpret_cast<u64 volatile*>(&host_ptr);
 | 
				
			||||||
            return Common::AtomicCompareAndSwap(pointer, data, expected);
 | 
					            return Common::AtomicCompareAndSwap(pointer, data, expected);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,11 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
 | 
				
			|||||||
ConfigureGeneral::~ConfigureGeneral() = default;
 | 
					ConfigureGeneral::~ConfigureGeneral() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ConfigureGeneral::SetConfiguration() {
 | 
					void ConfigureGeneral::SetConfiguration() {
 | 
				
			||||||
 | 
					    const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ui->use_multi_core->setEnabled(runtime_lock);
 | 
				
			||||||
 | 
					    ui->use_multi_core->setChecked(Settings::values.use_multi_core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
 | 
					    ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
 | 
				
			||||||
    ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot);
 | 
					    ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot);
 | 
				
			||||||
    ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background);
 | 
					    ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background);
 | 
				
			||||||
@ -41,6 +46,7 @@ void ConfigureGeneral::ApplyConfiguration() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked();
 | 
					    Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked();
 | 
				
			||||||
    Settings::values.frame_limit = ui->frame_limit->value();
 | 
					    Settings::values.frame_limit = ui->frame_limit->value();
 | 
				
			||||||
 | 
					    Settings::values.use_multi_core = ui->use_multi_core->isChecked();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ConfigureGeneral::changeEvent(QEvent* event) {
 | 
					void ConfigureGeneral::changeEvent(QEvent* event) {
 | 
				
			||||||
 | 
				
			|||||||
@ -51,6 +51,13 @@
 | 
				
			|||||||
            </item>
 | 
					            </item>
 | 
				
			||||||
           </layout>
 | 
					           </layout>
 | 
				
			||||||
          </item>
 | 
					          </item>
 | 
				
			||||||
 | 
					          <item>
 | 
				
			||||||
 | 
					           <widget class="QCheckBox" name="use_multi_core">
 | 
				
			||||||
 | 
					            <property name="text">
 | 
				
			||||||
 | 
					             <string>Emulate CPU in Multiple Cores</string>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					           </widget>
 | 
				
			||||||
 | 
					          </item>
 | 
				
			||||||
          <item>
 | 
					          <item>
 | 
				
			||||||
           <widget class="QCheckBox" name="toggle_check_exit">
 | 
					           <widget class="QCheckBox" name="toggle_check_exit">
 | 
				
			||||||
            <property name="text">
 | 
					            <property name="text">
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user