#include <atomic>
#include <climits>
#include <cstdio>
#include <cstring>
#include <mutex>
#include <set>
#include <vector>
#include "Common/Profiler/Profiler.h"
#include "Common/Serialize/Serializer.h"
#include "Common/Serialize/SerializeList.h"
#include "Core/CoreTiming.h"
#include "Core/Core.h"
#include "Core/Config.h"
#include "Core/HLE/sceKernelThread.h"
#include "Core/MIPS/MIPS.h"
static const int initialHz = 222000000;
int CPU_HZ = 222000000;
#define INITIAL_SLICE_LENGTH 20000
#define MAX_SLICE_LENGTH 100000000
namespace CoreTiming {
static std::vector<EventType> event_types;
static std::set<int> usedEventTypes;
static std::set<int> restoredEventTypes;
static int nextEventTypeRestoreId = -1;
Event *first;
Event *eventPool = 0;
int slicelength;
alignas(16) s64 globalTimer;
s64 idledCycles;
s64 lastGlobalTimeTicks;
s64 lastGlobalTimeUs;
std::vector<MHzChangeCallback> mhzChangeCallbacks;
void FireMhzChange() {
for (MHzChangeCallback cb : mhzChangeCallbacks) {
cb();
}
}
void SetClockFrequencyHz(int cpuHz) {
if (cpuHz <= 0) {
return;
}
lastGlobalTimeUs = GetGlobalTimeUs();
lastGlobalTimeTicks = GetTicks();
CPU_HZ = cpuHz;
FireMhzChange();
}
int GetClockFrequencyHz() {
return CPU_HZ;
}
u64 GetGlobalTimeUsScaled() {
return GetGlobalTimeUs();
}
u64 GetGlobalTimeUs() {
s64 ticksSinceLast = GetTicks() - lastGlobalTimeTicks;
int freq = GetClockFrequencyHz();
s64 usSinceLast = ticksSinceLast * 1000000 / freq;
if (ticksSinceLast > UINT_MAX) {
lastGlobalTimeUs += usSinceLast;
lastGlobalTimeTicks = GetTicks();
usSinceLast = 0;
}
return lastGlobalTimeUs + usSinceLast;
}
const Event *GetFirstEvent() {
return first;
}
const std::vector<EventType> &GetEventTypes() {
return event_types;
}
Event* GetNewEvent()
{
if(!eventPool)
return new Event;
Event* ev = eventPool;
eventPool = ev->next;
return ev;
}
void FreeEvent(Event* ev)
{
ev->next = eventPool;
eventPool = ev;
}
int RegisterEvent(const char *name, TimedCallback callback) {
for (const auto &ty : event_types) {
if (!strcmp(ty.name, name)) {
_assert_msg_(false, "Event type %s already registered", name);
return -1;
}
}
int id = (int)event_types.size();
event_types.push_back(EventType{ callback, name });
usedEventTypes.insert(id);
return id;
}
void AntiCrashCallback(u64 userdata, int cyclesLate) {
ERROR_LOG(Log::SaveState, "Savestate broken: an unregistered event was called.");
Core_Break(BreakReason::SavestateCrash, 0);
}
void RestoreRegisterEvent(int &event_type, const char *name, TimedCallback callback) {
if (restoredEventTypes.count(event_type) != 0)
event_type = -1;
if (event_type == -1)
event_type = nextEventTypeRestoreId++;
if (event_type >= (int)event_types.size()) {
for (int i = (int)event_types.size() - 1; i >= 0; --i) {
if (usedEventTypes.count(i) == 0) {
event_type = i;
break;
}
}
}
_assert_msg_(event_type >= 0 && event_type < (int)event_types.size(), "Invalid event type %d", event_type);
event_types[event_type] = EventType{ callback, name };
usedEventTypes.insert(event_type);
restoredEventTypes.insert(event_type);
}
void UnregisterAllEvents() {
_dbg_assert_msg_(first == nullptr, "Unregistering events with events pending - this isn't good.");
event_types.clear();
usedEventTypes.clear();
restoredEventTypes.clear();
}
void Init()
{
currentMIPS->downcount = INITIAL_SLICE_LENGTH;
slicelength = INITIAL_SLICE_LENGTH;
globalTimer = 0;
idledCycles = 0;
lastGlobalTimeTicks = 0;
lastGlobalTimeUs = 0;
mhzChangeCallbacks.clear();
CPU_HZ = initialHz;
}
void Shutdown()
{
ClearPendingEvents();
UnregisterAllEvents();
while (eventPool) {
Event *ev = eventPool;
eventPool = ev->next;
delete ev;
}
}
u64 GetTicks()
{
if (currentMIPS) {
return (u64)globalTimer + slicelength - currentMIPS->downcount;
} else {
return false;
}
}
u64 GetIdleTicks()
{
return (u64)idledCycles;
}
void ClearPendingEvents()
{
while (first)
{
Event *e = first->next;
FreeEvent(first);
first = e;
}
}
void AddEventToQueue(Event* ne)
{
Event* prev = NULL;
Event** pNext = &first;
for(;;)
{
Event*& next = *pNext;
if(!next || ne->time < next->time)
{
ne->next = next;
next = ne;
break;
}
prev = next;
pNext = &prev->next;
}
}
void ScheduleEvent(s64 cyclesIntoFuture, int event_type, u64 userdata)
{
Event *ne = GetNewEvent();
ne->userdata = userdata;
ne->type = event_type;
ne->time = GetTicks() + cyclesIntoFuture;
AddEventToQueue(ne);
}
s64 UnscheduleEvent(int event_type, u64 userdata)
{
s64 result = 0;
if (!first)
return result;
while(first)
{
if (first->type == event_type && first->userdata == userdata)
{
result = first->time - GetTicks();
Event *next = first->next;
FreeEvent(first);
first = next;
}
else
{
break;
}
}
if (!first)
return result;
Event *prev = first;
Event *ptr = prev->next;
while (ptr)
{
if (ptr->type == event_type && ptr->userdata == userdata)
{
result = ptr->time - GetTicks();
prev->next = ptr->next;
FreeEvent(ptr);
ptr = prev->next;
}
else
{
prev = ptr;
ptr = ptr->next;
}
}
return result;
}
void RegisterMHzChangeCallback(MHzChangeCallback callback) {
mhzChangeCallbacks.push_back(callback);
}
bool IsScheduled(int event_type)
{
if (!first)
return false;
Event *e = first;
while (e) {
if (e->type == event_type)
return true;
e = e->next;
}
return false;
}
void RemoveEvent(int event_type)
{
if (!first)
return;
while(first)
{
if (first->type == event_type)
{
Event *next = first->next;
FreeEvent(first);
first = next;
}
else
{
break;
}
}
if (!first)
return;
Event *prev = first;
Event *ptr = prev->next;
while (ptr)
{
if (ptr->type == event_type)
{
prev->next = ptr->next;
FreeEvent(ptr);
ptr = prev->next;
}
else
{
prev = ptr;
ptr = ptr->next;
}
}
}
void ProcessEvents() {
while (first) {
if (first->time <= (s64)GetTicks()) {
Event *evt = first;
first = first->next;
if (evt->type >= 0 && evt->type < event_types.size()) {
event_types[evt->type].callback(evt->userdata, (int)(GetTicks() - evt->time));
} else {
_dbg_assert_msg_(false, "Bad event type %d", evt->type);
}
FreeEvent(evt);
} else {
break;
}
}
}
void ForceCheck()
{
int cyclesExecuted = slicelength - currentMIPS->downcount;
globalTimer += cyclesExecuted;
currentMIPS->downcount = -1;
slicelength = -1;
#ifdef _DEBUG
_dbg_assert_msg_( cyclesExecuted >= 0, "Shouldn't have a negative cyclesExecuted");
#endif
}
void Advance() {
PROFILE_THIS_SCOPE("advance");
int cyclesExecuted = slicelength - currentMIPS->downcount;
globalTimer += cyclesExecuted;
currentMIPS->downcount = slicelength;
ProcessEvents();
if (!first) {
if (slicelength < 10000) {
slicelength += 10000;
currentMIPS->downcount += 10000;
}
} else {
int target = (int)(first->time - globalTimer);
if (target > MAX_SLICE_LENGTH)
target = MAX_SLICE_LENGTH;
const int diff = target - slicelength;
slicelength += diff;
currentMIPS->downcount += diff;
}
}
void LogPendingEvents() {
Event *ptr = first;
while (ptr) {
ptr = ptr->next;
}
}
void Idle(int maxIdle) {
int cyclesDown = currentMIPS->downcount;
if (maxIdle != 0 && cyclesDown > maxIdle)
cyclesDown = maxIdle;
if (first && cyclesDown > 0) {
int cyclesExecuted = slicelength - currentMIPS->downcount;
int cyclesNextEvent = (int) (first->time - globalTimer);
if (cyclesNextEvent < cyclesExecuted + cyclesDown)
cyclesDown = cyclesNextEvent - cyclesExecuted;
}
if (cyclesDown < 0)
cyclesDown = 0;
idledCycles += cyclesDown;
currentMIPS->downcount -= cyclesDown;
if (currentMIPS->downcount == 0)
currentMIPS->downcount = -1;
}
std::string GetScheduledEventsSummary() {
Event *ptr = first;
std::string text = "Scheduled events\n";
text.reserve(1000);
while (ptr) {
unsigned int t = ptr->type;
if (t >= event_types.size()) {
_dbg_assert_msg_(false, "Invalid event type %d", t);
ptr = ptr->next;
continue;
}
const char *name = event_types[t].name;
if (!name)
name = "[unknown]";
char temp[512];
snprintf(temp, sizeof(temp), "%s : %i %08x%08x\n", name, (int)ptr->time, (u32)(ptr->userdata >> 32), (u32)(ptr->userdata));
text += temp;
ptr = ptr->next;
}
return text;
}
void Event_DoState(PointerWrap &p, BaseEvent *ev) {
Do(p, ev->time);
Do(p, ev->userdata);
Do(p, ev->type);
usedEventTypes.insert(ev->type);
}
void Event_DoStateOld(PointerWrap &p, BaseEvent *ev) {
Do(p, *ev);
usedEventTypes.insert(ev->type);
}
void DoState(PointerWrap &p) {
auto s = p.Section("CoreTiming", 1, 3);
if (!s)
return;
int n = (int)event_types.size();
int current = n;
Do(p, n);
if (n > current) {
WARN_LOG(Log::SaveState, "Savestate failure: more events than current (can't ever remove an event)");
p.SetError(p.ERROR_FAILURE);
return;
}
for (int i = 0; i < current; ++i) {
event_types[i].callback = AntiCrashCallback;
event_types[i].name = "INVALID EVENT";
}
nextEventTypeRestoreId = n - 1;
usedEventTypes.clear();
restoredEventTypes.clear();
if (s >= 3) {
DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, Event_DoState>(p, first, (Event **)nullptr);
DoIgnoreUnusedLinkedList(p);
} else {
DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, Event_DoStateOld>(p, first, (Event **)nullptr);
DoIgnoreUnusedLinkedList(p);
}
Do(p, CPU_HZ);
Do(p, slicelength);
Do(p, globalTimer);
Do(p, idledCycles);
if (s >= 2) {
Do(p, lastGlobalTimeTicks);
Do(p, lastGlobalTimeUs);
} else {
lastGlobalTimeTicks = 0;
lastGlobalTimeUs = 0;
}
FireMhzChange();
}
}