summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp12
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h8
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp6
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h8
-rw-r--r--src/core/core.cpp19
-rw-r--r--src/core/core.h10
-rw-r--r--src/core/core_cpu.cpp15
-rw-r--r--src/core/core_cpu.h8
-rw-r--r--src/core/core_timing.cpp189
-rw-r--r--src/core/core_timing.h211
-rw-r--r--src/core/cpu_core_manager.cpp3
-rw-r--r--src/core/hle/kernel/kernel.cpp12
-rw-r--r--src/core/hle/kernel/kernel.h9
-rw-r--r--src/core/hle/kernel/scheduler.cpp2
-rw-r--r--src/core/hle/kernel/svc.cpp10
-rw-r--r--src/core/hle/kernel/thread.cpp19
-rw-r--r--src/core/hle/service/audio/audout_u.cpp10
-rw-r--r--src/core/hle/service/audio/audren_u.cpp9
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h7
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h2
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h2
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h2
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h2
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/npad.h2
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.h2
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp7
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h2
-rw-r--r--src/core/hle/service/hid/controllers/xpad.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/xpad.h2
-rw-r--r--src/core/hle/service/hid/hid.cpp18
-rw-r--r--src/core/hle/service/hid/irs.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp3
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp10
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h8
-rw-r--r--src/core/hle/service/service.cpp5
-rw-r--r--src/core/hle/service/service.h15
-rw-r--r--src/core/hle/service/time/time.cpp7
43 files changed, 404 insertions, 289 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index f28951f8a..9b7ca4030 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -112,14 +112,14 @@ public:
112 // Always execute at least one tick. 112 // Always execute at least one tick.
113 amortized_ticks = std::max<u64>(amortized_ticks, 1); 113 amortized_ticks = std::max<u64>(amortized_ticks, 1);
114 114
115 Timing::AddTicks(amortized_ticks); 115 parent.core_timing.AddTicks(amortized_ticks);
116 num_interpreted_instructions = 0; 116 num_interpreted_instructions = 0;
117 } 117 }
118 u64 GetTicksRemaining() override { 118 u64 GetTicksRemaining() override {
119 return std::max(Timing::GetDowncount(), 0); 119 return std::max(parent.core_timing.GetDowncount(), 0);
120 } 120 }
121 u64 GetCNTPCT() override { 121 u64 GetCNTPCT() override {
122 return Timing::GetTicks(); 122 return parent.core_timing.GetTicks();
123 } 123 }
124 124
125 ARM_Dynarmic& parent; 125 ARM_Dynarmic& parent;
@@ -172,8 +172,10 @@ void ARM_Dynarmic::Step() {
172 cb->InterpreterFallback(jit->GetPC(), 1); 172 cb->InterpreterFallback(jit->GetPC(), 1);
173} 173}
174 174
175ARM_Dynarmic::ARM_Dynarmic(ExclusiveMonitor& exclusive_monitor, std::size_t core_index) 175ARM_Dynarmic::ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
176 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index}, 176 std::size_t core_index)
177 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{core_timing},
178 core_index{core_index}, core_timing{core_timing},
177 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} { 179 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {
178 ThreadContext ctx{}; 180 ThreadContext ctx{};
179 inner_unicorn.SaveContext(ctx); 181 inner_unicorn.SaveContext(ctx);
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index 512bf8ce9..6cc458296 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -16,6 +16,10 @@ namespace Memory {
16struct PageTable; 16struct PageTable;
17} 17}
18 18
19namespace Core::Timing {
20class CoreTiming;
21}
22
19namespace Core { 23namespace Core {
20 24
21class ARM_Dynarmic_Callbacks; 25class ARM_Dynarmic_Callbacks;
@@ -23,7 +27,8 @@ class DynarmicExclusiveMonitor;
23 27
24class ARM_Dynarmic final : public ARM_Interface { 28class ARM_Dynarmic final : public ARM_Interface {
25public: 29public:
26 ARM_Dynarmic(ExclusiveMonitor& exclusive_monitor, std::size_t core_index); 30 ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
31 std::size_t core_index);
27 ~ARM_Dynarmic(); 32 ~ARM_Dynarmic();
28 33
29 void MapBackingMemory(VAddr address, std::size_t size, u8* memory, 34 void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
@@ -62,6 +67,7 @@ private:
62 ARM_Unicorn inner_unicorn; 67 ARM_Unicorn inner_unicorn;
63 68
64 std::size_t core_index; 69 std::size_t core_index;
70 Timing::CoreTiming& core_timing;
65 DynarmicExclusiveMonitor& exclusive_monitor; 71 DynarmicExclusiveMonitor& exclusive_monitor;
66 72
67 Memory::PageTable* current_page_table = nullptr; 73 Memory::PageTable* current_page_table = nullptr;
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index c36c15c02..a542a098b 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -72,7 +72,7 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si
72 return {}; 72 return {};
73} 73}
74 74
75ARM_Unicorn::ARM_Unicorn() { 75ARM_Unicorn::ARM_Unicorn(Timing::CoreTiming& core_timing) : core_timing{core_timing} {
76 CHECKED(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc)); 76 CHECKED(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc));
77 77
78 auto fpv = 3 << 20; 78 auto fpv = 3 << 20;
@@ -177,7 +177,7 @@ void ARM_Unicorn::Run() {
177 if (GDBStub::IsServerEnabled()) { 177 if (GDBStub::IsServerEnabled()) {
178 ExecuteInstructions(std::max(4000000, 0)); 178 ExecuteInstructions(std::max(4000000, 0));
179 } else { 179 } else {
180 ExecuteInstructions(std::max(Timing::GetDowncount(), 0)); 180 ExecuteInstructions(std::max(core_timing.GetDowncount(), 0));
181 } 181 }
182} 182}
183 183
@@ -190,7 +190,7 @@ MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64));
190void ARM_Unicorn::ExecuteInstructions(int num_instructions) { 190void ARM_Unicorn::ExecuteInstructions(int num_instructions) {
191 MICROPROFILE_SCOPE(ARM_Jit_Unicorn); 191 MICROPROFILE_SCOPE(ARM_Jit_Unicorn);
192 CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); 192 CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
193 Timing::AddTicks(num_instructions); 193 core_timing.AddTicks(num_instructions);
194 if (GDBStub::IsServerEnabled()) { 194 if (GDBStub::IsServerEnabled()) {
195 if (last_bkpt_hit) { 195 if (last_bkpt_hit) {
196 uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); 196 uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
index 75761950b..dbd6955ea 100644
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ b/src/core/arm/unicorn/arm_unicorn.h
@@ -9,12 +9,17 @@
9#include "core/arm/arm_interface.h" 9#include "core/arm/arm_interface.h"
10#include "core/gdbstub/gdbstub.h" 10#include "core/gdbstub/gdbstub.h"
11 11
12namespace Core::Timing {
13class CoreTiming;
14}
15
12namespace Core { 16namespace Core {
13 17
14class ARM_Unicorn final : public ARM_Interface { 18class ARM_Unicorn final : public ARM_Interface {
15public: 19public:
16 ARM_Unicorn(); 20 explicit ARM_Unicorn(Timing::CoreTiming& core_timing);
17 ~ARM_Unicorn(); 21 ~ARM_Unicorn();
22
18 void MapBackingMemory(VAddr address, std::size_t size, u8* memory, 23 void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
19 Kernel::VMAPermission perms) override; 24 Kernel::VMAPermission perms) override;
20 void UnmapMemory(VAddr address, std::size_t size) override; 25 void UnmapMemory(VAddr address, std::size_t size) override;
@@ -43,6 +48,7 @@ public:
43 48
44private: 49private:
45 uc_engine* uc{}; 50 uc_engine* uc{};
51 Timing::CoreTiming& core_timing;
46 GDBStub::BreakpointAddress last_bkpt{}; 52 GDBStub::BreakpointAddress last_bkpt{};
47 bool last_bkpt_hit; 53 bool last_bkpt_hit;
48}; 54};
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 4d9d21ee4..8aa0932c5 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -94,8 +94,8 @@ struct System::Impl {
94 ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { 94 ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
95 LOG_DEBUG(HW_Memory, "initialized OK"); 95 LOG_DEBUG(HW_Memory, "initialized OK");
96 96
97 Timing::Init(); 97 core_timing.Initialize();
98 kernel.Initialize(); 98 kernel.Initialize(core_timing);
99 99
100 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( 100 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
101 std::chrono::system_clock::now().time_since_epoch()); 101 std::chrono::system_clock::now().time_since_epoch());
@@ -120,7 +120,7 @@ struct System::Impl {
120 telemetry_session = std::make_unique<Core::TelemetrySession>(); 120 telemetry_session = std::make_unique<Core::TelemetrySession>();
121 service_manager = std::make_shared<Service::SM::ServiceManager>(); 121 service_manager = std::make_shared<Service::SM::ServiceManager>();
122 122
123 Service::Init(service_manager, *virtual_filesystem); 123 Service::Init(service_manager, system, *virtual_filesystem);
124 GDBStub::Init(); 124 GDBStub::Init();
125 125
126 renderer = VideoCore::CreateRenderer(emu_window, system); 126 renderer = VideoCore::CreateRenderer(emu_window, system);
@@ -205,7 +205,7 @@ struct System::Impl {
205 205
206 // Shutdown kernel and core timing 206 // Shutdown kernel and core timing
207 kernel.Shutdown(); 207 kernel.Shutdown();
208 Timing::Shutdown(); 208 core_timing.Shutdown();
209 209
210 // Close app loader 210 // Close app loader
211 app_loader.reset(); 211 app_loader.reset();
@@ -232,9 +232,10 @@ struct System::Impl {
232 } 232 }
233 233
234 PerfStatsResults GetAndResetPerfStats() { 234 PerfStatsResults GetAndResetPerfStats() {
235 return perf_stats.GetAndResetStats(Timing::GetGlobalTimeUs()); 235 return perf_stats.GetAndResetStats(core_timing.GetGlobalTimeUs());
236 } 236 }
237 237
238 Timing::CoreTiming core_timing;
238 Kernel::KernelCore kernel; 239 Kernel::KernelCore kernel;
239 /// RealVfsFilesystem instance 240 /// RealVfsFilesystem instance
240 FileSys::VirtualFilesystem virtual_filesystem; 241 FileSys::VirtualFilesystem virtual_filesystem;
@@ -396,6 +397,14 @@ const Kernel::KernelCore& System::Kernel() const {
396 return impl->kernel; 397 return impl->kernel;
397} 398}
398 399
400Timing::CoreTiming& System::CoreTiming() {
401 return impl->core_timing;
402}
403
404const Timing::CoreTiming& System::CoreTiming() const {
405 return impl->core_timing;
406}
407
399Core::PerfStats& System::GetPerfStats() { 408Core::PerfStats& System::GetPerfStats() {
400 return impl->perf_stats; 409 return impl->perf_stats;
401} 410}
diff --git a/src/core/core.h b/src/core/core.h
index 511a5ad3a..d720013f7 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -47,6 +47,10 @@ namespace VideoCore {
47class RendererBase; 47class RendererBase;
48} // namespace VideoCore 48} // namespace VideoCore
49 49
50namespace Core::Timing {
51class CoreTiming;
52}
53
50namespace Core { 54namespace Core {
51 55
52class ARM_Interface; 56class ARM_Interface;
@@ -205,6 +209,12 @@ public:
205 /// Provides a constant pointer to the current process. 209 /// Provides a constant pointer to the current process.
206 const Kernel::Process* CurrentProcess() const; 210 const Kernel::Process* CurrentProcess() const;
207 211
212 /// Provides a reference to the core timing instance.
213 Timing::CoreTiming& CoreTiming();
214
215 /// Provides a constant reference to the core timing instance.
216 const Timing::CoreTiming& CoreTiming() const;
217
208 /// Provides a reference to the kernel instance. 218 /// Provides a reference to the kernel instance.
209 Kernel::KernelCore& Kernel(); 219 Kernel::KernelCore& Kernel();
210 220
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index 452366250..54aa21a3a 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -49,17 +49,18 @@ bool CpuBarrier::Rendezvous() {
49 return false; 49 return false;
50} 50}
51 51
52Cpu::Cpu(ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, std::size_t core_index) 52Cpu::Cpu(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
53 : cpu_barrier{cpu_barrier}, core_index{core_index} { 53 CpuBarrier& cpu_barrier, std::size_t core_index)
54 : cpu_barrier{cpu_barrier}, core_timing{core_timing}, core_index{core_index} {
54 if (Settings::values.use_cpu_jit) { 55 if (Settings::values.use_cpu_jit) {
55#ifdef ARCHITECTURE_x86_64 56#ifdef ARCHITECTURE_x86_64
56 arm_interface = std::make_unique<ARM_Dynarmic>(exclusive_monitor, core_index); 57 arm_interface = std::make_unique<ARM_Dynarmic>(core_timing, exclusive_monitor, core_index);
57#else 58#else
58 arm_interface = std::make_unique<ARM_Unicorn>(); 59 arm_interface = std::make_unique<ARM_Unicorn>();
59 LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); 60 LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
60#endif 61#endif
61 } else { 62 } else {
62 arm_interface = std::make_unique<ARM_Unicorn>(); 63 arm_interface = std::make_unique<ARM_Unicorn>(core_timing);
63 } 64 }
64 65
65 scheduler = std::make_unique<Kernel::Scheduler>(*arm_interface); 66 scheduler = std::make_unique<Kernel::Scheduler>(*arm_interface);
@@ -93,14 +94,14 @@ void Cpu::RunLoop(bool tight_loop) {
93 94
94 if (IsMainCore()) { 95 if (IsMainCore()) {
95 // TODO(Subv): Only let CoreTiming idle if all 4 cores are idling. 96 // TODO(Subv): Only let CoreTiming idle if all 4 cores are idling.
96 Timing::Idle(); 97 core_timing.Idle();
97 Timing::Advance(); 98 core_timing.Advance();
98 } 99 }
99 100
100 PrepareReschedule(); 101 PrepareReschedule();
101 } else { 102 } else {
102 if (IsMainCore()) { 103 if (IsMainCore()) {
103 Timing::Advance(); 104 core_timing.Advance();
104 } 105 }
105 106
106 if (tight_loop) { 107 if (tight_loop) {
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h
index 1d2bdc6cd..e2204c6b0 100644
--- a/src/core/core_cpu.h
+++ b/src/core/core_cpu.h
@@ -15,6 +15,10 @@ namespace Kernel {
15class Scheduler; 15class Scheduler;
16} 16}
17 17
18namespace Core::Timing {
19class CoreTiming;
20}
21
18namespace Core { 22namespace Core {
19 23
20class ARM_Interface; 24class ARM_Interface;
@@ -41,7 +45,8 @@ private:
41 45
42class Cpu { 46class Cpu {
43public: 47public:
44 Cpu(ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, std::size_t core_index); 48 Cpu(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
49 CpuBarrier& cpu_barrier, std::size_t core_index);
45 ~Cpu(); 50 ~Cpu();
46 51
47 void RunLoop(bool tight_loop = true); 52 void RunLoop(bool tight_loop = true);
@@ -82,6 +87,7 @@ private:
82 std::unique_ptr<ARM_Interface> arm_interface; 87 std::unique_ptr<ARM_Interface> arm_interface;
83 CpuBarrier& cpu_barrier; 88 CpuBarrier& cpu_barrier;
84 std::unique_ptr<Kernel::Scheduler> scheduler; 89 std::unique_ptr<Kernel::Scheduler> scheduler;
90 Timing::CoreTiming& core_timing;
85 91
86 std::atomic<bool> reschedule_pending = false; 92 std::atomic<bool> reschedule_pending = false;
87 std::size_t core_index; 93 std::size_t core_index;
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 4ea00c277..a0dd5db24 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -8,94 +8,42 @@
8#include <mutex> 8#include <mutex>
9#include <string> 9#include <string>
10#include <tuple> 10#include <tuple>
11#include <unordered_map> 11
12#include <vector>
13#include "common/assert.h" 12#include "common/assert.h"
14#include "common/thread.h" 13#include "common/thread.h"
15#include "common/threadsafe_queue.h"
16#include "core/core_timing_util.h" 14#include "core/core_timing_util.h"
17 15
18namespace Core::Timing { 16namespace Core::Timing {
19 17
20static s64 global_timer; 18constexpr int MAX_SLICE_LENGTH = 20000;
21static int slice_length;
22static int downcount;
23
24struct EventType {
25 TimedCallback callback;
26 const std::string* name;
27};
28 19
29struct Event { 20struct CoreTiming::Event {
30 s64 time; 21 s64 time;
31 u64 fifo_order; 22 u64 fifo_order;
32 u64 userdata; 23 u64 userdata;
33 const EventType* type; 24 const EventType* type;
34};
35
36// Sort by time, unless the times are the same, in which case sort by the order added to the queue
37static bool operator>(const Event& left, const Event& right) {
38 return std::tie(left.time, left.fifo_order) > std::tie(right.time, right.fifo_order);
39}
40
41static bool operator<(const Event& left, const Event& right) {
42 return std::tie(left.time, left.fifo_order) < std::tie(right.time, right.fifo_order);
43}
44
45// unordered_map stores each element separately as a linked list node so pointers to elements
46// remain stable regardless of rehashes/resizing.
47static std::unordered_map<std::string, EventType> event_types;
48 25
49// The queue is a min-heap using std::make_heap/push_heap/pop_heap. 26 // Sort by time, unless the times are the same, in which case sort by
50// We don't use std::priority_queue because we need to be able to serialize, unserialize and 27 // the order added to the queue
51// erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't accomodated 28 friend bool operator>(const Event& left, const Event& right) {
52// by the standard adaptor class. 29 return std::tie(left.time, left.fifo_order) > std::tie(right.time, right.fifo_order);
53static std::vector<Event> event_queue; 30 }
54static u64 event_fifo_id;
55// the queue for storing the events from other threads threadsafe until they will be added
56// to the event_queue by the emu thread
57static Common::MPSCQueue<Event> ts_queue;
58
59// the queue for unscheduling the events from other threads threadsafe
60static Common::MPSCQueue<std::pair<const EventType*, u64>> unschedule_queue;
61
62constexpr int MAX_SLICE_LENGTH = 20000;
63
64static s64 idled_cycles;
65
66// Are we in a function that has been called from Advance()
67// If events are sheduled from a function that gets called from Advance(),
68// don't change slice_length and downcount.
69static bool is_global_timer_sane;
70
71static EventType* ev_lost = nullptr;
72
73EventType* RegisterEvent(const std::string& name, TimedCallback callback) {
74 // check for existing type with same name.
75 // we want event type names to remain unique so that we can use them for serialization.
76 ASSERT_MSG(event_types.find(name) == event_types.end(),
77 "CoreTiming Event \"{}\" is already registered. Events should only be registered "
78 "during Init to avoid breaking save states.",
79 name.c_str());
80 31
81 auto info = event_types.emplace(name, EventType{callback, nullptr}); 32 friend bool operator<(const Event& left, const Event& right) {
82 EventType* event_type = &info.first->second; 33 return std::tie(left.time, left.fifo_order) < std::tie(right.time, right.fifo_order);
83 event_type->name = &info.first->first; 34 }
84 return event_type; 35};
85}
86 36
87void UnregisterAllEvents() { 37CoreTiming::CoreTiming() = default;
88 ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending"); 38CoreTiming::~CoreTiming() = default;
89 event_types.clear();
90}
91 39
92void Init() { 40void CoreTiming::Initialize() {
93 downcount = MAX_SLICE_LENGTH; 41 downcount = MAX_SLICE_LENGTH;
94 slice_length = MAX_SLICE_LENGTH; 42 slice_length = MAX_SLICE_LENGTH;
95 global_timer = 0; 43 global_timer = 0;
96 idled_cycles = 0; 44 idled_cycles = 0;
97 45
98 // The time between CoreTiming being intialized and the first call to Advance() is considered 46 // The time between CoreTiming being initialized and the first call to Advance() is considered
99 // the slice boundary between slice -1 and slice 0. Dispatcher loops must call Advance() before 47 // the slice boundary between slice -1 and slice 0. Dispatcher loops must call Advance() before
100 // executing the first cycle of each slice to prepare the slice length and downcount for 48 // executing the first cycle of each slice to prepare the slice length and downcount for
101 // that slice. 49 // that slice.
@@ -107,50 +55,51 @@ void Init() {
107 ev_lost = RegisterEvent("_lost_event", empty_timed_callback); 55 ev_lost = RegisterEvent("_lost_event", empty_timed_callback);
108} 56}
109 57
110void Shutdown() { 58void CoreTiming::Shutdown() {
111 MoveEvents(); 59 MoveEvents();
112 ClearPendingEvents(); 60 ClearPendingEvents();
113 UnregisterAllEvents(); 61 UnregisterAllEvents();
114} 62}
115 63
116// This should only be called from the CPU thread. If you are calling 64EventType* CoreTiming::RegisterEvent(const std::string& name, TimedCallback callback) {
117// it from any other thread, you are doing something evil 65 // check for existing type with same name.
118u64 GetTicks() { 66 // we want event type names to remain unique so that we can use them for serialization.
119 u64 ticks = static_cast<u64>(global_timer); 67 ASSERT_MSG(event_types.find(name) == event_types.end(),
120 if (!is_global_timer_sane) { 68 "CoreTiming Event \"{}\" is already registered. Events should only be registered "
121 ticks += slice_length - downcount; 69 "during Init to avoid breaking save states.",
122 } 70 name.c_str());
123 return ticks;
124}
125
126void AddTicks(u64 ticks) {
127 downcount -= static_cast<int>(ticks);
128}
129 71
130u64 GetIdleTicks() { 72 auto info = event_types.emplace(name, EventType{callback, nullptr});
131 return static_cast<u64>(idled_cycles); 73 EventType* event_type = &info.first->second;
74 event_type->name = &info.first->first;
75 return event_type;
132} 76}
133 77
134void ClearPendingEvents() { 78void CoreTiming::UnregisterAllEvents() {
135 event_queue.clear(); 79 ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending");
80 event_types.clear();
136} 81}
137 82
138void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) { 83void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
139 ASSERT(event_type != nullptr); 84 ASSERT(event_type != nullptr);
140 s64 timeout = GetTicks() + cycles_into_future; 85 const s64 timeout = GetTicks() + cycles_into_future;
86
141 // If this event needs to be scheduled before the next advance(), force one early 87 // If this event needs to be scheduled before the next advance(), force one early
142 if (!is_global_timer_sane) 88 if (!is_global_timer_sane) {
143 ForceExceptionCheck(cycles_into_future); 89 ForceExceptionCheck(cycles_into_future);
90 }
91
144 event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); 92 event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type});
145 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); 93 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
146} 94}
147 95
148void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata) { 96void CoreTiming::ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type,
97 u64 userdata) {
149 ts_queue.Push(Event{global_timer + cycles_into_future, 0, userdata, event_type}); 98 ts_queue.Push(Event{global_timer + cycles_into_future, 0, userdata, event_type});
150} 99}
151 100
152void UnscheduleEvent(const EventType* event_type, u64 userdata) { 101void CoreTiming::UnscheduleEvent(const EventType* event_type, u64 userdata) {
153 auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { 102 const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
154 return e.type == event_type && e.userdata == userdata; 103 return e.type == event_type && e.userdata == userdata;
155 }); 104 });
156 105
@@ -161,13 +110,33 @@ void UnscheduleEvent(const EventType* event_type, u64 userdata) {
161 } 110 }
162} 111}
163 112
164void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata) { 113void CoreTiming::UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata) {
165 unschedule_queue.Push(std::make_pair(event_type, userdata)); 114 unschedule_queue.Push(std::make_pair(event_type, userdata));
166} 115}
167 116
168void RemoveEvent(const EventType* event_type) { 117u64 CoreTiming::GetTicks() const {
169 auto itr = std::remove_if(event_queue.begin(), event_queue.end(), 118 u64 ticks = static_cast<u64>(global_timer);
170 [&](const Event& e) { return e.type == event_type; }); 119 if (!is_global_timer_sane) {
120 ticks += slice_length - downcount;
121 }
122 return ticks;
123}
124
125u64 CoreTiming::GetIdleTicks() const {
126 return static_cast<u64>(idled_cycles);
127}
128
129void CoreTiming::AddTicks(u64 ticks) {
130 downcount -= static_cast<int>(ticks);
131}
132
133void CoreTiming::ClearPendingEvents() {
134 event_queue.clear();
135}
136
137void CoreTiming::RemoveEvent(const EventType* event_type) {
138 const auto itr = std::remove_if(event_queue.begin(), event_queue.end(),
139 [&](const Event& e) { return e.type == event_type; });
171 140
172 // Removing random items breaks the invariant so we have to re-establish it. 141 // Removing random items breaks the invariant so we have to re-establish it.
173 if (itr != event_queue.end()) { 142 if (itr != event_queue.end()) {
@@ -176,22 +145,24 @@ void RemoveEvent(const EventType* event_type) {
176 } 145 }
177} 146}
178 147
179void RemoveNormalAndThreadsafeEvent(const EventType* event_type) { 148void CoreTiming::RemoveNormalAndThreadsafeEvent(const EventType* event_type) {
180 MoveEvents(); 149 MoveEvents();
181 RemoveEvent(event_type); 150 RemoveEvent(event_type);
182} 151}
183 152
184void ForceExceptionCheck(s64 cycles) { 153void CoreTiming::ForceExceptionCheck(s64 cycles) {
185 cycles = std::max<s64>(0, cycles); 154 cycles = std::max<s64>(0, cycles);
186 if (downcount > cycles) { 155 if (downcount <= cycles) {
187 // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int 156 return;
188 // here. Account for cycles already executed by adjusting the g.slice_length
189 slice_length -= downcount - static_cast<int>(cycles);
190 downcount = static_cast<int>(cycles);
191 } 157 }
158
159 // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int
160 // here. Account for cycles already executed by adjusting the g.slice_length
161 slice_length -= downcount - static_cast<int>(cycles);
162 downcount = static_cast<int>(cycles);
192} 163}
193 164
194void MoveEvents() { 165void CoreTiming::MoveEvents() {
195 for (Event ev; ts_queue.Pop(ev);) { 166 for (Event ev; ts_queue.Pop(ev);) {
196 ev.fifo_order = event_fifo_id++; 167 ev.fifo_order = event_fifo_id++;
197 event_queue.emplace_back(std::move(ev)); 168 event_queue.emplace_back(std::move(ev));
@@ -199,13 +170,13 @@ void MoveEvents() {
199 } 170 }
200} 171}
201 172
202void Advance() { 173void CoreTiming::Advance() {
203 MoveEvents(); 174 MoveEvents();
204 for (std::pair<const EventType*, u64> ev; unschedule_queue.Pop(ev);) { 175 for (std::pair<const EventType*, u64> ev; unschedule_queue.Pop(ev);) {
205 UnscheduleEvent(ev.first, ev.second); 176 UnscheduleEvent(ev.first, ev.second);
206 } 177 }
207 178
208 int cycles_executed = slice_length - downcount; 179 const int cycles_executed = slice_length - downcount;
209 global_timer += cycles_executed; 180 global_timer += cycles_executed;
210 slice_length = MAX_SLICE_LENGTH; 181 slice_length = MAX_SLICE_LENGTH;
211 182
@@ -229,16 +200,16 @@ void Advance() {
229 downcount = slice_length; 200 downcount = slice_length;
230} 201}
231 202
232void Idle() { 203void CoreTiming::Idle() {
233 idled_cycles += downcount; 204 idled_cycles += downcount;
234 downcount = 0; 205 downcount = 0;
235} 206}
236 207
237std::chrono::microseconds GetGlobalTimeUs() { 208std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
238 return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE}; 209 return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE};
239} 210}
240 211
241int GetDowncount() { 212int CoreTiming::GetDowncount() const {
242 return downcount; 213 return downcount;
243} 214}
244 215
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 093989d4c..59163bae1 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -4,92 +4,153 @@
4 4
5#pragma once 5#pragma once
6 6
7/**
8 * This is a system to schedule events into the emulated machine's future. Time is measured
9 * in main CPU clock cycles.
10 *
11 * To schedule an event, you first have to register its type. This is where you pass in the
12 * callback. You then schedule events using the type id you get back.
13 *
14 * The int cyclesLate that the callbacks get is how many cycles late it was.
15 * So to schedule a new event on a regular basis:
16 * inside callback:
17 * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
18 */
19
20#include <chrono> 7#include <chrono>
21#include <functional> 8#include <functional>
22#include <string> 9#include <string>
10#include <unordered_map>
11#include <vector>
23#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/threadsafe_queue.h"
24 14
25namespace Core::Timing { 15namespace Core::Timing {
26 16
27struct EventType; 17/// A callback that may be scheduled for a particular core timing event.
28
29using TimedCallback = std::function<void(u64 userdata, int cycles_late)>; 18using TimedCallback = std::function<void(u64 userdata, int cycles_late)>;
30 19
31/** 20/// Contains the characteristics of a particular event.
32 * CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is 21struct EventType {
33 * required to end slice -1 and start slice 0 before the first cycle of code is executed. 22 /// The event's callback function.
34 */ 23 TimedCallback callback;
35void Init(); 24 /// A pointer to the name of the event.
36void Shutdown(); 25 const std::string* name;
37 26};
38/**
39 * This should only be called from the emu thread, if you are calling it any other thread, you are
40 * doing something evil
41 */
42u64 GetTicks();
43u64 GetIdleTicks();
44void AddTicks(u64 ticks);
45
46/**
47 * Returns the event_type identifier. if name is not unique, it will assert.
48 */
49EventType* RegisterEvent(const std::string& name, TimedCallback callback);
50void UnregisterAllEvents();
51
52/**
53 * After the first Advance, the slice lengths and the downcount will be reduced whenever an event
54 * is scheduled earlier than the current values.
55 * Scheduling from a callback will not update the downcount until the Advance() completes.
56 */
57void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata = 0);
58 27
59/** 28/**
60 * This is to be called when outside of hle threads, such as the graphics thread, wants to 29 * This is a system to schedule events into the emulated machine's future. Time is measured
61 * schedule things to be executed on the main thread. 30 * in main CPU clock cycles.
62 * Not that this doesn't change slice_length and thus events scheduled by this might be called 31 *
63 * with a delay of up to MAX_SLICE_LENGTH 32 * To schedule an event, you first have to register its type. This is where you pass in the
64 */ 33 * callback. You then schedule events using the type id you get back.
65void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata); 34 *
66 35 * The int cyclesLate that the callbacks get is how many cycles late it was.
67void UnscheduleEvent(const EventType* event_type, u64 userdata); 36 * So to schedule a new event on a regular basis:
68void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata); 37 * inside callback:
69 38 * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
70/// We only permit one event of each type in the queue at a time.
71void RemoveEvent(const EventType* event_type);
72void RemoveNormalAndThreadsafeEvent(const EventType* event_type);
73
74/** Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends
75 * the previous timing slice and begins the next one, you must Advance from the previous
76 * slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an
77 * Advance() is required to initialize the slice length before the first cycle of emulated
78 * instructions is executed.
79 */ 39 */
80void Advance(); 40class CoreTiming {
81void MoveEvents(); 41public:
82 42 CoreTiming();
83/// Pretend that the main CPU has executed enough cycles to reach the next event. 43 ~CoreTiming();
84void Idle(); 44
85 45 CoreTiming(const CoreTiming&) = delete;
86/// Clear all pending events. This should ONLY be done on exit. 46 CoreTiming(CoreTiming&&) = delete;
87void ClearPendingEvents(); 47
88 48 CoreTiming& operator=(const CoreTiming&) = delete;
89void ForceExceptionCheck(s64 cycles); 49 CoreTiming& operator=(CoreTiming&&) = delete;
90 50
91std::chrono::microseconds GetGlobalTimeUs(); 51 /// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
92 52 /// required to end slice - 1 and start slice 0 before the first cycle of code is executed.
93int GetDowncount(); 53 void Initialize();
54
55 /// Tears down all timing related functionality.
56 void Shutdown();
57
58 /// Registers a core timing event with the given name and callback.
59 ///
60 /// @param name The name of the core timing event to register.
61 /// @param callback The callback to execute for the event.
62 ///
63 /// @returns An EventType instance representing the registered event.
64 ///
65 /// @pre The name of the event being registered must be unique among all
66 /// registered events.
67 ///
68 EventType* RegisterEvent(const std::string& name, TimedCallback callback);
69
70 /// Unregisters all registered events thus far.
71 void UnregisterAllEvents();
72
73 /// After the first Advance, the slice lengths and the downcount will be reduced whenever an
74 /// event is scheduled earlier than the current values.
75 ///
76 /// Scheduling from a callback will not update the downcount until the Advance() completes.
77 void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata = 0);
78
79 /// This is to be called when outside of hle threads, such as the graphics thread, wants to
80 /// schedule things to be executed on the main thread.
81 ///
82 /// @note This doesn't change slice_length and thus events scheduled by this might be
83 /// called with a delay of up to MAX_SLICE_LENGTH
84 void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type,
85 u64 userdata = 0);
86
87 void UnscheduleEvent(const EventType* event_type, u64 userdata);
88 void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata);
89
90 /// We only permit one event of each type in the queue at a time.
91 void RemoveEvent(const EventType* event_type);
92 void RemoveNormalAndThreadsafeEvent(const EventType* event_type);
93
94 void ForceExceptionCheck(s64 cycles);
95
96 /// This should only be called from the emu thread, if you are calling it any other thread,
97 /// you are doing something evil
98 u64 GetTicks() const;
99
100 u64 GetIdleTicks() const;
101
102 void AddTicks(u64 ticks);
103
104 /// Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends
105 /// the previous timing slice and begins the next one, you must Advance from the previous
106 /// slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an
107 /// Advance() is required to initialize the slice length before the first cycle of emulated
108 /// instructions is executed.
109 void Advance();
110
111 /// Pretend that the main CPU has executed enough cycles to reach the next event.
112 void Idle();
113
114 std::chrono::microseconds GetGlobalTimeUs() const;
115
116 int GetDowncount() const;
117
118private:
119 struct Event;
120
121 /// Clear all pending events. This should ONLY be done on exit.
122 void ClearPendingEvents();
123 void MoveEvents();
124
125 s64 global_timer = 0;
126 s64 idled_cycles = 0;
127 int slice_length = 0;
128 int downcount = 0;
129
130 // Are we in a function that has been called from Advance()
131 // If events are scheduled from a function that gets called from Advance(),
132 // don't change slice_length and downcount.
133 bool is_global_timer_sane = false;
134
135 // The queue is a min-heap using std::make_heap/push_heap/pop_heap.
136 // We don't use std::priority_queue because we need to be able to serialize, unserialize and
137 // erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't
138 // accomodated by the standard adaptor class.
139 std::vector<Event> event_queue;
140 u64 event_fifo_id = 0;
141
142 // Stores each element separately as a linked list node so pointers to elements
143 // remain stable regardless of rehashes/resizing.
144 std::unordered_map<std::string, EventType> event_types;
145
146 // The queue for storing the events from other threads threadsafe until they will be added
147 // to the event_queue by the emu thread
148 Common::MPSCQueue<Event> ts_queue;
149
150 // The queue for unscheduling the events from other threads threadsafe
151 Common::MPSCQueue<std::pair<const EventType*, u64>> unschedule_queue;
152
153 EventType* ev_lost = nullptr;
154};
94 155
95} // namespace Core::Timing 156} // namespace Core::Timing
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp
index 769a6fefa..2ddb3610d 100644
--- a/src/core/cpu_core_manager.cpp
+++ b/src/core/cpu_core_manager.cpp
@@ -27,7 +27,8 @@ void CpuCoreManager::Initialize(System& system) {
27 exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size()); 27 exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
28 28
29 for (std::size_t index = 0; index < cores.size(); ++index) { 29 for (std::size_t index = 0; index < cores.size(); ++index) {
30 cores[index] = std::make_unique<Cpu>(*exclusive_monitor, *barrier, index); 30 cores[index] =
31 std::make_unique<Cpu>(system.CoreTiming(), *exclusive_monitor, *barrier, index);
31 } 32 }
32 33
33 // Create threads for CPU cores 1-3, and build thread_to_cpu map 34 // Create threads for CPU cores 1-3, and build thread_to_cpu map
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 3721ae8fe..dd749eed4 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -86,11 +86,11 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_
86} 86}
87 87
88struct KernelCore::Impl { 88struct KernelCore::Impl {
89 void Initialize(KernelCore& kernel) { 89 void Initialize(KernelCore& kernel, Core::Timing::CoreTiming& core_timing) {
90 Shutdown(); 90 Shutdown();
91 91
92 InitializeSystemResourceLimit(kernel); 92 InitializeSystemResourceLimit(kernel);
93 InitializeThreads(); 93 InitializeThreads(core_timing);
94 } 94 }
95 95
96 void Shutdown() { 96 void Shutdown() {
@@ -122,9 +122,9 @@ struct KernelCore::Impl {
122 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess()); 122 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());
123 } 123 }
124 124
125 void InitializeThreads() { 125 void InitializeThreads(Core::Timing::CoreTiming& core_timing) {
126 thread_wakeup_event_type = 126 thread_wakeup_event_type =
127 Core::Timing::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); 127 core_timing.RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
128 } 128 }
129 129
130 std::atomic<u32> next_object_id{0}; 130 std::atomic<u32> next_object_id{0};
@@ -152,8 +152,8 @@ KernelCore::~KernelCore() {
152 Shutdown(); 152 Shutdown();
153} 153}
154 154
155void KernelCore::Initialize() { 155void KernelCore::Initialize(Core::Timing::CoreTiming& core_timing) {
156 impl->Initialize(*this); 156 impl->Initialize(*this, core_timing);
157} 157}
158 158
159void KernelCore::Shutdown() { 159void KernelCore::Shutdown() {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 7406f107e..154bced42 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -12,8 +12,9 @@ template <typename T>
12class ResultVal; 12class ResultVal;
13 13
14namespace Core::Timing { 14namespace Core::Timing {
15class CoreTiming;
15struct EventType; 16struct EventType;
16} 17} // namespace Core::Timing
17 18
18namespace Kernel { 19namespace Kernel {
19 20
@@ -39,7 +40,11 @@ public:
39 KernelCore& operator=(KernelCore&&) = delete; 40 KernelCore& operator=(KernelCore&&) = delete;
40 41
41 /// Resets the kernel to a clean slate for use. 42 /// Resets the kernel to a clean slate for use.
42 void Initialize(); 43 ///
44 /// @param core_timing CoreTiming instance used to create any necessary
45 /// kernel-specific callback events.
46 ///
47 void Initialize(Core::Timing::CoreTiming& core_timing);
43 48
44 /// Clears all resources in use by the kernel instance. 49 /// Clears all resources in use by the kernel instance.
45 void Shutdown(); 50 void Shutdown();
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 9e2517e1b..44f30d070 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -111,7 +111,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
111 111
112void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { 112void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) {
113 const u64 prev_switch_ticks = last_context_switch_time; 113 const u64 prev_switch_ticks = last_context_switch_time;
114 const u64 most_recent_switch_ticks = Core::Timing::GetTicks(); 114 const u64 most_recent_switch_ticks = Core::System::GetInstance().CoreTiming().GetTicks();
115 const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; 115 const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
116 116
117 if (thread != nullptr) { 117 if (thread != nullptr) {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 5f040f79f..c5d399bab 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -918,6 +918,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
918 } 918 }
919 919
920 const auto& system = Core::System::GetInstance(); 920 const auto& system = Core::System::GetInstance();
921 const auto& core_timing = system.CoreTiming();
921 const auto& scheduler = system.CurrentScheduler(); 922 const auto& scheduler = system.CurrentScheduler();
922 const auto* const current_thread = scheduler.GetCurrentThread(); 923 const auto* const current_thread = scheduler.GetCurrentThread();
923 const bool same_thread = current_thread == thread; 924 const bool same_thread = current_thread == thread;
@@ -927,9 +928,9 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
927 if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { 928 if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
928 const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks(); 929 const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks();
929 930
930 out_ticks = thread_ticks + (Core::Timing::GetTicks() - prev_ctx_ticks); 931 out_ticks = thread_ticks + (core_timing.GetTicks() - prev_ctx_ticks);
931 } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { 932 } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) {
932 out_ticks = Core::Timing::GetTicks() - prev_ctx_ticks; 933 out_ticks = core_timing.GetTicks() - prev_ctx_ticks;
933 } 934 }
934 935
935 *result = out_ticks; 936 *result = out_ticks;
@@ -1546,10 +1547,11 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
1546static u64 GetSystemTick() { 1547static u64 GetSystemTick() {
1547 LOG_TRACE(Kernel_SVC, "called"); 1548 LOG_TRACE(Kernel_SVC, "called");
1548 1549
1549 const u64 result{Core::Timing::GetTicks()}; 1550 auto& core_timing = Core::System::GetInstance().CoreTiming();
1551 const u64 result{core_timing.GetTicks()};
1550 1552
1551 // Advance time to defeat dumb games that busy-wait for the frame to end. 1553 // Advance time to defeat dumb games that busy-wait for the frame to end.
1552 Core::Timing::AddTicks(400); 1554 core_timing.AddTicks(400);
1553 1555
1554 return result; 1556 return result;
1555} 1557}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 7881c2b90..6661e2130 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -43,7 +43,8 @@ Thread::~Thread() = default;
43 43
44void Thread::Stop() { 44void Thread::Stop() {
45 // Cancel any outstanding wakeup events for this thread 45 // Cancel any outstanding wakeup events for this thread
46 Core::Timing::UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), callback_handle); 46 Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(),
47 callback_handle);
47 kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); 48 kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle);
48 callback_handle = 0; 49 callback_handle = 0;
49 50
@@ -85,13 +86,14 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
85 86
86 // This function might be called from any thread so we have to be cautious and use the 87 // This function might be called from any thread so we have to be cautious and use the
87 // thread-safe version of ScheduleEvent. 88 // thread-safe version of ScheduleEvent.
88 Core::Timing::ScheduleEventThreadsafe(Core::Timing::nsToCycles(nanoseconds), 89 Core::System::GetInstance().CoreTiming().ScheduleEventThreadsafe(
89 kernel.ThreadWakeupCallbackEventType(), callback_handle); 90 Core::Timing::nsToCycles(nanoseconds), kernel.ThreadWakeupCallbackEventType(),
91 callback_handle);
90} 92}
91 93
92void Thread::CancelWakeupTimer() { 94void Thread::CancelWakeupTimer() {
93 Core::Timing::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(), 95 Core::System::GetInstance().CoreTiming().UnscheduleEventThreadsafe(
94 callback_handle); 96 kernel.ThreadWakeupCallbackEventType(), callback_handle);
95} 97}
96 98
97static std::optional<s32> GetNextProcessorId(u64 mask) { 99static std::optional<s32> GetNextProcessorId(u64 mask) {
@@ -190,6 +192,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
190 return ResultCode(-1); 192 return ResultCode(-1);
191 } 193 }
192 194
195 auto& system = Core::System::GetInstance();
193 SharedPtr<Thread> thread(new Thread(kernel)); 196 SharedPtr<Thread> thread(new Thread(kernel));
194 197
195 thread->thread_id = kernel.CreateNewThreadID(); 198 thread->thread_id = kernel.CreateNewThreadID();
@@ -198,7 +201,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
198 thread->stack_top = stack_top; 201 thread->stack_top = stack_top;
199 thread->tpidr_el0 = 0; 202 thread->tpidr_el0 = 0;
200 thread->nominal_priority = thread->current_priority = priority; 203 thread->nominal_priority = thread->current_priority = priority;
201 thread->last_running_ticks = Core::Timing::GetTicks(); 204 thread->last_running_ticks = system.CoreTiming().GetTicks();
202 thread->processor_id = processor_id; 205 thread->processor_id = processor_id;
203 thread->ideal_core = processor_id; 206 thread->ideal_core = processor_id;
204 thread->affinity_mask = 1ULL << processor_id; 207 thread->affinity_mask = 1ULL << processor_id;
@@ -209,7 +212,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
209 thread->name = std::move(name); 212 thread->name = std::move(name);
210 thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap(); 213 thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap();
211 thread->owner_process = &owner_process; 214 thread->owner_process = &owner_process;
212 thread->scheduler = &Core::System::GetInstance().Scheduler(processor_id); 215 thread->scheduler = &system.Scheduler(processor_id);
213 thread->scheduler->AddThread(thread, priority); 216 thread->scheduler->AddThread(thread, priority);
214 thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread); 217 thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);
215 218
@@ -258,7 +261,7 @@ void Thread::SetStatus(ThreadStatus new_status) {
258 } 261 }
259 262
260 if (status == ThreadStatus::Running) { 263 if (status == ThreadStatus::Running) {
261 last_running_ticks = Core::Timing::GetTicks(); 264 last_running_ticks = Core::System::GetInstance().CoreTiming().GetTicks();
262 } 265 }
263 266
264 status = new_status; 267 status = new_status;
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index dc6a6b188..6831c0735 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -68,12 +68,12 @@ public:
68 RegisterHandlers(functions); 68 RegisterHandlers(functions);
69 69
70 // This is the event handle used to check if the audio buffer was released 70 // This is the event handle used to check if the audio buffer was released
71 auto& kernel = Core::System::GetInstance().Kernel(); 71 auto& system = Core::System::GetInstance();
72 buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, 72 buffer_event = Kernel::WritableEvent::CreateEventPair(
73 "IAudioOutBufferReleased"); 73 system.Kernel(), Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
74 74
75 stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count, 75 stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
76 std::move(unique_name), 76 audio_params.channel_count, std::move(unique_name),
77 [=]() { buffer_event.writable->Signal(); }); 77 [=]() { buffer_event.writable->Signal(); });
78 } 78 }
79 79
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 76cc48254..7e0cc64a8 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -42,10 +42,11 @@ public:
42 // clang-format on 42 // clang-format on
43 RegisterHandlers(functions); 43 RegisterHandlers(functions);
44 44
45 auto& kernel = Core::System::GetInstance().Kernel(); 45 auto& system = Core::System::GetInstance();
46 system_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, 46 system_event = Kernel::WritableEvent::CreateEventPair(
47 "IAudioRenderer:SystemEvent"); 47 system.Kernel(), Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent");
48 renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event.writable); 48 renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), audren_params,
49 system_event.writable);
49 } 50 }
50 51
51private: 52private:
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
index f0e092b1b..5e5097a03 100644
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -7,6 +7,10 @@
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/swap.h" 8#include "common/swap.h"
9 9
10namespace Core::Timing {
11class CoreTiming;
12}
13
10namespace Service::HID { 14namespace Service::HID {
11class ControllerBase { 15class ControllerBase {
12public: 16public:
@@ -20,7 +24,8 @@ public:
20 virtual void OnRelease() = 0; 24 virtual void OnRelease() = 0;
21 25
22 // When the controller is requesting an update for the shared memory 26 // When the controller is requesting an update for the shared memory
23 virtual void OnUpdate(u8* data, std::size_t size) = 0; 27 virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
28 std::size_t size) = 0;
24 29
25 // Called when input devices should be loaded 30 // Called when input devices should be loaded
26 virtual void OnLoadInputDevices() = 0; 31 virtual void OnLoadInputDevices() = 0;
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index b264c9503..c5c2e032a 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -21,8 +21,9 @@ void Controller_DebugPad::OnInit() {}
21 21
22void Controller_DebugPad::OnRelease() {} 22void Controller_DebugPad::OnRelease() {}
23 23
24void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) { 24void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
25 shared_memory.header.timestamp = Core::Timing::GetTicks(); 25 std::size_t size) {
26 shared_memory.header.timestamp = core_timing.GetTicks();
26 shared_memory.header.total_entry_count = 17; 27 shared_memory.header.total_entry_count = 17;
27 28
28 if (!IsControllerActivated()) { 29 if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
index 68b734248..929035034 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -26,7 +26,7 @@ public:
26 void OnRelease() override; 26 void OnRelease() override;
27 27
28 // When the controller is requesting an update for the shared memory 28 // When the controller is requesting an update for the shared memory
29 void OnUpdate(u8* data, std::size_t size) override; 29 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
30 30
31 // Called when input devices should be loaded 31 // Called when input devices should be loaded
32 void OnLoadInputDevices() override; 32 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
index 6d21f1a7d..a179252e3 100644
--- a/src/core/hle/service/hid/controllers/gesture.cpp
+++ b/src/core/hle/service/hid/controllers/gesture.cpp
@@ -17,8 +17,9 @@ void Controller_Gesture::OnInit() {}
17 17
18void Controller_Gesture::OnRelease() {} 18void Controller_Gesture::OnRelease() {}
19 19
20void Controller_Gesture::OnUpdate(u8* data, std::size_t size) { 20void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
21 shared_memory.header.timestamp = Core::Timing::GetTicks(); 21 std::size_t size) {
22 shared_memory.header.timestamp = core_timing.GetTicks();
22 shared_memory.header.total_entry_count = 17; 23 shared_memory.header.total_entry_count = 17;
23 24
24 if (!IsControllerActivated()) { 25 if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h
index 1056ffbcd..f305fe90f 100644
--- a/src/core/hle/service/hid/controllers/gesture.h
+++ b/src/core/hle/service/hid/controllers/gesture.h
@@ -22,7 +22,7 @@ public:
22 void OnRelease() override; 22 void OnRelease() override;
23 23
24 // When the controller is requesting an update for the shared memory 24 // When the controller is requesting an update for the shared memory
25 void OnUpdate(u8* data, size_t size) override; 25 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override;
26 26
27 // Called when input devices should be loaded 27 // Called when input devices should be loaded
28 void OnLoadInputDevices() override; 28 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index 798f30436..92d7bfb52 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -19,8 +19,9 @@ void Controller_Keyboard::OnInit() {}
19 19
20void Controller_Keyboard::OnRelease() {} 20void Controller_Keyboard::OnRelease() {}
21 21
22void Controller_Keyboard::OnUpdate(u8* data, std::size_t size) { 22void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
23 shared_memory.header.timestamp = Core::Timing::GetTicks(); 23 std::size_t size) {
24 shared_memory.header.timestamp = core_timing.GetTicks();
24 shared_memory.header.total_entry_count = 17; 25 shared_memory.header.total_entry_count = 17;
25 26
26 if (!IsControllerActivated()) { 27 if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index f52775456..73cd2c7bb 100644
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -25,7 +25,7 @@ public:
25 void OnRelease() override; 25 void OnRelease() override;
26 26
27 // When the controller is requesting an update for the shared memory 27 // When the controller is requesting an update for the shared memory
28 void OnUpdate(u8* data, std::size_t size) override; 28 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
29 29
30 // Called when input devices should be loaded 30 // Called when input devices should be loaded
31 void OnLoadInputDevices() override; 31 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
index 4985037be..11ab096d9 100644
--- a/src/core/hle/service/hid/controllers/mouse.cpp
+++ b/src/core/hle/service/hid/controllers/mouse.cpp
@@ -17,8 +17,9 @@ Controller_Mouse::~Controller_Mouse() = default;
17void Controller_Mouse::OnInit() {} 17void Controller_Mouse::OnInit() {}
18void Controller_Mouse::OnRelease() {} 18void Controller_Mouse::OnRelease() {}
19 19
20void Controller_Mouse::OnUpdate(u8* data, std::size_t size) { 20void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
21 shared_memory.header.timestamp = Core::Timing::GetTicks(); 21 std::size_t size) {
22 shared_memory.header.timestamp = core_timing.GetTicks();
22 shared_memory.header.total_entry_count = 17; 23 shared_memory.header.total_entry_count = 17;
23 24
24 if (!IsControllerActivated()) { 25 if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
index 70b654d07..9d46eecbe 100644
--- a/src/core/hle/service/hid/controllers/mouse.h
+++ b/src/core/hle/service/hid/controllers/mouse.h
@@ -24,7 +24,7 @@ public:
24 void OnRelease() override; 24 void OnRelease() override;
25 25
26 // When the controller is requesting an update for the shared memory 26 // When the controller is requesting an update for the shared memory
27 void OnUpdate(u8* data, std::size_t size) override; 27 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
28 28
29 // Called when input devices should be loaded 29 // Called when input devices should be loaded
30 void OnLoadInputDevices() override; 30 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index ffdd1c593..e7fc7a619 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -288,7 +288,8 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
288 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); 288 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
289} 289}
290 290
291void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { 291void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
292 std::size_t data_len) {
292 if (!IsControllerActivated()) 293 if (!IsControllerActivated())
293 return; 294 return;
294 for (std::size_t i = 0; i < shared_memory_entries.size(); i++) { 295 for (std::size_t i = 0; i < shared_memory_entries.size(); i++) {
@@ -308,7 +309,7 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
308 const auto& last_entry = 309 const auto& last_entry =
309 main_controller->npad[main_controller->common.last_entry_index]; 310 main_controller->npad[main_controller->common.last_entry_index];
310 311
311 main_controller->common.timestamp = Core::Timing::GetTicks(); 312 main_controller->common.timestamp = core_timing.GetTicks();
312 main_controller->common.last_entry_index = 313 main_controller->common.last_entry_index =
313 (main_controller->common.last_entry_index + 1) % 17; 314 (main_controller->common.last_entry_index + 1) % 17;
314 315
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 106cf58c8..18c7a94e6 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -30,7 +30,7 @@ public:
30 void OnRelease() override; 30 void OnRelease() override;
31 31
32 // When the controller is requesting an update for the shared memory 32 // When the controller is requesting an update for the shared memory
33 void OnUpdate(u8* data, std::size_t size) override; 33 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
34 34
35 // Called when input devices should be loaded 35 // Called when input devices should be loaded
36 void OnLoadInputDevices() override; 36 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp
index cca4dca1d..946948f5e 100644
--- a/src/core/hle/service/hid/controllers/stubbed.cpp
+++ b/src/core/hle/service/hid/controllers/stubbed.cpp
@@ -16,13 +16,14 @@ void Controller_Stubbed::OnInit() {}
16 16
17void Controller_Stubbed::OnRelease() {} 17void Controller_Stubbed::OnRelease() {}
18 18
19void Controller_Stubbed::OnUpdate(u8* data, std::size_t size) { 19void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
20 std::size_t size) {
20 if (!smart_update) { 21 if (!smart_update) {
21 return; 22 return;
22 } 23 }
23 24
24 CommonHeader header{}; 25 CommonHeader header{};
25 header.timestamp = Core::Timing::GetTicks(); 26 header.timestamp = core_timing.GetTicks();
26 header.total_entry_count = 17; 27 header.total_entry_count = 17;
27 header.entry_count = 0; 28 header.entry_count = 0;
28 header.last_entry_index = 0; 29 header.last_entry_index = 0;
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h
index 4a21c643e..24469f03e 100644
--- a/src/core/hle/service/hid/controllers/stubbed.h
+++ b/src/core/hle/service/hid/controllers/stubbed.h
@@ -20,7 +20,7 @@ public:
20 void OnRelease() override; 20 void OnRelease() override;
21 21
22 // When the controller is requesting an update for the shared memory 22 // When the controller is requesting an update for the shared memory
23 void OnUpdate(u8* data, std::size_t size) override; 23 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
24 24
25 // Called when input devices should be loaded 25 // Called when input devices should be loaded
26 void OnLoadInputDevices() override; 26 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index a7c8acc72..1a8445a43 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -20,8 +20,9 @@ void Controller_Touchscreen::OnInit() {}
20 20
21void Controller_Touchscreen::OnRelease() {} 21void Controller_Touchscreen::OnRelease() {}
22 22
23void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) { 23void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
24 shared_memory.header.timestamp = Core::Timing::GetTicks(); 24 std::size_t size) {
25 shared_memory.header.timestamp = core_timing.GetTicks();
25 shared_memory.header.total_entry_count = 17; 26 shared_memory.header.total_entry_count = 17;
26 27
27 if (!IsControllerActivated()) { 28 if (!IsControllerActivated()) {
@@ -48,7 +49,7 @@ void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) {
48 touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; 49 touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
49 touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; 50 touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
50 touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; 51 touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
51 const u64 tick = Core::Timing::GetTicks(); 52 const u64 tick = core_timing.GetTicks();
52 touch_entry.delta_time = tick - last_touch; 53 touch_entry.delta_time = tick - last_touch;
53 last_touch = tick; 54 last_touch = tick;
54 touch_entry.finger = Settings::values.touchscreen.finger; 55 touch_entry.finger = Settings::values.touchscreen.finger;
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index 94cd0eba9..012b6e0dd 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -24,7 +24,7 @@ public:
24 void OnRelease() override; 24 void OnRelease() override;
25 25
26 // When the controller is requesting an update for the shared memory 26 // When the controller is requesting an update for the shared memory
27 void OnUpdate(u8* data, std::size_t size) override; 27 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
28 28
29 // Called when input devices should be loaded 29 // Called when input devices should be loaded
30 void OnLoadInputDevices() override; 30 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp
index eff03d14e..1a9da9576 100644
--- a/src/core/hle/service/hid/controllers/xpad.cpp
+++ b/src/core/hle/service/hid/controllers/xpad.cpp
@@ -17,9 +17,10 @@ void Controller_XPad::OnInit() {}
17 17
18void Controller_XPad::OnRelease() {} 18void Controller_XPad::OnRelease() {}
19 19
20void Controller_XPad::OnUpdate(u8* data, std::size_t size) { 20void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
21 std::size_t size) {
21 for (auto& xpad_entry : shared_memory.shared_memory_entries) { 22 for (auto& xpad_entry : shared_memory.shared_memory_entries) {
22 xpad_entry.header.timestamp = Core::Timing::GetTicks(); 23 xpad_entry.header.timestamp = core_timing.GetTicks();
23 xpad_entry.header.total_entry_count = 17; 24 xpad_entry.header.total_entry_count = 17;
24 25
25 if (!IsControllerActivated()) { 26 if (!IsControllerActivated()) {
diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h
index ff836989f..2864e6617 100644
--- a/src/core/hle/service/hid/controllers/xpad.h
+++ b/src/core/hle/service/hid/controllers/xpad.h
@@ -22,7 +22,7 @@ public:
22 void OnRelease() override; 22 void OnRelease() override;
23 23
24 // When the controller is requesting an update for the shared memory 24 // When the controller is requesting an update for the shared memory
25 void OnUpdate(u8* data, std::size_t size) override; 25 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
26 26
27 // Called when input devices should be loaded 27 // Called when input devices should be loaded
28 void OnLoadInputDevices() override; 28 void OnLoadInputDevices() override;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 79c320d04..8a6de83a2 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -73,13 +73,15 @@ IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") {
73 GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); 73 GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
74 74
75 // Register update callbacks 75 // Register update callbacks
76 pad_update_event = Core::Timing::RegisterEvent( 76 auto& core_timing = Core::System::GetInstance().CoreTiming();
77 "HID::UpdatePadCallback", 77 pad_update_event =
78 [this](u64 userdata, int cycles_late) { UpdateControllers(userdata, cycles_late); }); 78 core_timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, int cycles_late) {
79 UpdateControllers(userdata, cycles_late);
80 });
79 81
80 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) 82 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
81 83
82 Core::Timing::ScheduleEvent(pad_update_ticks, pad_update_event); 84 core_timing.ScheduleEvent(pad_update_ticks, pad_update_event);
83 85
84 ReloadInputDevices(); 86 ReloadInputDevices();
85} 87}
@@ -93,7 +95,7 @@ void IAppletResource::DeactivateController(HidController controller) {
93} 95}
94 96
95IAppletResource ::~IAppletResource() { 97IAppletResource ::~IAppletResource() {
96 Core::Timing::UnscheduleEvent(pad_update_event, 0); 98 Core::System::GetInstance().CoreTiming().UnscheduleEvent(pad_update_event, 0);
97} 99}
98 100
99void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { 101void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
@@ -105,15 +107,17 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
105} 107}
106 108
107void IAppletResource::UpdateControllers(u64 userdata, int cycles_late) { 109void IAppletResource::UpdateControllers(u64 userdata, int cycles_late) {
110 auto& core_timing = Core::System::GetInstance().CoreTiming();
111
108 const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); 112 const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
109 for (const auto& controller : controllers) { 113 for (const auto& controller : controllers) {
110 if (should_reload) { 114 if (should_reload) {
111 controller->OnLoadInputDevices(); 115 controller->OnLoadInputDevices();
112 } 116 }
113 controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE); 117 controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
114 } 118 }
115 119
116 Core::Timing::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); 120 core_timing.ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
117} 121}
118 122
119class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { 123class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index b427d4068..2c4625c99 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -98,7 +98,7 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
98 98
99 IPC::ResponseBuilder rb{ctx, 5}; 99 IPC::ResponseBuilder rb{ctx, 5};
100 rb.Push(RESULT_SUCCESS); 100 rb.Push(RESULT_SUCCESS);
101 rb.PushRaw<u64>(Core::Timing::GetTicks()); 101 rb.PushRaw<u64>(Core::System::GetInstance().CoreTiming().GetTicks());
102 rb.PushRaw<u32>(0); 102 rb.PushRaw<u32>(0);
103} 103}
104 104
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 88d80ba06..45812d238 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -5,6 +5,7 @@
5#include <cstring> 5#include <cstring>
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h"
8#include "core/core_timing.h" 9#include "core/core_timing.h"
9#include "core/core_timing_util.h" 10#include "core/core_timing_util.h"
10#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" 11#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
@@ -184,7 +185,7 @@ u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& o
184 185
185 IoctlGetGpuTime params{}; 186 IoctlGetGpuTime params{};
186 std::memcpy(&params, input.data(), input.size()); 187 std::memcpy(&params, input.data(), input.size());
187 params.gpu_time = Core::Timing::cyclesToNs(Core::Timing::GetTicks()); 188 params.gpu_time = Core::Timing::cyclesToNs(Core::System::GetInstance().CoreTiming().GetTicks());
188 std::memcpy(output.data(), &params, output.size()); 189 std::memcpy(output.data(), &params, output.size());
189 return 0; 190 return 0;
190} 191}
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index ce1b59860..3babc3f7c 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -27,19 +27,19 @@ namespace Service::NVFlinger {
27constexpr std::size_t SCREEN_REFRESH_RATE = 60; 27constexpr std::size_t SCREEN_REFRESH_RATE = 60;
28constexpr u64 frame_ticks = static_cast<u64>(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); 28constexpr u64 frame_ticks = static_cast<u64>(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE);
29 29
30NVFlinger::NVFlinger() { 30NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_timing} {
31 // Schedule the screen composition events 31 // Schedule the screen composition events
32 composition_event = 32 composition_event =
33 Core::Timing::RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) { 33 core_timing.RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) {
34 Compose(); 34 Compose();
35 Core::Timing::ScheduleEvent(frame_ticks - cycles_late, composition_event); 35 this->core_timing.ScheduleEvent(frame_ticks - cycles_late, composition_event);
36 }); 36 });
37 37
38 Core::Timing::ScheduleEvent(frame_ticks, composition_event); 38 core_timing.ScheduleEvent(frame_ticks, composition_event);
39} 39}
40 40
41NVFlinger::~NVFlinger() { 41NVFlinger::~NVFlinger() {
42 Core::Timing::UnscheduleEvent(composition_event, 0); 42 core_timing.UnscheduleEvent(composition_event, 0);
43} 43}
44 44
45void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { 45void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 6d8bcbd30..437aa592d 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -15,8 +15,9 @@
15#include "core/hle/kernel/object.h" 15#include "core/hle/kernel/object.h"
16 16
17namespace Core::Timing { 17namespace Core::Timing {
18class CoreTiming;
18struct EventType; 19struct EventType;
19} 20} // namespace Core::Timing
20 21
21namespace Kernel { 22namespace Kernel {
22class ReadableEvent; 23class ReadableEvent;
@@ -52,7 +53,7 @@ struct Display {
52 53
53class NVFlinger final { 54class NVFlinger final {
54public: 55public:
55 NVFlinger(); 56 explicit NVFlinger(Core::Timing::CoreTiming& core_timing);
56 ~NVFlinger(); 57 ~NVFlinger();
57 58
58 /// Sets the NVDrv module instance to use to send buffers to the GPU. 59 /// Sets the NVDrv module instance to use to send buffers to the GPU.
@@ -117,6 +118,9 @@ private:
117 118
118 /// Event that handles screen composition. 119 /// Event that handles screen composition.
119 Core::Timing::EventType* composition_event; 120 Core::Timing::EventType* composition_event;
121
122 /// Core timing instance for registering/unregistering the composition event.
123 Core::Timing::CoreTiming& core_timing;
120}; 124};
121 125
122} // namespace Service::NVFlinger 126} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index d25b80ab0..117f87a45 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -194,10 +194,11 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
194// Module interface 194// Module interface
195 195
196/// Initialize ServiceManager 196/// Initialize ServiceManager
197void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs) { 197void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
198 FileSys::VfsFilesystem& vfs) {
198 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it 199 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
199 // here and pass it into the respective InstallInterfaces functions. 200 // here and pass it into the respective InstallInterfaces functions.
200 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(); 201 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming());
201 202
202 SM::ServiceManager::InstallInterfaces(sm); 203 SM::ServiceManager::InstallInterfaces(sm);
203 204
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 029533628..830790269 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -14,6 +14,14 @@
14//////////////////////////////////////////////////////////////////////////////////////////////////// 14////////////////////////////////////////////////////////////////////////////////////////////////////
15// Namespace Service 15// Namespace Service
16 16
17namespace Core {
18class System;
19}
20
21namespace FileSys {
22class VfsFilesystem;
23}
24
17namespace Kernel { 25namespace Kernel {
18class ClientPort; 26class ClientPort;
19class ServerPort; 27class ServerPort;
@@ -21,10 +29,6 @@ class ServerSession;
21class HLERequestContext; 29class HLERequestContext;
22} // namespace Kernel 30} // namespace Kernel
23 31
24namespace FileSys {
25class VfsFilesystem;
26}
27
28namespace Service { 32namespace Service {
29 33
30namespace SM { 34namespace SM {
@@ -178,7 +182,8 @@ private:
178}; 182};
179 183
180/// Initialize ServiceManager 184/// Initialize ServiceManager
181void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs); 185void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
186 FileSys::VfsFilesystem& vfs);
182 187
183/// Shutdown ServiceManager 188/// Shutdown ServiceManager
184void Shutdown(); 189void Shutdown();
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index efebd1b24..aa115935d 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -5,6 +5,7 @@
5#include <chrono> 5#include <chrono>
6#include <ctime> 6#include <ctime>
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h"
8#include "core/core_timing.h" 9#include "core/core_timing.h"
9#include "core/core_timing_util.h" 10#include "core/core_timing_util.h"
10#include "core/hle/ipc_helpers.h" 11#include "core/hle/ipc_helpers.h"
@@ -106,8 +107,9 @@ private:
106 void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { 107 void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
107 LOG_DEBUG(Service_Time, "called"); 108 LOG_DEBUG(Service_Time, "called");
108 109
110 const auto& core_timing = Core::System::GetInstance().CoreTiming();
109 const SteadyClockTimePoint steady_clock_time_point{ 111 const SteadyClockTimePoint steady_clock_time_point{
110 Core::Timing::cyclesToMs(Core::Timing::GetTicks()) / 1000}; 112 Core::Timing::cyclesToMs(core_timing.GetTicks()) / 1000};
111 IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; 113 IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
112 rb.Push(RESULT_SUCCESS); 114 rb.Push(RESULT_SUCCESS);
113 rb.PushRaw(steady_clock_time_point); 115 rb.PushRaw(steady_clock_time_point);
@@ -281,8 +283,9 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
281 return; 283 return;
282 } 284 }
283 285
286 const auto& core_timing = Core::System::GetInstance().CoreTiming();
284 const SteadyClockTimePoint steady_clock_time_point{ 287 const SteadyClockTimePoint steady_clock_time_point{
285 Core::Timing::cyclesToMs(Core::Timing::GetTicks()) / 1000, {}}; 288 Core::Timing::cyclesToMs(core_timing.GetTicks()) / 1000, {}};
286 289
287 CalendarTime calendar_time{}; 290 CalendarTime calendar_time{};
288 calendar_time.year = tm->tm_year + 1900; 291 calendar_time.year = tm->tm_year + 1900;