cpu_core_manager.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/assert.h"
  5. #include "core/arm/exclusive_monitor.h"
  6. #include "core/core.h"
  7. #include "core/core_cpu.h"
  8. #include "core/cpu_core_manager.h"
  9. #include "core/gdbstub/gdbstub.h"
  10. #include "core/settings.h"
  11. namespace Core {
  12. namespace {
  13. void RunCpuCore(const System& system, Cpu& cpu_state) {
  14. while (system.IsPoweredOn()) {
  15. cpu_state.RunLoop(true);
  16. }
  17. }
  18. } // Anonymous namespace
  19. CpuCoreManager::CpuCoreManager(System& system) : system{system} {}
  20. CpuCoreManager::~CpuCoreManager() = default;
  21. void CpuCoreManager::Initialize() {
  22. barrier = std::make_unique<CpuBarrier>();
  23. exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
  24. for (std::size_t index = 0; index < cores.size(); ++index) {
  25. cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index);
  26. }
  27. }
  28. void CpuCoreManager::StartThreads() {
  29. // Create threads for CPU cores 1-3, and build thread_to_cpu map
  30. // CPU core 0 is run on the main thread
  31. thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
  32. if (!Settings::values.use_multi_core) {
  33. return;
  34. }
  35. for (std::size_t index = 0; index < core_threads.size(); ++index) {
  36. core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system),
  37. std::ref(*cores[index + 1]));
  38. thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get();
  39. }
  40. }
  41. void CpuCoreManager::Shutdown() {
  42. barrier->NotifyEnd();
  43. if (Settings::values.use_multi_core) {
  44. for (auto& thread : core_threads) {
  45. thread->join();
  46. thread.reset();
  47. }
  48. }
  49. thread_to_cpu.clear();
  50. for (auto& cpu_core : cores) {
  51. cpu_core.reset();
  52. }
  53. exclusive_monitor.reset();
  54. barrier.reset();
  55. }
  56. Cpu& CpuCoreManager::GetCore(std::size_t index) {
  57. return *cores.at(index);
  58. }
  59. const Cpu& CpuCoreManager::GetCore(std::size_t index) const {
  60. return *cores.at(index);
  61. }
  62. ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() {
  63. return *exclusive_monitor;
  64. }
  65. const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const {
  66. return *exclusive_monitor;
  67. }
  68. Cpu& CpuCoreManager::GetCurrentCore() {
  69. if (Settings::values.use_multi_core) {
  70. const auto& search = thread_to_cpu.find(std::this_thread::get_id());
  71. ASSERT(search != thread_to_cpu.end());
  72. ASSERT(search->second);
  73. return *search->second;
  74. }
  75. // Otherwise, use single-threaded mode active_core variable
  76. return *cores[active_core];
  77. }
  78. const Cpu& CpuCoreManager::GetCurrentCore() const {
  79. if (Settings::values.use_multi_core) {
  80. const auto& search = thread_to_cpu.find(std::this_thread::get_id());
  81. ASSERT(search != thread_to_cpu.end());
  82. ASSERT(search->second);
  83. return *search->second;
  84. }
  85. // Otherwise, use single-threaded mode active_core variable
  86. return *cores[active_core];
  87. }
  88. void CpuCoreManager::RunLoop(bool tight_loop) {
  89. // Update thread_to_cpu in case Core 0 is run from a different host thread
  90. thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
  91. if (GDBStub::IsServerEnabled()) {
  92. GDBStub::HandlePacket();
  93. // If the loop is halted and we want to step, use a tiny (1) number of instructions to
  94. // execute. Otherwise, get out of the loop function.
  95. if (GDBStub::GetCpuHaltFlag()) {
  96. if (GDBStub::GetCpuStepFlag()) {
  97. tight_loop = false;
  98. } else {
  99. return;
  100. }
  101. }
  102. }
  103. for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
  104. cores[active_core]->RunLoop(tight_loop);
  105. if (Settings::values.use_multi_core) {
  106. // Cores 1-3 are run on other threads in this mode
  107. break;
  108. }
  109. }
  110. if (GDBStub::IsServerEnabled()) {
  111. GDBStub::SetCpuStepFlag(false);
  112. }
  113. }
  114. void CpuCoreManager::InvalidateAllInstructionCaches() {
  115. for (auto& cpu : cores) {
  116. cpu->ArmInterface().ClearInstructionCache();
  117. }
  118. }
  119. } // namespace Core