summaryrefslogtreecommitdiff
path: root/src/core/core_cpu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/core_cpu.cpp')
-rw-r--r--src/core/core_cpu.cpp119
1 files changed, 119 insertions, 0 deletions
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
new file mode 100644
index 000000000..099f2bb1a
--- /dev/null
+++ b/src/core/core_cpu.cpp
@@ -0,0 +1,119 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <condition_variable>
6#include <mutex>
7
8#include "common/logging/log.h"
9#ifdef ARCHITECTURE_x86_64
10#include "core/arm/dynarmic/arm_dynarmic.h"
11#endif
12#include "core/arm/unicorn/arm_unicorn.h"
13#include "core/core_cpu.h"
14#include "core/core_timing.h"
15#include "core/hle/kernel/kernel.h"
16#include "core/hle/kernel/scheduler.h"
17#include "core/hle/kernel/thread.h"
18#include "core/settings.h"
19
20namespace Core {
21
22void CpuBarrier::NotifyEnd() {
23 std::unique_lock<std::mutex> lock(mutex);
24 end = true;
25 condition.notify_all();
26}
27
28bool CpuBarrier::Rendezvous() {
29 if (!Settings::values.use_multi_core) {
30 // Meaningless when running in single-core mode
31 return true;
32 }
33
34 if (!end) {
35 std::unique_lock<std::mutex> lock(mutex);
36
37 --cores_waiting;
38 if (!cores_waiting) {
39 cores_waiting = NUM_CPU_CORES;
40 condition.notify_all();
41 return true;
42 }
43
44 condition.wait(lock);
45 return true;
46 }
47
48 return false;
49}
50
51Cpu::Cpu(std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index)
52 : cpu_barrier{std::move(cpu_barrier)}, core_index{core_index} {
53
54 if (Settings::values.use_cpu_jit) {
55#ifdef ARCHITECTURE_x86_64
56 arm_interface = std::make_shared<ARM_Dynarmic>();
57#else
58 cpu_core = std::make_shared<ARM_Unicorn>();
59 NGLOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
60#endif
61 } else {
62 arm_interface = std::make_shared<ARM_Unicorn>();
63 }
64
65 scheduler = std::make_shared<Kernel::Scheduler>(arm_interface.get());
66}
67
68void Cpu::RunLoop(bool tight_loop) {
69 // Wait for all other CPU cores to complete the previous slice, such that they run in lock-step
70 if (!cpu_barrier->Rendezvous()) {
71 // If rendezvous failed, session has been killed
72 return;
73 }
74
75 // If we don't have a currently active thread then don't execute instructions,
76 // instead advance to the next event and try to yield to the next thread
77 if (Kernel::GetCurrentThread() == nullptr) {
78 NGLOG_TRACE(Core, "Core-{} idling", core_index);
79
80 if (IsMainCore()) {
81 CoreTiming::Idle();
82 CoreTiming::Advance();
83 }
84
85 PrepareReschedule();
86 } else {
87 if (IsMainCore()) {
88 CoreTiming::Advance();
89 }
90
91 if (tight_loop) {
92 arm_interface->Run();
93 } else {
94 arm_interface->Step();
95 }
96 }
97
98 Reschedule();
99}
100
101void Cpu::SingleStep() {
102 return RunLoop(false);
103}
104
105void Cpu::PrepareReschedule() {
106 arm_interface->PrepareReschedule();
107 reschedule_pending = true;
108}
109
110void Cpu::Reschedule() {
111 if (!reschedule_pending) {
112 return;
113 }
114
115 reschedule_pending = false;
116 scheduler->Reschedule();
117}
118
119} // namespace Core