better, less hacky, more OOP-friendly scheduler design

This commit is contained in:
Arisotura
2023-11-02 21:04:09 +01:00
parent 5ccd3916ff
commit 70c6750561
14 changed files with 203 additions and 219 deletions

View File

@ -104,6 +104,14 @@ u64 ARM9Timestamp, ARM9Target;
u64 ARM7Timestamp, ARM7Target;
u64 SysTimestamp;
struct SchedEvent
{
std::map<u32, EventFunc> Funcs;
u64 Timestamp;
u32 FuncID;
u32 Param;
};
SchedEvent SchedList[Event_MAX];
u32 SchedListMask;
@ -184,6 +192,9 @@ void SetGBASlotTimings();
bool Init()
{
RegisterEventFunc(Event_Div, 0, DivDone);
RegisterEventFunc(Event_Sqrt, 0, SqrtDone);
ARM9 = new ARMv5();
ARM7 = new ARMv4();
@ -248,6 +259,9 @@ void DeInit()
DSi::DeInit();
AREngine::DeInit();
UnregisterEventFunc(Event_Div, 0);
UnregisterEventFunc(Event_Sqrt, 0);
}
@ -608,7 +622,14 @@ void Reset()
for (i = 0; i < 8; i++) DMAs[i]->Reset();
memset(DMA9Fill, 0, 4*4);
memset(SchedList, 0, sizeof(SchedList));
for (i = 0; i < Event_MAX; i++)
{
SchedEvent& evt = SchedList[i];
evt.Timestamp = 0;
evt.FuncID = 0;
evt.Param = 0;
}
SchedListMask = 0;
KeyInput = 0x007F03FF;
@ -699,106 +720,6 @@ void Stop(Platform::StopReason reason)
DSi::Stop();
}
bool DoSavestate_Scheduler(Savestate* file)
{
// this is a bit of a hack
// but uh, your local coder realized that the scheduler list contains function pointers
// and that storing those as-is is not a very good idea
// unless you want it to crash and burn
// this is the solution your local coder came up with.
// it's gross but I think it's the best solution for this problem.
// just remember to add here if you add more event callbacks, kay?
// atleast until we come up with something more elegant.
void (*eventfuncs[])(u32) =
{
GPU::StartScanline, GPU::StartHBlank, GPU::FinishFrame,
SPU::Mix,
Wifi::USTimer,
RTC::ClockTimer,
GPU::DisplayFIFO,
NDSCart::ROMPrepareData, NDSCart::ROMEndTransfer,
NDSCart::SPITransferDone,
SPI::TransferDone,
DivDone,
SqrtDone,
DSi_SDHost::FinishRX,
DSi_SDHost::FinishTX,
DSi_NWifi::MSTimer,
DSi_CamModule::IRQ,
DSi_CamModule::TransferScanline,
DSi_DSP::DSPCatchUpU32,
nullptr
};
int len = Event_MAX;
if (file->Saving)
{
for (int i = 0; i < len; i++)
{
SchedEvent* evt = &SchedList[i];
u32 funcid = 0xFFFFFFFF;
if (evt->Func)
{
for (int j = 0; eventfuncs[j]; j++)
{
if (evt->Func == eventfuncs[j])
{
funcid = j;
break;
}
}
if (funcid == 0xFFFFFFFF)
{
Log(LogLevel::Error, "savestate: VERY BAD!!!!! FUNCTION POINTER FOR EVENT %d NOT IN HACKY LIST. CANNOT SAVE. SMACK ARISOTURA.\n", i);
return false;
}
}
file->Var32(&funcid);
file->Var64(&evt->Timestamp);
file->Var32(&evt->Param);
}
}
else
{
for (int i = 0; i < len; i++)
{
SchedEvent* evt = &SchedList[i];
u32 funcid;
file->Var32(&funcid);
if (funcid != 0xFFFFFFFF)
{
for (int j = 0; ; j++)
{
if (!eventfuncs[j])
{
Log(LogLevel::Error, "savestate: VERY BAD!!!!!! EVENT FUNCTION POINTER ID %d IS OUT OF RANGE. HAX?????\n", j);
return false;
}
if (j == funcid) break;
}
evt->Func = eventfuncs[funcid];
}
else
evt->Func = nullptr;
file->Var64(&evt->Timestamp);
file->Var32(&evt->Param);
}
}
return true;
}
bool DoSavestate(Savestate* file)
{
file->Section("NDSG");
@ -871,10 +792,13 @@ bool DoSavestate(Savestate* file)
file->VarArray(DMA9Fill, 4*sizeof(u32));
if (!DoSavestate_Scheduler(file))
for (int i = 0; i < Event_MAX; i++)
{
Platform::Log(Platform::LogLevel::Error, "savestate: failed to %s scheduler state\n", file->Saving ? "save" : "load");
return false;
SchedEvent& evt = SchedList[i];
file->Var64(&evt.Timestamp);
file->Var32(&evt.FuncID);
file->Var32(&evt.Param);
}
file->Var32(&SchedListMask);
file->Var64(&ARM9Timestamp);
@ -1050,10 +974,14 @@ void RunSystem(u64 timestamp)
if (!mask) break;
if (mask & 0x1)
{
if (SchedList[i].Timestamp <= SysTimestamp)
SchedEvent& evt = SchedList[i];
if (evt.Timestamp <= SysTimestamp)
{
SchedListMask &= ~(1<<i);
SchedList[i].Func(SchedList[i].Param);
EventFunc func = evt.Funcs[evt.FuncID];
func(evt.Param);
}
}
@ -1097,7 +1025,9 @@ void RunSystemSleep(u64 timestamp)
{
if (mask & 0x1)
{
if (SchedList[i].Timestamp <= SysTimestamp)
SchedEvent& evt = SchedList[i];
if (evt.Timestamp <= SysTimestamp)
{
SchedListMask &= ~(1<<i);
@ -1105,9 +1035,10 @@ void RunSystemSleep(u64 timestamp)
if (i == Event_SPU)
param = 1;
else
param = SchedList[i].Param;
param = evt.Param;
SchedList[i].Func(param);
EventFunc func = evt.Funcs[evt.FuncID];
func(param);
}
}
}
@ -1298,7 +1229,21 @@ void Reschedule(u64 target)
}
}
void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param)
void RegisterEventFunc(u32 id, u32 funcid, EventFunc func)
{
SchedEvent& evt = SchedList[id];
evt.Funcs[funcid] = func;
}
void UnregisterEventFunc(u32 id, u32 funcid)
{
SchedEvent& evt = SchedList[id];
evt.Funcs.erase(funcid);
}
void ScheduleEvent(u32 id, bool periodic, s32 delay, u32 funcid, u32 param)
{
if (SchedListMask & (1<<id))
{
@ -1306,43 +1251,24 @@ void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 para
return;
}
SchedEvent* evt = &SchedList[id];
SchedEvent& evt = SchedList[id];
if (periodic)
evt->Timestamp += delay;
evt.Timestamp += delay;
else
{
if (CurCPU == 0)
evt->Timestamp = (ARM9Timestamp >> ARM9ClockShift) + delay;
evt.Timestamp = (ARM9Timestamp >> ARM9ClockShift) + delay;
else
evt->Timestamp = ARM7Timestamp + delay;
evt.Timestamp = ARM7Timestamp + delay;
}
evt->Func = func;
evt->Param = param;
evt.FuncID = funcid;
evt.Param = param;
SchedListMask |= (1<<id);
Reschedule(evt->Timestamp);
}
void ScheduleEvent(u32 id, u64 timestamp, void (*func)(u32), u32 param)
{
if (SchedListMask & (1<<id))
{
Log(LogLevel::Debug, "!! EVENT %d ALREADY SCHEDULED\n", id);
return;
}
SchedEvent* evt = &SchedList[id];
evt->Timestamp = timestamp;
evt->Func = func;
evt->Param = param;
SchedListMask |= (1<<id);
Reschedule(evt->Timestamp);
Reschedule(evt.Timestamp);
}
void CancelEvent(u32 id)
@ -2096,7 +2022,7 @@ void StartDiv()
{
NDS::CancelEvent(NDS::Event_Div);
DivCnt |= 0x8000;
NDS::ScheduleEvent(NDS::Event_Div, false, ((DivCnt&0x3)==0) ? 18:34, DivDone, 0);
NDS::ScheduleEvent(NDS::Event_Div, false, ((DivCnt&0x3)==0) ? 18:34, 0, 0);
}
// http://stackoverflow.com/questions/1100090/looking-for-an-efficient-integer-square-root-algorithm-for-arm-thumb2
@ -2144,7 +2070,7 @@ void StartSqrt()
{
NDS::CancelEvent(NDS::Event_Sqrt);
SqrtCnt |= 0x8000;
NDS::ScheduleEvent(NDS::Event_Sqrt, false, 13, SqrtDone, 0);
NDS::ScheduleEvent(NDS::Event_Sqrt, false, 13, 0, 0);
}