mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-12-26 20:50:05 +00:00
f2331a804a
Our initialization process is a little wonky than one would expect when it comes to code flow. We initialize the CPU last, as opposed to hardware, where the CPU obviously needs to be first, otherwise nothing else would work, and we have code that adds checks to get around this. For example, in the page table setting code, we check to see if the system is turned on before we even notify the CPU instances of a page table switch. This results in dead code (at the moment), because the only time a page table switch will occur is when the system is *not* running, preventing the emulated CPU instances from being notified of a page table switch in a convenient manner (technically the code path could be taken, but we don't emulate the process creation svc handlers yet). This moves the threads creation into its own member function of the core manager and restores a little order (and predictability) to our initialization process. Previously, in the multi-threaded cases, we'd kick off several threads before even the main kernel process was created and ready to execute (gross!). Now the initialization process is like so: Initialization: 1. Timers 2. CPU 3. Kernel 4. Filesystem stuff (kind of gross, but can be amended trivially) 5. Applet stuff (ditto in terms of being kind of gross) 6. Main process (will be moved into the loading step in a following change) 7. Telemetry (this should be initialized last in the future). 8. Services (4 and 5 should ideally be alongside this). 9. GDB (gross. Uses namespace scope state. Needs to be refactored into a class or booted altogether). 10. Renderer 11. GPU (will also have its threads created in a separate step in a following change). Which... isn't *ideal* per-se, however getting rid of the wonky intertwining of CPU state initialization out of this mix gets rid of most of the footguns when it comes to our initialization process.
63 lines
1.5 KiB
C++
63 lines
1.5 KiB
C++
// 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
|