cpu_core_manager.cpp 4.4 KB

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