summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/arm/arm_interface.h6
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp37
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h2
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp39
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h2
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp6
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h4
-rw-r--r--src/core/core_timing.cpp41
-rw-r--r--src/core/core_timing.h14
-rw-r--r--src/core/core_timing_util.cpp29
-rw-r--r--src/core/core_timing_util.h15
-rw-r--r--src/core/cpu_manager.cpp18
-rw-r--r--src/core/cpu_manager.h2
-rw-r--r--src/core/hle/kernel/svc.cpp5
-rw-r--r--src/core/hle/kernel/thread.cpp12
15 files changed, 152 insertions, 80 deletions
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index e5c484336..fbdce4134 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -26,8 +26,9 @@ using CPUInterrupts = std::array<CPUInterruptHandler, Core::Hardware::NUM_CPU_CO
26/// Generic ARMv8 CPU interface 26/// Generic ARMv8 CPU interface
27class ARM_Interface : NonCopyable { 27class ARM_Interface : NonCopyable {
28public: 28public:
29 explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers) 29 explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers, bool uses_wall_clock)
30 : system{system_}, interrupt_handlers{interrupt_handlers} {} 30 : system{system_}, interrupt_handlers{interrupt_handlers}, uses_wall_clock{
31 uses_wall_clock} {}
31 virtual ~ARM_Interface() = default; 32 virtual ~ARM_Interface() = default;
32 33
33 struct ThreadContext32 { 34 struct ThreadContext32 {
@@ -186,6 +187,7 @@ protected:
186 /// System context that this ARM interface is running under. 187 /// System context that this ARM interface is running under.
187 System& system; 188 System& system;
188 CPUInterrupts& interrupt_handlers; 189 CPUInterrupts& interrupt_handlers;
190 bool uses_wall_clock;
189}; 191};
190 192
191} // namespace Core 193} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 9c47c133c..c4aeedef9 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -72,23 +72,35 @@ public:
72 } 72 }
73 73
74 void AddTicks(u64 ticks) override { 74 void AddTicks(u64 ticks) override {
75 this->ticks -= ticks; 75 if (parent.uses_wall_clock) {
76 return;
77 }
78 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
79 // rough approximation of the amount of executed ticks in the system, it may be thrown off
80 // if not all cores are doing a similar amount of work. Instead of doing this, we should
81 // device a way so that timing is consistent across all cores without increasing the ticks 4
82 // times.
83 u64 amortized_ticks =
84 (ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES;
85 // Always execute at least one tick.
86 amortized_ticks = std::max<u64>(amortized_ticks, 1);
87
88 parent.system.CoreTiming().AddTicks(amortized_ticks);
89 num_interpreted_instructions = 0;
76 } 90 }
77 91
78 u64 GetTicksRemaining() override { 92 u64 GetTicksRemaining() override {
79 if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { 93 if (parent.uses_wall_clock) {
80 return std::max<s64>(ticks, 0); 94 if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) {
95 return std::max<s64>(1000U, 0);
96 }
97 return 0ULL;
81 } 98 }
82 return 0ULL; 99 return std::max(parent.system.CoreTiming().GetDowncount(), 0LL);
83 }
84
85 void ResetTicks() {
86 ticks = 1000LL;
87 } 100 }
88 101
89 ARM_Dynarmic_32& parent; 102 ARM_Dynarmic_32& parent;
90 std::size_t num_interpreted_instructions{}; 103 std::size_t num_interpreted_instructions{};
91 s64 ticks{};
92}; 104};
93 105
94std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table, 106std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table,
@@ -103,7 +115,6 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
103} 115}
104 116
105void ARM_Dynarmic_32::Run() { 117void ARM_Dynarmic_32::Run() {
106 cb->ResetTicks();
107 jit->Run(); 118 jit->Run();
108} 119}
109 120
@@ -112,8 +123,10 @@ void ARM_Dynarmic_32::Step() {
112} 123}
113 124
114ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, 125ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers,
115 ExclusiveMonitor& exclusive_monitor, std::size_t core_index) 126 bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor,
116 : ARM_Interface{system, interrupt_handlers}, cb(std::make_unique<DynarmicCallbacks32>(*this)), 127 std::size_t core_index)
128 : ARM_Interface{system, interrupt_handlers, uses_wall_clock},
129 cb(std::make_unique<DynarmicCallbacks32>(*this)),
117 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index}, 130 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index},
118 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} 131 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
119 132
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index bea4933c8..8afd15c8b 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -29,7 +29,7 @@ class System;
29 29
30class ARM_Dynarmic_32 final : public ARM_Interface { 30class ARM_Dynarmic_32 final : public ARM_Interface {
31public: 31public:
32 ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, 32 ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
33 ExclusiveMonitor& exclusive_monitor, std::size_t core_index); 33 ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
34 ~ARM_Dynarmic_32() override; 34 ~ARM_Dynarmic_32() override;
35 35
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 03b3313cf..a518733b6 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -124,29 +124,41 @@ public:
124 } 124 }
125 125
126 void AddTicks(u64 ticks) override { 126 void AddTicks(u64 ticks) override {
127 this->ticks -= ticks; 127 if (parent.uses_wall_clock) {
128 return;
129 }
130 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
131 // rough approximation of the amount of executed ticks in the system, it may be thrown off
132 // if not all cores are doing a similar amount of work. Instead of doing this, we should
133 // device a way so that timing is consistent across all cores without increasing the ticks 4
134 // times.
135 u64 amortized_ticks =
136 (ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES;
137 // Always execute at least one tick.
138 amortized_ticks = std::max<u64>(amortized_ticks, 1);
139
140 parent.system.CoreTiming().AddTicks(amortized_ticks);
141 num_interpreted_instructions = 0;
128 } 142 }
129 143
130 u64 GetTicksRemaining() override { 144 u64 GetTicksRemaining() override {
131 if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { 145 if (parent.uses_wall_clock) {
132 return std::max<s64>(ticks, 0); 146 if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) {
147 return std::max<s64>(1000U, 0);
148 }
149 return 0ULL;
133 } 150 }
134 return 0ULL; 151 return std::max(parent.system.CoreTiming().GetDowncount(), 0LL);
135 } 152 }
136 153
137 u64 GetCNTPCT() override { 154 u64 GetCNTPCT() override {
138 return parent.system.CoreTiming().GetClockTicks(); 155 return parent.system.CoreTiming().GetClockTicks();
139 } 156 }
140 157
141 void ResetTicks() {
142 ticks = 1000LL;
143 }
144
145 ARM_Dynarmic_64& parent; 158 ARM_Dynarmic_64& parent;
146 std::size_t num_interpreted_instructions = 0; 159 std::size_t num_interpreted_instructions = 0;
147 u64 tpidrro_el0 = 0; 160 u64 tpidrro_el0 = 0;
148 u64 tpidr_el0 = 0; 161 u64 tpidr_el0 = 0;
149 s64 ticks{};
150}; 162};
151 163
152std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table, 164std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table,
@@ -185,13 +197,12 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
185 } 197 }
186 198
187 // CNTPCT uses wall clock. 199 // CNTPCT uses wall clock.
188 config.wall_clock_cntpct = true; 200 config.wall_clock_cntpct = uses_wall_clock;
189 201
190 return std::make_shared<Dynarmic::A64::Jit>(config); 202 return std::make_shared<Dynarmic::A64::Jit>(config);
191} 203}
192 204
193void ARM_Dynarmic_64::Run() { 205void ARM_Dynarmic_64::Run() {
194 cb->ResetTicks();
195 jit->Run(); 206 jit->Run();
196} 207}
197 208
@@ -200,9 +211,11 @@ void ARM_Dynarmic_64::Step() {
200} 211}
201 212
202ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, 213ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers,
203 ExclusiveMonitor& exclusive_monitor, std::size_t core_index) 214 bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor,
204 : ARM_Interface{system, interrupt_handler}, 215 std::size_t core_index)
216 : ARM_Interface{system, interrupt_handler, uses_wall_clock},
205 cb(std::make_unique<DynarmicCallbacks64>(*this)), inner_unicorn{system, interrupt_handler, 217 cb(std::make_unique<DynarmicCallbacks64>(*this)), inner_unicorn{system, interrupt_handler,
218 uses_wall_clock,
206 ARM_Unicorn::Arch::AArch64, 219 ARM_Unicorn::Arch::AArch64,
207 core_index}, 220 core_index},
208 core_index{core_index}, exclusive_monitor{ 221 core_index{core_index}, exclusive_monitor{
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index c26b47249..31ec16521 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -28,7 +28,7 @@ class System;
28 28
29class ARM_Dynarmic_64 final : public ARM_Interface { 29class ARM_Dynarmic_64 final : public ARM_Interface {
30public: 30public:
31 ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, 31 ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
32 ExclusiveMonitor& exclusive_monitor, std::size_t core_index); 32 ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
33 ~ARM_Dynarmic_64() override; 33 ~ARM_Dynarmic_64() override;
34 34
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index 099229c8d..1cb71942b 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -63,9 +63,9 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si
63 return false; 63 return false;
64} 64}
65 65
66ARM_Unicorn::ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, Arch architecture, 66ARM_Unicorn::ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler,
67 std::size_t core_index) 67 bool uses_wall_clock, Arch architecture, std::size_t core_index)
68 : ARM_Interface{system, interrupt_handler}, core_index{core_index} { 68 : ARM_Interface{system, interrupt_handler, uses_wall_clock}, core_index{core_index} {
69 const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64; 69 const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64;
70 CHECKED(uc_open(arch, UC_MODE_ARM, &uc)); 70 CHECKED(uc_open(arch, UC_MODE_ARM, &uc));
71 71
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
index f09b24a85..a01751e65 100644
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ b/src/core/arm/unicorn/arm_unicorn.h
@@ -20,8 +20,8 @@ public:
20 AArch64, // 64-bit ARM 20 AArch64, // 64-bit ARM
21 }; 21 };
22 22
23 explicit ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, Arch architecture, 23 explicit ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler,
24 std::size_t core_index); 24 bool uses_wall_clock, Arch architecture, std::size_t core_index);
25 ~ARM_Unicorn() override; 25 ~ARM_Unicorn() override;
26 26
27 void SetPC(u64 pc) override; 27 void SetPC(u64 pc) override;
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 189d4aa34..12e9e60a4 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -14,6 +14,8 @@
14 14
15namespace Core::Timing { 15namespace Core::Timing {
16 16
17constexpr u64 MAX_SLICE_LENGTH = 4000;
18
17std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) { 19std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
18 return std::make_shared<EventType>(std::move(callback), std::move(name)); 20 return std::make_shared<EventType>(std::move(callback), std::move(name));
19} 21}
@@ -53,6 +55,7 @@ void CoreTiming::ThreadEntry(CoreTiming& instance) {
53void CoreTiming::Initialize(std::function<void(void)>&& on_thread_init_) { 55void CoreTiming::Initialize(std::function<void(void)>&& on_thread_init_) {
54 on_thread_init = std::move(on_thread_init_); 56 on_thread_init = std::move(on_thread_init_);
55 event_fifo_id = 0; 57 event_fifo_id = 0;
58 ticks = 0;
56 const auto empty_timed_callback = [](u64, s64) {}; 59 const auto empty_timed_callback = [](u64, s64) {};
57 ev_lost = CreateEvent("_lost_event", empty_timed_callback); 60 ev_lost = CreateEvent("_lost_event", empty_timed_callback);
58 if (is_multicore) { 61 if (is_multicore) {
@@ -126,20 +129,36 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u
126 basic_lock.unlock(); 129 basic_lock.unlock();
127} 130}
128 131
129void CoreTiming::AddTicks(std::size_t core_index, u64 ticks) { 132void CoreTiming::AddTicks(u64 ticks) {
130 ticks_count[core_index] += ticks; 133 this->ticks += ticks;
134 downcount -= ticks;
131} 135}
132 136
133void CoreTiming::ResetTicks(std::size_t core_index) { 137void CoreTiming::Idle() {
134 ticks_count[core_index] = 0; 138 if (!event_queue.empty()) {
139 u64 next_event_time = event_queue.front().time;
140 ticks = nsToCycles(std::chrono::nanoseconds(next_event_time)) + 10U;
141 return;
142 }
143 ticks += 1000U;
144}
145
146void CoreTiming::ResetTicks() {
147 downcount = MAX_SLICE_LENGTH;
135} 148}
136 149
137u64 CoreTiming::GetCPUTicks() const { 150u64 CoreTiming::GetCPUTicks() const {
138 return clock->GetCPUCycles(); 151 if (is_multicore) {
152 return clock->GetCPUCycles();
153 }
154 return ticks;
139} 155}
140 156
141u64 CoreTiming::GetClockTicks() const { 157u64 CoreTiming::GetClockTicks() const {
142 return clock->GetClockCycles(); 158 if (is_multicore) {
159 return clock->GetClockCycles();
160 }
161 return CpuCyclesToClockCycles(ticks);
143} 162}
144 163
145void CoreTiming::ClearPendingEvents() { 164void CoreTiming::ClearPendingEvents() {
@@ -217,11 +236,17 @@ void CoreTiming::ThreadLoop() {
217} 236}
218 237
219std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { 238std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const {
220 return clock->GetTimeNS(); 239 if (is_multicore) {
240 return clock->GetTimeNS();
241 }
242 return CyclesToNs(ticks);
221} 243}
222 244
223std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { 245std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
224 return clock->GetTimeUS(); 246 if (is_multicore) {
247 return clock->GetTimeUS();
248 }
249 return CyclesToUs(ticks);
225} 250}
226 251
227} // namespace Core::Timing 252} // namespace Core::Timing
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 03f9a5c76..ed5de9b97 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -98,9 +98,15 @@ public:
98 /// We only permit one event of each type in the queue at a time. 98 /// We only permit one event of each type in the queue at a time.
99 void RemoveEvent(const std::shared_ptr<EventType>& event_type); 99 void RemoveEvent(const std::shared_ptr<EventType>& event_type);
100 100
101 void AddTicks(std::size_t core_index, u64 ticks); 101 void AddTicks(u64 ticks);
102 102
103 void ResetTicks(std::size_t core_index); 103 void ResetTicks();
104
105 void Idle();
106
107 s64 GetDowncount() const {
108 return downcount;
109 }
104 110
105 /// Returns current time in emulated CPU cycles 111 /// Returns current time in emulated CPU cycles
106 u64 GetCPUTicks() const; 112 u64 GetCPUTicks() const;
@@ -154,7 +160,9 @@ private:
154 160
155 bool is_multicore{}; 161 bool is_multicore{};
156 162
157 std::array<std::atomic<u64>, Core::Hardware::NUM_CPU_CORES> ticks_count{}; 163 /// Cycle timing
164 u64 ticks{};
165 s64 downcount{};
158}; 166};
159 167
160/// Creates a core timing event with the given name and callback. 168/// Creates a core timing event with the given name and callback.
diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp
index be34b26fe..aefc63663 100644
--- a/src/core/core_timing_util.cpp
+++ b/src/core/core_timing_util.cpp
@@ -38,15 +38,8 @@ s64 usToCycles(std::chrono::microseconds us) {
38} 38}
39 39
40s64 nsToCycles(std::chrono::nanoseconds ns) { 40s64 nsToCycles(std::chrono::nanoseconds ns) {
41 if (static_cast<u64>(ns.count() / 1000000000) > MAX_VALUE_TO_MULTIPLY) { 41 const u128 temporal = Common::Multiply64Into128(ns.count(), Hardware::BASE_CLOCK_RATE);
42 LOG_ERROR(Core_Timing, "Integer overflow, use max value"); 42 return Common::Divide128On32(temporal, static_cast<u32>(1000000000)).first;
43 return std::numeric_limits<s64>::max();
44 }
45 if (static_cast<u64>(ns.count()) > MAX_VALUE_TO_MULTIPLY) {
46 LOG_DEBUG(Core_Timing, "Time very big, do rounding");
47 return Hardware::BASE_CLOCK_RATE * (ns.count() / 1000000000);
48 }
49 return (Hardware::BASE_CLOCK_RATE * ns.count()) / 1000000000;
50} 43}
51 44
52u64 msToClockCycles(std::chrono::milliseconds ns) { 45u64 msToClockCycles(std::chrono::milliseconds ns) {
@@ -69,4 +62,22 @@ u64 CpuCyclesToClockCycles(u64 ticks) {
69 return Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first; 62 return Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first;
70} 63}
71 64
65std::chrono::milliseconds CyclesToMs(s64 cycles) {
66 const u128 temporal = Common::Multiply64Into128(cycles, 1000);
67 u64 ms = Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first;
68 return std::chrono::milliseconds(ms);
69}
70
71std::chrono::nanoseconds CyclesToNs(s64 cycles) {
72 const u128 temporal = Common::Multiply64Into128(cycles, 1000000000);
73 u64 ns = Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first;
74 return std::chrono::nanoseconds(ns);
75}
76
77std::chrono::microseconds CyclesToUs(s64 cycles) {
78 const u128 temporal = Common::Multiply64Into128(cycles, 1000000);
79 u64 us = Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first;
80 return std::chrono::microseconds(us);
81}
82
72} // namespace Core::Timing 83} // namespace Core::Timing
diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h
index b3c58447d..2ed979e14 100644
--- a/src/core/core_timing_util.h
+++ b/src/core/core_timing_util.h
@@ -16,18 +16,9 @@ s64 nsToCycles(std::chrono::nanoseconds ns);
16u64 msToClockCycles(std::chrono::milliseconds ns); 16u64 msToClockCycles(std::chrono::milliseconds ns);
17u64 usToClockCycles(std::chrono::microseconds ns); 17u64 usToClockCycles(std::chrono::microseconds ns);
18u64 nsToClockCycles(std::chrono::nanoseconds ns); 18u64 nsToClockCycles(std::chrono::nanoseconds ns);
19 19std::chrono::milliseconds CyclesToMs(s64 cycles);
20inline std::chrono::milliseconds CyclesToMs(s64 cycles) { 20std::chrono::nanoseconds CyclesToNs(s64 cycles);
21 return std::chrono::milliseconds(cycles * 1000 / Hardware::BASE_CLOCK_RATE); 21std::chrono::microseconds CyclesToUs(s64 cycles);
22}
23
24inline std::chrono::nanoseconds CyclesToNs(s64 cycles) {
25 return std::chrono::nanoseconds(cycles * 1000000000 / Hardware::BASE_CLOCK_RATE);
26}
27
28inline std::chrono::microseconds CyclesToUs(s64 cycles) {
29 return std::chrono::microseconds(cycles * 1000000 / Hardware::BASE_CLOCK_RATE);
30}
31 22
32u64 CpuCyclesToClockCycles(u64 ticks); 23u64 CpuCyclesToClockCycles(u64 ticks);
33 24
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 2e9dc9dc3..604405060 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -232,13 +232,10 @@ void CpuManager::SingleCoreRunGuestLoop() {
232 auto* physical_core = &kernel.CurrentPhysicalCore(); 232 auto* physical_core = &kernel.CurrentPhysicalCore();
233 auto& arm_interface = thread->ArmInterface(); 233 auto& arm_interface = thread->ArmInterface();
234 system.EnterDynarmicProfile(); 234 system.EnterDynarmicProfile();
235 while (!physical_core->IsInterrupted()) { 235 if (!physical_core->IsInterrupted()) {
236 system.CoreTiming().ResetTicks();
236 arm_interface.Run(); 237 arm_interface.Run();
237 physical_core = &kernel.CurrentPhysicalCore(); 238 physical_core = &kernel.CurrentPhysicalCore();
238 preemption_count++;
239 if (preemption_count % max_cycle_runs == 0) {
240 break;
241 }
242 } 239 }
243 system.ExitDynarmicProfile(); 240 system.ExitDynarmicProfile();
244 thread->SetPhantomMode(true); 241 thread->SetPhantomMode(true);
@@ -255,7 +252,7 @@ void CpuManager::SingleCoreRunIdleThread() {
255 auto& kernel = system.Kernel(); 252 auto& kernel = system.Kernel();
256 while (true) { 253 while (true) {
257 auto& physical_core = kernel.CurrentPhysicalCore(); 254 auto& physical_core = kernel.CurrentPhysicalCore();
258 PreemptSingleCore(); 255 PreemptSingleCore(false);
259 idle_count++; 256 idle_count++;
260 auto& scheduler = physical_core.Scheduler(); 257 auto& scheduler = physical_core.Scheduler();
261 scheduler.TryDoContextSwitch(); 258 scheduler.TryDoContextSwitch();
@@ -279,12 +276,15 @@ void CpuManager::SingleCoreRunSuspendThread() {
279 } 276 }
280} 277}
281 278
282void CpuManager::PreemptSingleCore() { 279void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
283 preemption_count = 0;
284 std::size_t old_core = current_core; 280 std::size_t old_core = current_core;
285 auto& scheduler = system.Kernel().Scheduler(old_core); 281 auto& scheduler = system.Kernel().Scheduler(old_core);
286 Kernel::Thread* current_thread = scheduler.GetCurrentThread(); 282 Kernel::Thread* current_thread = scheduler.GetCurrentThread();
287 if (idle_count >= 4) { 283 if (idle_count >= 4 || from_running_enviroment) {
284 if (!from_running_enviroment) {
285 system.CoreTiming().Idle();
286 idle_count = 0;
287 }
288 current_thread->SetPhantomMode(true); 288 current_thread->SetPhantomMode(true);
289 system.CoreTiming().Advance(); 289 system.CoreTiming().Advance();
290 current_thread->SetPhantomMode(false); 290 current_thread->SetPhantomMode(false);
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h
index e6b8612f0..ae55d6427 100644
--- a/src/core/cpu_manager.h
+++ b/src/core/cpu_manager.h
@@ -55,7 +55,7 @@ public:
55 std::function<void(void*)> GetSuspendThreadStartFunc(); 55 std::function<void(void*)> GetSuspendThreadStartFunc();
56 void* GetStartFuncParamater(); 56 void* GetStartFuncParamater();
57 57
58 void PreemptSingleCore(); 58 void PreemptSingleCore(bool from_running_enviroment = true);
59 59
60 std::size_t CurrentCore() const { 60 std::size_t CurrentCore() const {
61 return current_core.load(); 61 return current_core.load();
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 599972211..c47fa9167 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1534,6 +1534,7 @@ static void SleepThread(Core::System& system, s64 nanoseconds) {
1534 1534
1535 if (is_redundant && !system.Kernel().IsMulticore()) { 1535 if (is_redundant && !system.Kernel().IsMulticore()) {
1536 system.Kernel().ExitSVCProfile(); 1536 system.Kernel().ExitSVCProfile();
1537 system.CoreTiming().AddTicks(1000U);
1537 system.GetCpuManager().PreemptSingleCore(); 1538 system.GetCpuManager().PreemptSingleCore();
1538 system.Kernel().EnterSVCProfile(); 1539 system.Kernel().EnterSVCProfile();
1539 } 1540 }
@@ -1762,6 +1763,10 @@ static u64 GetSystemTick(Core::System& system) {
1762 // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) 1763 // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick)
1763 const u64 result{system.CoreTiming().GetClockTicks()}; 1764 const u64 result{system.CoreTiming().GetClockTicks()};
1764 1765
1766 if (!system.Kernel().IsMulticore()) {
1767 core_timing.AddTicks(400U);
1768 }
1769
1765 return result; 1770 return result;
1766} 1771}
1767 1772
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 65fedfc9b..d88039a16 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -246,19 +246,23 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
246#ifdef ARCHITECTURE_x86_64 246#ifdef ARCHITECTURE_x86_64
247 if (owner_process && !owner_process->Is64BitProcess()) { 247 if (owner_process && !owner_process->Is64BitProcess()) {
248 thread->arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( 248 thread->arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
249 system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); 249 system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(),
250 processor_id);
250 } else { 251 } else {
251 thread->arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( 252 thread->arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
252 system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); 253 system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(),
254 processor_id);
253 } 255 }
254 256
255#else 257#else
256 if (owner_process && !owner_process->Is64BitProcess()) { 258 if (owner_process && !owner_process->Is64BitProcess()) {
257 thread->arm_interface = std::make_shared<Core::ARM_Unicorn>( 259 thread->arm_interface = std::make_shared<Core::ARM_Unicorn>(
258 system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch32, processor_id); 260 system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch32,
261 processor_id);
259 } else { 262 } else {
260 thread->arm_interface = std::make_shared<Core::ARM_Unicorn>( 263 thread->arm_interface = std::make_shared<Core::ARM_Unicorn>(
261 system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch64, processor_id); 264 system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch64,
265 processor_id);
262 } 266 }
263 LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); 267 LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
264#endif 268#endif