cpu_core_manager.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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() = default;
  20. CpuCoreManager::~CpuCoreManager() = default;
  21. void CpuCoreManager::Initialize(System& system) {
  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. // Create threads for CPU cores 1-3, and build thread_to_cpu map
  28. // CPU core 0 is run on the main thread
  29. thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
  30. if (!Settings::values.use_multi_core) {
  31. return;
  32. }
  33. for (std::size_t index = 0; index < core_threads.size(); ++index) {
  34. core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system),
  35. std::ref(*cores[index + 1]));
  36. thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get();
  37. }
  38. }
  39. void CpuCoreManager::Shutdown() {
  40. barrier->NotifyEnd();
  41. if (Settings::values.use_multi_core) {
  42. for (auto& thread : core_threads) {
  43. thread->join();
  44. thread.reset();
  45. }
  46. }
  47. thread_to_cpu.clear();
  48. for (auto& cpu_core : cores) {
  49. cpu_core.reset();
  50. }
  51. exclusive_monitor.reset();
  52. barrier.reset();
  53. }
  54. Cpu& CpuCoreManager::GetCore(std::size_t index) {
  55. return *cores.at(index);
  56. }
  57. const Cpu& CpuCoreManager::GetCore(std::size_t index) const {
  58. return *cores.at(index);
  59. }
  60. ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() {
  61. return *exclusive_monitor;
  62. }
  63. const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const {
  64. return *exclusive_monitor;
  65. }
  66. Cpu& CpuCoreManager::GetCurrentCore() {
  67. if (Settings::values.use_multi_core) {
  68. const auto& search = thread_to_cpu.find(std::this_thread::get_id());
  69. ASSERT(search != thread_to_cpu.end());
  70. ASSERT(search->second);
  71. return *search->second;
  72. }
  73. // Otherwise, use single-threaded mode active_core variable
  74. return *cores[active_core];
  75. }
  76. const Cpu& CpuCoreManager::GetCurrentCore() const {
  77. if (Settings::values.use_multi_core) {
  78. const auto& search = thread_to_cpu.find(std::this_thread::get_id());
  79. ASSERT(search != thread_to_cpu.end());
  80. ASSERT(search->second);
  81. return *search->second;
  82. }
  83. // Otherwise, use single-threaded mode active_core variable
  84. return *cores[active_core];
  85. }
  86. void CpuCoreManager::RunLoop(bool tight_loop) {
  87. // Update thread_to_cpu in case Core 0 is run from a different host thread
  88. thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
  89. if (GDBStub::IsServerEnabled()) {
  90. GDBStub::HandlePacket();
  91. // If the loop is halted and we want to step, use a tiny (1) number of instructions to
  92. // execute. Otherwise, get out of the loop function.
  93. if (GDBStub::GetCpuHaltFlag()) {
  94. if (GDBStub::GetCpuStepFlag()) {
  95. tight_loop = false;
  96. } else {
  97. return;
  98. }
  99. }
  100. }
  101. for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
  102. cores[active_core]->RunLoop(tight_loop);
  103. if (Settings::values.use_multi_core) {
  104. // Cores 1-3 are run on other threads in this mode
  105. break;
  106. }
  107. }
  108. if (GDBStub::IsServerEnabled()) {
  109. GDBStub::SetCpuStepFlag(false);
  110. }
  111. }
  112. void CpuCoreManager::InvalidateAllInstructionCaches() {
  113. for (auto& cpu : cores) {
  114. cpu->ArmInterface().ClearInstructionCache();
  115. }
  116. }
  117. } // namespace Core