mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-23 06:10:03 -06:00
better, less hacky, more OOP-friendly scheduler design
This commit is contained in:
202
src/NDS.cpp
202
src/NDS.cpp
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user