core.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <memory>
  5. #include <utility>
  6. #include "common/logging/log.h"
  7. #ifdef ARCHITECTURE_x86_64
  8. #include "core/arm/dynarmic/arm_dynarmic.h"
  9. #endif
  10. #include "core/arm/unicorn/arm_unicorn.h"
  11. #include "core/core.h"
  12. #include "core/core_timing.h"
  13. #include "core/gdbstub/gdbstub.h"
  14. #include "core/hle/kernel/kernel.h"
  15. #include "core/hle/kernel/process.h"
  16. #include "core/hle/kernel/thread.h"
  17. #include "core/hle/service/service.h"
  18. #include "core/hw/hw.h"
  19. #include "core/loader/loader.h"
  20. #include "core/memory_setup.h"
  21. #include "core/settings.h"
  22. #include "video_core/video_core.h"
  23. namespace Core {
  24. /*static*/ System System::s_instance;
  25. System::ResultStatus System::RunLoop(int tight_loop) {
  26. status = ResultStatus::Success;
  27. if (!cpu_core) {
  28. return ResultStatus::ErrorNotInitialized;
  29. }
  30. if (GDBStub::IsServerEnabled()) {
  31. GDBStub::HandlePacket();
  32. // If the loop is halted and we want to step, use a tiny (1) number of instructions to
  33. // execute. Otherwise, get out of the loop function.
  34. if (GDBStub::GetCpuHaltFlag()) {
  35. if (GDBStub::GetCpuStepFlag()) {
  36. GDBStub::SetCpuStepFlag(false);
  37. tight_loop = 1;
  38. } else {
  39. return ResultStatus::Success;
  40. }
  41. }
  42. }
  43. // If we don't have a currently active thread then don't execute instructions,
  44. // instead advance to the next event and try to yield to the next thread
  45. if (Kernel::GetCurrentThread() == nullptr) {
  46. LOG_TRACE(Core_ARM, "Idling");
  47. CoreTiming::Idle();
  48. CoreTiming::Advance();
  49. PrepareReschedule();
  50. } else {
  51. CoreTiming::Advance();
  52. cpu_core->Run(tight_loop);
  53. }
  54. HW::Update();
  55. Reschedule();
  56. return status;
  57. }
  58. System::ResultStatus System::SingleStep() {
  59. return RunLoop(1);
  60. }
  61. System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& filepath) {
  62. app_loader = Loader::GetLoader(filepath);
  63. if (!app_loader) {
  64. LOG_CRITICAL(Core, "Failed to obtain loader for %s!", filepath.c_str());
  65. return ResultStatus::ErrorGetLoader;
  66. }
  67. std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode =
  68. app_loader->LoadKernelSystemMode();
  69. if (system_mode.second != Loader::ResultStatus::Success) {
  70. LOG_CRITICAL(Core, "Failed to determine system mode (Error %i)!",
  71. static_cast<int>(system_mode.second));
  72. switch (system_mode.second) {
  73. case Loader::ResultStatus::ErrorEncrypted:
  74. return ResultStatus::ErrorLoader_ErrorEncrypted;
  75. case Loader::ResultStatus::ErrorInvalidFormat:
  76. return ResultStatus::ErrorLoader_ErrorInvalidFormat;
  77. default:
  78. return ResultStatus::ErrorSystemMode;
  79. }
  80. }
  81. ResultStatus init_result{Init(emu_window, system_mode.first.get())};
  82. if (init_result != ResultStatus::Success) {
  83. LOG_CRITICAL(Core, "Failed to initialize system (Error %i)!", init_result);
  84. System::Shutdown();
  85. return init_result;
  86. }
  87. const Loader::ResultStatus load_result{app_loader->Load(Kernel::g_current_process)};
  88. if (Loader::ResultStatus::Success != load_result) {
  89. LOG_CRITICAL(Core, "Failed to load ROM (Error %i)!", load_result);
  90. System::Shutdown();
  91. switch (load_result) {
  92. case Loader::ResultStatus::ErrorEncrypted:
  93. return ResultStatus::ErrorLoader_ErrorEncrypted;
  94. case Loader::ResultStatus::ErrorInvalidFormat:
  95. return ResultStatus::ErrorLoader_ErrorInvalidFormat;
  96. default:
  97. return ResultStatus::ErrorLoader;
  98. }
  99. }
  100. status = ResultStatus::Success;
  101. return status;
  102. }
  103. void System::PrepareReschedule() {
  104. cpu_core->PrepareReschedule();
  105. reschedule_pending = true;
  106. }
  107. PerfStats::Results System::GetAndResetPerfStats() {
  108. return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs());
  109. }
  110. void System::Reschedule() {
  111. if (!reschedule_pending) {
  112. return;
  113. }
  114. reschedule_pending = false;
  115. Kernel::Reschedule();
  116. }
  117. System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
  118. LOG_DEBUG(HW_Memory, "initialized OK");
  119. switch (Settings::values.cpu_core) {
  120. case Settings::CpuCore::Unicorn:
  121. cpu_core = std::make_unique<ARM_Unicorn>();
  122. break;
  123. case Settings::CpuCore::Dynarmic:
  124. default:
  125. #ifdef ARCHITECTURE_x86_64
  126. cpu_core = std::make_unique<ARM_Dynarmic>();
  127. #else
  128. cpu_core = std::make_unique<ARM_Unicorn>();
  129. LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
  130. #endif
  131. break;
  132. }
  133. telemetry_session = std::make_unique<Core::TelemetrySession>();
  134. CoreTiming::Init();
  135. HW::Init();
  136. Kernel::Init(system_mode);
  137. Service::Init();
  138. GDBStub::Init();
  139. if (!VideoCore::Init(emu_window)) {
  140. return ResultStatus::ErrorVideoCore;
  141. }
  142. LOG_DEBUG(Core, "Initialized OK");
  143. // Reset counters and set time origin to current frame
  144. GetAndResetPerfStats();
  145. perf_stats.BeginSystemFrame();
  146. return ResultStatus::Success;
  147. }
  148. void System::Shutdown() {
  149. // Log last frame performance stats
  150. auto perf_results = GetAndResetPerfStats();
  151. Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_EmulationSpeed",
  152. perf_results.emulation_speed * 100.0);
  153. Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate",
  154. perf_results.game_fps);
  155. Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
  156. perf_results.frametime * 1000.0);
  157. // Shutdown emulation session
  158. GDBStub::Shutdown();
  159. VideoCore::Shutdown();
  160. Service::Shutdown();
  161. Kernel::Shutdown();
  162. HW::Shutdown();
  163. CoreTiming::Shutdown();
  164. cpu_core = nullptr;
  165. app_loader = nullptr;
  166. telemetry_session = nullptr;
  167. LOG_DEBUG(Core, "Shutdown OK");
  168. }
  169. } // namespace Core