summaryrefslogtreecommitdiff
path: root/src/core/core_timing.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/core_timing.cpp')
-rw-r--r--src/core/core_timing.cpp709
1 files changed, 315 insertions, 394 deletions
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 321648b37..833199680 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -1,16 +1,14 @@
1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project 1// Copyright (c) 2012- PPSSPP Project / Dolphin Project.
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <vector>
6#include <cstdio>
7#include <atomic> 5#include <atomic>
6#include <cstdio>
8#include <mutex> 7#include <mutex>
8#include <vector>
9 9
10#include "common/chunk_file.h" 10#include "common/chunk_file.h"
11#include "common/msg_handler.h" 11#include "common/log.h"
12#include "common/string_util.h"
13
14#include "core/core.h" 12#include "core/core.h"
15#include "core/core_timing.h" 13#include "core/core_timing.h"
16 14
@@ -22,16 +20,15 @@ int g_clock_rate_arm11 = 268123480;
22 20
23namespace CoreTiming 21namespace CoreTiming
24{ 22{
25
26struct EventType 23struct EventType
27{ 24{
28 EventType() {} 25 EventType() {}
29 26
30 EventType(TimedCallback cb, const char *n) 27 EventType(TimedCallback cb, const char* n)
31 : callback(cb), name(n) {} 28 : callback(cb), name(n) {}
32 29
33 TimedCallback callback; 30 TimedCallback callback;
34 const char *name; 31 const char* name;
35}; 32};
36 33
37std::vector<EventType> event_types; 34std::vector<EventType> event_types;
@@ -41,262 +38,247 @@ struct BaseEvent
41 s64 time; 38 s64 time;
42 u64 userdata; 39 u64 userdata;
43 int type; 40 int type;
44 // Event *next;
45}; 41};
46 42
47typedef LinkedListItem<BaseEvent> Event; 43typedef LinkedListItem<BaseEvent> Event;
48 44
49Event *first; 45Event* first;
50Event *tsFirst; 46Event* ts_first;
51Event *tsLast; 47Event* ts_last;
52 48
53// event pools 49// event pools
54Event *eventPool = 0; 50Event* event_pool = 0;
55Event *eventTsPool = 0; 51Event* event_ts_pool = 0;
56int allocatedTsEvents = 0; 52int allocated_ts_events = 0;
57// Optimization to skip MoveEvents when possible. 53// Optimization to skip MoveEvents when possible.
58std::atomic<u32> hasTsEvents; 54std::atomic<bool> has_ts_events(false);
59 55
60// Downcount has been moved to currentMIPS, to save a couple of clocks in every ARM JIT block 56int g_slice_length;
61// as we can already reach that structure through a register.
62int slicelength;
63 57
64MEMORY_ALIGNED16(s64) globalTimer; 58s64 global_timer;
65s64 idledCycles; 59s64 idled_cycles;
60s64 last_global_time_ticks;
61s64 last_global_time_us;
66 62
67static std::recursive_mutex externalEventSection; 63static std::recursive_mutex external_event_section;
68 64
69// Warning: not included in save state. 65// Warning: not included in save state.
70void(*advanceCallback)(int cyclesExecuted) = nullptr; 66using AdvanceCallback = void(int cycles_executed);
67AdvanceCallback* advance_callback = nullptr;
68std::vector<MHzChangeCallback> mhz_change_callbacks;
71 69
72void SetClockFrequencyMHz(int cpuMhz) 70void FireMhzChange() {
73{ 71 for (auto callback : mhz_change_callbacks)
74 g_clock_rate_arm11 = cpuMhz * 1000000; 72 callback();
73}
74
75void SetClockFrequencyMHz(int cpu_mhz) {
76 // When the mhz changes, we keep track of what "time" it was before hand.
77 // This way, time always moves forward, even if mhz is changed.
78 last_global_time_us = GetGlobalTimeUs();
79 last_global_time_ticks = GetTicks();
80
81 g_clock_rate_arm11 = cpu_mhz * 1000000;
75 // TODO: Rescale times of scheduled events? 82 // TODO: Rescale times of scheduled events?
83
84 FireMhzChange();
76} 85}
77 86
78int GetClockFrequencyMHz() 87int GetClockFrequencyMHz() {
79{
80 return g_clock_rate_arm11 / 1000000; 88 return g_clock_rate_arm11 / 1000000;
81} 89}
82 90
91u64 GetGlobalTimeUs() {
92 s64 ticks_since_last = GetTicks() - last_global_time_ticks;
93 int freq = GetClockFrequencyMHz();
94 s64 us_since_last = ticks_since_last / freq;
95 return last_global_time_us + us_since_last;
96}
83 97
84Event* GetNewEvent() 98Event* GetNewEvent() {
85{ 99 if (!event_pool)
86 if (!eventPool)
87 return new Event; 100 return new Event;
88 101
89 Event* ev = eventPool; 102 Event* event = event_pool;
90 eventPool = ev->next; 103 event_pool = event->next;
91 return ev; 104 return event;
92} 105}
93 106
94Event* GetNewTsEvent() 107Event* GetNewTsEvent() {
95{ 108 allocated_ts_events++;
96 allocatedTsEvents++;
97 109
98 if (!eventTsPool) 110 if (!event_ts_pool)
99 return new Event; 111 return new Event;
100 112
101 Event* ev = eventTsPool; 113 Event* event = event_ts_pool;
102 eventTsPool = ev->next; 114 event_ts_pool = event->next;
103 return ev; 115 return event;
104} 116}
105 117
106void FreeEvent(Event* ev) 118void FreeEvent(Event* event) {
107{ 119 event->next = event_pool;
108 ev->next = eventPool; 120 event_pool = event;
109 eventPool = ev;
110} 121}
111 122
112void FreeTsEvent(Event* ev) 123void FreeTsEvent(Event* event) {
113{ 124 event->next = event_ts_pool;
114 ev->next = eventTsPool; 125 event_ts_pool = event;
115 eventTsPool = ev; 126 allocated_ts_events--;
116 allocatedTsEvents--;
117} 127}
118 128
119int RegisterEvent(const char *name, TimedCallback callback) 129int RegisterEvent(const char* name, TimedCallback callback) {
120{
121 event_types.push_back(EventType(callback, name)); 130 event_types.push_back(EventType(callback, name));
122 return (int)event_types.size() - 1; 131 return (int)event_types.size() - 1;
123} 132}
124 133
125void AntiCrashCallback(u64 userdata, int cyclesLate) 134void AntiCrashCallback(u64 userdata, int cycles_late) {
126{ 135 LOG_CRITICAL(Core_Timing, "Savestate broken: an unregistered event was called.");
127 LOG_CRITICAL(Core, "Savestate broken: an unregistered event was called.");
128 Core::Halt("invalid timing events"); 136 Core::Halt("invalid timing events");
129} 137}
130 138
131void RestoreRegisterEvent(int event_type, const char *name, TimedCallback callback) 139void RestoreRegisterEvent(int event_type, const char* name, TimedCallback callback) {
132{
133 if (event_type >= (int)event_types.size()) 140 if (event_type >= (int)event_types.size())
134 event_types.resize(event_type + 1, EventType(AntiCrashCallback, "INVALID EVENT")); 141 event_types.resize(event_type + 1, EventType(AntiCrashCallback, "INVALID EVENT"));
135 142
136 event_types[event_type] = EventType(callback, name); 143 event_types[event_type] = EventType(callback, name);
137} 144}
138 145
139void UnregisterAllEvents() 146void UnregisterAllEvents() {
140{
141 if (first) 147 if (first)
142 PanicAlert("Cannot unregister events with events pending"); 148 PanicAlert("Cannot unregister events with events pending");
143 event_types.clear(); 149 event_types.clear();
144} 150}
145 151
146void Init() 152void Init() {
147{ 153 Core::g_app_core->down_count = INITIAL_SLICE_LENGTH;
148 //currentMIPS->downcount = INITIAL_SLICE_LENGTH; 154 g_slice_length = INITIAL_SLICE_LENGTH;
149 //slicelength = INITIAL_SLICE_LENGTH; 155 global_timer = 0;
150 globalTimer = 0; 156 idled_cycles = 0;
151 idledCycles = 0; 157 last_global_time_ticks = 0;
152 hasTsEvents = 0; 158 last_global_time_us = 0;
159 has_ts_events = 0;
160 mhz_change_callbacks.clear();
153} 161}
154 162
155void Shutdown() 163void Shutdown() {
156{
157 MoveEvents(); 164 MoveEvents();
158 ClearPendingEvents(); 165 ClearPendingEvents();
159 UnregisterAllEvents(); 166 UnregisterAllEvents();
160 167
161 while (eventPool) 168 while (event_pool) {
162 { 169 Event* event = event_pool;
163 Event *ev = eventPool; 170 event_pool = event->next;
164 eventPool = ev->next; 171 delete event;
165 delete ev;
166 } 172 }
167 173
168 std::lock_guard<std::recursive_mutex> lk(externalEventSection); 174 std::lock_guard<std::recursive_mutex> lock(external_event_section);
169 while (eventTsPool) 175 while (event_ts_pool) {
170 { 176 Event* event = event_ts_pool;
171 Event *ev = eventTsPool; 177 event_ts_pool = event->next;
172 eventTsPool = ev->next; 178 delete event;
173 delete ev;
174 } 179 }
175} 180}
176 181
177u64 GetTicks() 182u64 GetTicks() {
178{ 183 return (u64)global_timer + g_slice_length - Core::g_app_core->down_count;
179 LOG_ERROR(Core, "Unimplemented function!");
180 return 0;
181 //return (u64)globalTimer + slicelength - currentMIPS->downcount;
182} 184}
183 185
184u64 GetIdleTicks() 186u64 GetIdleTicks() {
185{ 187 return (u64)idled_cycles;
186 return (u64)idledCycles;
187} 188}
188 189
189 190
190// This is to be called when outside threads, such as the graphics thread, wants to 191// This is to be called when outside threads, such as the graphics thread, wants to
191// schedule things to be executed on the main thread. 192// schedule things to be executed on the main thread.
192void ScheduleEvent_Threadsafe(s64 cyclesIntoFuture, int event_type, u64 userdata) 193void ScheduleEvent_Threadsafe(s64 cycles_into_future, int event_type, u64 userdata) {
193{ 194 std::lock_guard<std::recursive_mutex> lock(external_event_section);
194 std::lock_guard<std::recursive_mutex> lk(externalEventSection); 195 Event* new_event = GetNewTsEvent();
195 Event *ne = GetNewTsEvent(); 196 new_event->time = GetTicks() + cycles_into_future;
196 ne->time = GetTicks() + cyclesIntoFuture; 197 new_event->type = event_type;
197 ne->type = event_type; 198 new_event->next = 0;
198 ne->next = 0; 199 new_event->userdata = userdata;
199 ne->userdata = userdata; 200 if (!ts_first)
200 if (!tsFirst) 201 ts_first = new_event;
201 tsFirst = ne; 202 if (ts_last)
202 if (tsLast) 203 ts_last->next = new_event;
203 tsLast->next = ne; 204 ts_last = new_event;
204 tsLast = ne; 205
205 206 has_ts_events = true;
206 hasTsEvents.store(1, std::memory_order_release);
207} 207}
208 208
209// Same as ScheduleEvent_Threadsafe(0, ...) EXCEPT if we are already on the CPU thread 209// Same as ScheduleEvent_Threadsafe(0, ...) EXCEPT if we are already on the CPU thread
210// in which case the event will get handled immediately, before returning. 210// in which case the event will get handled immediately, before returning.
211void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata) 211void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata) {
212{
213 if (false) //Core::IsCPUThread()) 212 if (false) //Core::IsCPUThread())
214 { 213 {
215 std::lock_guard<std::recursive_mutex> lk(externalEventSection); 214 std::lock_guard<std::recursive_mutex> lock(external_event_section);
216 event_types[event_type].callback(userdata, 0); 215 event_types[event_type].callback(userdata, 0);
217 } 216 }
218 else 217 else
219 ScheduleEvent_Threadsafe(0, event_type, userdata); 218 ScheduleEvent_Threadsafe(0, event_type, userdata);
220} 219}
221 220
222void ClearPendingEvents() 221void ClearPendingEvents() {
223{ 222 while (first) {
224 while (first) 223 Event* event = first->next;
225 {
226 Event *e = first->next;
227 FreeEvent(first); 224 FreeEvent(first);
228 first = e; 225 first = event;
229 } 226 }
230} 227}
231 228
232void AddEventToQueue(Event* ne) 229void AddEventToQueue(Event* new_event) {
233{ 230 Event* prev_event = nullptr;
234 Event* prev = nullptr; 231 Event** next_event = &first;
235 Event** pNext = &first; 232 for (;;) {
236 for (;;) 233 Event*& next = *next_event;
237 { 234 if (!next || new_event->time < next->time) {
238 Event*& next = *pNext; 235 new_event->next = next;
239 if (!next || ne->time < next->time) 236 next = new_event;
240 {
241 ne->next = next;
242 next = ne;
243 break; 237 break;
244 } 238 }
245 prev = next; 239 prev_event = next;
246 pNext = &prev->next; 240 next_event = &prev_event->next;
247 } 241 }
248} 242}
249 243
250// This must be run ONLY from within the cpu thread 244void ScheduleEvent(s64 cycles_into_future, int event_type, u64 userdata) {
251// cyclesIntoFuture may be VERY inaccurate if called from anything else 245 Event* new_event = GetNewEvent();
252// than Advance 246 new_event->userdata = userdata;
253void ScheduleEvent(s64 cyclesIntoFuture, int event_type, u64 userdata) 247 new_event->type = event_type;
254{ 248 new_event->time = GetTicks() + cycles_into_future;
255 Event *ne = GetNewEvent(); 249 AddEventToQueue(new_event);
256 ne->userdata = userdata;
257 ne->type = event_type;
258 ne->time = GetTicks() + cyclesIntoFuture;
259 AddEventToQueue(ne);
260} 250}
261 251
262// Returns cycles left in timer. 252s64 UnscheduleEvent(int event_type, u64 userdata) {
263s64 UnscheduleEvent(int event_type, u64 userdata)
264{
265 s64 result = 0; 253 s64 result = 0;
266 if (!first) 254 if (!first)
267 return result; 255 return result;
268 while (first) 256 while (first) {
269 { 257 if (first->type == event_type && first->userdata == userdata) {
270 if (first->type == event_type && first->userdata == userdata) 258 result = first->time - GetTicks();
271 {
272 result = first->time - globalTimer;
273 259
274 Event *next = first->next; 260 Event* next = first->next;
275 FreeEvent(first); 261 FreeEvent(first);
276 first = next; 262 first = next;
277 } 263 } else {
278 else
279 {
280 break; 264 break;
281 } 265 }
282 } 266 }
283 if (!first) 267 if (!first)
284 return result; 268 return result;
285 Event *prev = first;
286 Event *ptr = prev->next;
287 while (ptr)
288 {
289 if (ptr->type == event_type && ptr->userdata == userdata)
290 {
291 result = ptr->time - globalTimer;
292 269
293 prev->next = ptr->next; 270 Event* prev_event = first;
271 Event* ptr = prev_event->next;
272
273 while (ptr) {
274 if (ptr->type == event_type && ptr->userdata == userdata) {
275 result = ptr->time - GetTicks();
276
277 prev_event->next = ptr->next;
294 FreeEvent(ptr); 278 FreeEvent(ptr);
295 ptr = prev->next; 279 ptr = prev_event->next;
296 } 280 } else {
297 else 281 prev_event = ptr;
298 {
299 prev = ptr;
300 ptr = ptr->next; 282 ptr = ptr->next;
301 } 283 }
302 } 284 }
@@ -304,51 +286,44 @@ s64 UnscheduleEvent(int event_type, u64 userdata)
304 return result; 286 return result;
305} 287}
306 288
307s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata) 289s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata) {
308{
309 s64 result = 0; 290 s64 result = 0;
310 std::lock_guard<std::recursive_mutex> lk(externalEventSection); 291 std::lock_guard<std::recursive_mutex> lock(external_event_section);
311 if (!tsFirst) 292 if (!ts_first)
312 return result; 293 return result;
313 while (tsFirst)
314 {
315 if (tsFirst->type == event_type && tsFirst->userdata == userdata)
316 {
317 result = tsFirst->time - globalTimer;
318 294
319 Event *next = tsFirst->next; 295 while (ts_first) {
320 FreeTsEvent(tsFirst); 296 if (ts_first->type == event_type && ts_first->userdata == userdata) {
321 tsFirst = next; 297 result = ts_first->time - GetTicks();
322 } 298
323 else 299 Event* next = ts_first->next;
324 { 300 FreeTsEvent(ts_first);
301 ts_first = next;
302 } else {
325 break; 303 break;
326 } 304 }
327 } 305 }
328 if (!tsFirst) 306
307 if (!ts_first)
329 { 308 {
330 tsLast = nullptr; 309 ts_last = nullptr;
331 return result; 310 return result;
332 } 311 }
333 312
334 Event *prev = tsFirst; 313 Event* prev_event = ts_first;
335 Event *ptr = prev->next; 314 Event* next = prev_event->next;
336 while (ptr) 315 while (next) {
337 { 316 if (next->type == event_type && next->userdata == userdata) {
338 if (ptr->type == event_type && ptr->userdata == userdata) 317 result = next->time - GetTicks();
339 { 318
340 result = ptr->time - globalTimer; 319 prev_event->next = next->next;
341 320 if (next == ts_last)
342 prev->next = ptr->next; 321 ts_last = prev_event;
343 if (ptr == tsLast) 322 FreeTsEvent(next);
344 tsLast = prev; 323 next = prev_event->next;
345 FreeTsEvent(ptr); 324 } else {
346 ptr = prev->next; 325 prev_event = next;
347 } 326 next = next->next;
348 else
349 {
350 prev = ptr;
351 ptr = ptr->next;
352 } 327 }
353 } 328 }
354 329
@@ -356,271 +331,217 @@ s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata)
356} 331}
357 332
358// Warning: not included in save state. 333// Warning: not included in save state.
359void RegisterAdvanceCallback(void(*callback)(int cyclesExecuted)) 334void RegisterAdvanceCallback(AdvanceCallback* callback) {
360{ 335 advance_callback = callback;
361 advanceCallback = callback;
362} 336}
363 337
364bool IsScheduled(int event_type) 338void RegisterMHzChangeCallback(MHzChangeCallback callback) {
365{ 339 mhz_change_callbacks.push_back(callback);
340}
341
342bool IsScheduled(int event_type) {
366 if (!first) 343 if (!first)
367 return false; 344 return false;
368 Event *e = first; 345 Event* event = first;
369 while (e) { 346 while (event) {
370 if (e->type == event_type) 347 if (event->type == event_type)
371 return true; 348 return true;
372 e = e->next; 349 event = event->next;
373 } 350 }
374 return false; 351 return false;
375} 352}
376 353
377void RemoveEvent(int event_type) 354void RemoveEvent(int event_type) {
378{
379 if (!first) 355 if (!first)
380 return; 356 return;
381 while (first) 357 while (first) {
382 { 358 if (first->type == event_type) {
383 if (first->type == event_type)
384 {
385 Event *next = first->next; 359 Event *next = first->next;
386 FreeEvent(first); 360 FreeEvent(first);
387 first = next; 361 first = next;
388 } 362 } else {
389 else
390 {
391 break; 363 break;
392 } 364 }
393 } 365 }
394 if (!first) 366 if (!first)
395 return; 367 return;
396 Event *prev = first; 368 Event* prev = first;
397 Event *ptr = prev->next; 369 Event* next = prev->next;
398 while (ptr) 370 while (next) {
399 { 371 if (next->type == event_type) {
400 if (ptr->type == event_type) 372 prev->next = next->next;
401 { 373 FreeEvent(next);
402 prev->next = ptr->next; 374 next = prev->next;
403 FreeEvent(ptr); 375 } else {
404 ptr = prev->next; 376 prev = next;
405 } 377 next = next->next;
406 else
407 {
408 prev = ptr;
409 ptr = ptr->next;
410 } 378 }
411 } 379 }
412} 380}
413 381
414void RemoveThreadsafeEvent(int event_type) 382void RemoveThreadsafeEvent(int event_type) {
415{ 383 std::lock_guard<std::recursive_mutex> lock(external_event_section);
416 std::lock_guard<std::recursive_mutex> lk(externalEventSection); 384 if (!ts_first)
417 if (!tsFirst)
418 {
419 return; 385 return;
420 } 386
421 while (tsFirst) 387 while (ts_first) {
422 { 388 if (ts_first->type == event_type) {
423 if (tsFirst->type == event_type) 389 Event* next = ts_first->next;
424 { 390 FreeTsEvent(ts_first);
425 Event *next = tsFirst->next; 391 ts_first = next;
426 FreeTsEvent(tsFirst); 392 } else {
427 tsFirst = next;
428 }
429 else
430 {
431 break; 393 break;
432 } 394 }
433 } 395 }
434 if (!tsFirst) 396
435 { 397 if (!ts_first) {
436 tsLast = nullptr; 398 ts_last = nullptr;
437 return; 399 return;
438 } 400 }
439 Event *prev = tsFirst; 401
440 Event *ptr = prev->next; 402 Event* prev = ts_first;
441 while (ptr) 403 Event* next = prev->next;
442 { 404 while (next) {
443 if (ptr->type == event_type) 405 if (next->type == event_type) {
444 { 406 prev->next = next->next;
445 prev->next = ptr->next; 407 if (next == ts_last)
446 if (ptr == tsLast) 408 ts_last = prev;
447 tsLast = prev; 409 FreeTsEvent(next);
448 FreeTsEvent(ptr); 410 next = prev->next;
449 ptr = prev->next; 411 } else {
450 } 412 prev = next;
451 else 413 next = next->next;
452 {
453 prev = ptr;
454 ptr = ptr->next;
455 } 414 }
456 } 415 }
457} 416}
458 417
459void RemoveAllEvents(int event_type) 418void RemoveAllEvents(int event_type) {
460{
461 RemoveThreadsafeEvent(event_type); 419 RemoveThreadsafeEvent(event_type);
462 RemoveEvent(event_type); 420 RemoveEvent(event_type);
463} 421}
464 422
465//This raise only the events required while the fifo is processing data 423// This raise only the events required while the fifo is processing data
466void ProcessFifoWaitEvents() 424void ProcessFifoWaitEvents() {
467{ 425 while (first) {
468 while (first) 426 if (first->time <= (s64)GetTicks()) {
469 {
470 if (first->time <= globalTimer)
471 {
472 //LOG(TIMER, "[Scheduler] %s (%lld, %lld) ",
473 // first->name ? first->name : "?", (u64)globalTimer, (u64)first->time);
474 Event* evt = first; 427 Event* evt = first;
475 first = first->next; 428 first = first->next;
476 event_types[evt->type].callback(evt->userdata, (int)(globalTimer - evt->time)); 429 event_types[evt->type].callback(evt->userdata, (int)(GetTicks() - evt->time));
477 FreeEvent(evt); 430 FreeEvent(evt);
478 } 431 } else {
479 else
480 {
481 break; 432 break;
482 } 433 }
483 } 434 }
484} 435}
485 436
486void MoveEvents() 437void MoveEvents() {
487{ 438 has_ts_events = false;
488 hasTsEvents.store(0, std::memory_order_release);
489 439
490 std::lock_guard<std::recursive_mutex> lk(externalEventSection); 440 std::lock_guard<std::recursive_mutex> lock(external_event_section);
491 // Move events from async queue into main queue 441 // Move events from async queue into main queue
492 while (tsFirst) 442 while (ts_first) {
493 { 443 Event* next = ts_first->next;
494 Event *next = tsFirst->next; 444 AddEventToQueue(ts_first);
495 AddEventToQueue(tsFirst); 445 ts_first = next;
496 tsFirst = next;
497 } 446 }
498 tsLast = nullptr; 447 ts_last = nullptr;
499 448
500 // Move free events to threadsafe pool 449 // Move free events to threadsafe pool
501 while (allocatedTsEvents > 0 && eventPool) 450 while (allocated_ts_events > 0 && event_pool) {
502 { 451 Event* event = event_pool;
503 Event *ev = eventPool; 452 event_pool = event->next;
504 eventPool = ev->next; 453 event->next = event_ts_pool;
505 ev->next = eventTsPool; 454 event_ts_pool = event;
506 eventTsPool = ev; 455 allocated_ts_events--;
507 allocatedTsEvents--;
508 } 456 }
509} 457}
510 458
511void Advance() 459void ForceCheck() {
512{ 460 int cycles_executed = g_slice_length - Core::g_app_core->down_count;
513 LOG_ERROR(Core, "Unimplemented function!"); 461 global_timer += cycles_executed;
514 //int cyclesExecuted = slicelength - currentMIPS->downcount; 462 // This will cause us to check for new events immediately.
515 //globalTimer += cyclesExecuted; 463 Core::g_app_core->down_count = 0;
516 //currentMIPS->downcount = slicelength; 464 // But let's not eat a bunch more time in Advance() because of this.
517 465 g_slice_length = 0;
518 //if (Common::AtomicLoadAcquire(hasTsEvents))
519 // MoveEvents();
520 //ProcessFifoWaitEvents();
521
522 //if (!first)
523 //{
524 // // WARN_LOG(TIMER, "WARNING - no events in queue. Setting currentMIPS->downcount to 10000");
525 // currentMIPS->downcount += 10000;
526 //}
527 //else
528 //{
529 // slicelength = (int)(first->time - globalTimer);
530 // if (slicelength > MAX_SLICE_LENGTH)
531 // slicelength = MAX_SLICE_LENGTH;
532 // currentMIPS->downcount = slicelength;
533 //}
534 //if (advanceCallback)
535 // advanceCallback(cyclesExecuted);
536}
537
538void LogPendingEvents()
539{
540 Event *ptr = first;
541 while (ptr)
542 {
543 //INFO_LOG(TIMER, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer, ptr->time, ptr->type);
544 ptr = ptr->next;
545 }
546} 466}
547 467
548void Idle(int maxIdle) 468void Advance() {
549{ 469 int cycles_executed = g_slice_length - Core::g_app_core->down_count;
550 LOG_ERROR(Core, "Unimplemented function!"); 470 global_timer += cycles_executed;
551 //int cyclesDown = currentMIPS->downcount; 471 Core::g_app_core->down_count = g_slice_length;
552 //if (maxIdle != 0 && cyclesDown > maxIdle)
553 // cyclesDown = maxIdle;
554
555 //if (first && cyclesDown > 0)
556 //{
557 // int cyclesExecuted = slicelength - currentMIPS->downcount;
558 // int cyclesNextEvent = (int) (first->time - globalTimer);
559
560 // if (cyclesNextEvent < cyclesExecuted + cyclesDown)
561 // {
562 // cyclesDown = cyclesNextEvent - cyclesExecuted;
563 // // Now, now... no time machines, please.
564 // if (cyclesDown < 0)
565 // cyclesDown = 0;
566 // }
567 //}
568
569 //INFO_LOG(TIME, "Idle for %i cycles! (%f ms)", cyclesDown, cyclesDown / (float)(g_clock_rate_arm11 * 0.001f));
570
571 //idledCycles += cyclesDown;
572 //currentMIPS->downcount -= cyclesDown;
573 //if (currentMIPS->downcount == 0)
574 // currentMIPS->downcount = -1;
575}
576
577std::string GetScheduledEventsSummary()
578{
579 Event *ptr = first;
580 std::string text = "Scheduled events\n";
581 text.reserve(1000);
582 while (ptr)
583 {
584 unsigned int t = ptr->type;
585 if (t >= event_types.size())
586 PanicAlert("Invalid event type"); // %i", t);
587 const char *name = event_types[ptr->type].name;
588 if (!name)
589 name = "[unknown]";
590 472
591 text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)ptr->time, 473 if (has_ts_events)
592 (u32)(ptr->userdata >> 32), (u32)(ptr->userdata)); 474 MoveEvents();
475 ProcessFifoWaitEvents();
593 476
594 ptr = ptr->next; 477 if (!first) {
478 if (g_slice_length < 10000) {
479 g_slice_length += 10000;
480 Core::g_app_core->down_count += g_slice_length;
481 }
482 } else {
483 // Note that events can eat cycles as well.
484 int target = (int)(first->time - global_timer);
485 if (target > MAX_SLICE_LENGTH)
486 target = MAX_SLICE_LENGTH;
487
488 const int diff = target - g_slice_length;
489 g_slice_length += diff;
490 Core::g_app_core->down_count += diff;
595 } 491 }
596 return text; 492 if (advance_callback)
493 advance_callback(cycles_executed);
597} 494}
598 495
599void Event_DoState(PointerWrap &p, BaseEvent *ev) 496void LogPendingEvents() {
600{ 497 Event* event = first;
601 p.Do(*ev); 498 while (event) {
499 //LOG_TRACE(Core_Timing, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer, next->time, next->type);
500 event = event->next;
501 }
602} 502}
603 503
604void DoState(PointerWrap &p) 504void Idle(int max_idle) {
605{ 505 int cycles_down = Core::g_app_core->down_count;
606 std::lock_guard<std::recursive_mutex> lk(externalEventSection); 506 if (max_idle != 0 && cycles_down > max_idle)
507 cycles_down = max_idle;
607 508
608 auto s = p.Section("CoreTiming", 1); 509 if (first && cycles_down > 0) {
609 if (!s) 510 int cycles_executed = g_slice_length - Core::g_app_core->down_count;
610 return; 511 int cycles_next_event = (int)(first->time - global_timer);
611 512
612 int n = (int)event_types.size(); 513 if (cycles_next_event < cycles_executed + cycles_down) {
613 p.Do(n); 514 cycles_down = cycles_next_event - cycles_executed;
614 // These (should) be filled in later by the modules. 515 // Now, now... no time machines, please.
615 event_types.resize(n, EventType(AntiCrashCallback, "INVALID EVENT")); 516 if (cycles_down < 0)
517 cycles_down = 0;
518 }
519 }
616 520
617 p.DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, Event_DoState>(first, (Event **)nullptr); 521 LOG_TRACE(Core_Timing, "Idle for %i cycles! (%f ms)", cycles_down, cycles_down / (float)(g_clock_rate_arm11 * 0.001f));
618 p.DoLinkedList<BaseEvent, GetNewTsEvent, FreeTsEvent, Event_DoState>(tsFirst, &tsLast);
619 522
620 p.Do(g_clock_rate_arm11); 523 idled_cycles += cycles_down;
621 p.Do(slicelength); 524 Core::g_app_core->down_count -= cycles_down;
622 p.Do(globalTimer); 525 if (Core::g_app_core->down_count == 0)
623 p.Do(idledCycles); 526 Core::g_app_core->down_count = -1;
527}
528
529std::string GetScheduledEventsSummary() {
530 Event* event = first;
531 std::string text = "Scheduled events\n";
532 text.reserve(1000);
533 while (event) {
534 unsigned int t = event->type;
535 if (t >= event_types.size())
536 PanicAlert("Invalid event type"); // %i", t);
537 const char* name = event_types[event->type].name;
538 if (!name)
539 name = "[unknown]";
540 text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time,
541 (u32)(event->userdata >> 32), (u32)(event->userdata));
542 event = event->next;
543 }
544 return text;
624} 545}
625 546
626} // namespace 547} // namespace