mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-23 06:10:03 -06:00
* somewhat proper event scheduler
* support for timers * fixes, additions, shit
This commit is contained in:
342
NDS.cpp
342
NDS.cpp
@ -9,10 +9,17 @@
|
||||
namespace NDS
|
||||
{
|
||||
|
||||
SchedEvent SchedBuffer[SCHED_BUF_LEN];
|
||||
SchedEvent* SchedQueue;
|
||||
|
||||
bool NeedReschedule;
|
||||
|
||||
ARM* ARM9;
|
||||
ARM* ARM7;
|
||||
|
||||
s32 ARM9Cycles, ARM7Cycles;
|
||||
s32 CompensatedCycles;
|
||||
s32 SchedCycles;
|
||||
|
||||
u8 ARM9BIOS[0x1000];
|
||||
u8 ARM7BIOS[0x4000];
|
||||
@ -37,8 +44,12 @@ u32 ARM9DTCMBase, ARM9DTCMSize;
|
||||
u32 IME[2];
|
||||
u32 IE[2], IF[2];
|
||||
|
||||
Timer Timers[8];
|
||||
|
||||
u16 IPCSync9, IPCSync7;
|
||||
|
||||
u16 _soundbias; // temp
|
||||
|
||||
bool Running;
|
||||
|
||||
|
||||
@ -103,10 +114,18 @@ void Reset()
|
||||
ARM7->Reset();
|
||||
CP15::Reset();
|
||||
|
||||
memset(Timers, 0, 8*sizeof(Timer));
|
||||
|
||||
SPI::Reset();
|
||||
|
||||
memset(SchedBuffer, 0, sizeof(SchedEvent)*SCHED_BUF_LEN);
|
||||
SchedQueue = NULL;
|
||||
|
||||
ARM9Cycles = 0;
|
||||
ARM7Cycles = 0;
|
||||
SchedCycles = 0;
|
||||
|
||||
_soundbias = 0;
|
||||
|
||||
Running = true; // hax
|
||||
}
|
||||
@ -116,17 +135,144 @@ void RunFrame()
|
||||
{
|
||||
s32 framecycles = 560190<<1;
|
||||
|
||||
// very gross and temp. loop
|
||||
const s32 maxcycles = 16;
|
||||
|
||||
while (Running && framecycles>0)
|
||||
{
|
||||
ARM9Cycles = ARM9->Execute(32 + ARM9Cycles);
|
||||
ARM7Cycles = ARM7->Execute(16 + ARM7Cycles);
|
||||
//ARM9Cycles = ARM9->Execute(32 + ARM9Cycles);
|
||||
//ARM7Cycles = ARM7->Execute(16 + ARM7Cycles);
|
||||
|
||||
framecycles -= 32;
|
||||
//framecycles -= 32;
|
||||
s32 cyclestorun = maxcycles;
|
||||
// TODO: scheduler integration here
|
||||
|
||||
CompensatedCycles = ARM9Cycles;
|
||||
s32 c9 = ARM9->Execute(cyclestorun - ARM9Cycles);
|
||||
ARM9Cycles = c9 - cyclestorun;
|
||||
c9 -= CompensatedCycles;
|
||||
|
||||
s32 c7 = ARM7->Execute((c9 - ARM7Cycles) >> 1) << 1;
|
||||
ARM7Cycles = c7 - c9;
|
||||
|
||||
RunEvents(c9);
|
||||
framecycles -= cyclestorun;
|
||||
}
|
||||
}
|
||||
|
||||
SchedEvent* ScheduleEvent(s32 Delay, void (*Func)(u32), u32 Param)
|
||||
{
|
||||
// find a free entry
|
||||
u32 entry = -1;
|
||||
for (int i = 0; i < SCHED_BUF_LEN; i++)
|
||||
{
|
||||
if (SchedBuffer[i].Func == NULL)
|
||||
{
|
||||
entry = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry == -1)
|
||||
{
|
||||
printf("!! SCHEDULER BUFFER FULL\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SchedEvent* evt = &SchedBuffer[entry];
|
||||
evt->Func = Func;
|
||||
evt->Param = Param;
|
||||
|
||||
SchedEvent* cur = SchedQueue;
|
||||
SchedEvent* prev = NULL;
|
||||
for (;;)
|
||||
{
|
||||
if (cur == NULL) break;
|
||||
if (cur->Delay > Delay) break;
|
||||
|
||||
Delay -= cur->Delay;
|
||||
prev = cur;
|
||||
cur = cur->NextEvent;
|
||||
}
|
||||
|
||||
// so, we found it. we insert our event before 'cur'.
|
||||
evt->Delay = Delay;
|
||||
|
||||
if (cur == NULL)
|
||||
{
|
||||
if (prev == NULL)
|
||||
{
|
||||
// list empty
|
||||
SchedQueue = evt;
|
||||
evt->PrevEvent = NULL;
|
||||
evt->NextEvent = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// inserting at the end of the list
|
||||
evt->PrevEvent = prev;
|
||||
evt->NextEvent = NULL;
|
||||
prev->NextEvent = evt;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
evt->NextEvent = cur;
|
||||
evt->PrevEvent = cur->PrevEvent;
|
||||
|
||||
if (evt->PrevEvent)
|
||||
evt->PrevEvent->NextEvent = evt;
|
||||
|
||||
cur->PrevEvent = evt;
|
||||
cur->Delay -= evt->Delay;
|
||||
}
|
||||
|
||||
return evt;
|
||||
}
|
||||
|
||||
void CancelEvent(SchedEvent* event)
|
||||
{
|
||||
event->Func = NULL;
|
||||
|
||||
// unlink
|
||||
|
||||
if (event->PrevEvent)
|
||||
event->PrevEvent->NextEvent = event->NextEvent;
|
||||
else
|
||||
SchedQueue = event->NextEvent;
|
||||
|
||||
if (event->NextEvent)
|
||||
event->NextEvent->PrevEvent = event->PrevEvent;
|
||||
}
|
||||
|
||||
void RunEvents(s32 cycles)
|
||||
{
|
||||
SchedCycles += cycles;
|
||||
|
||||
SchedEvent* evt = SchedQueue;
|
||||
while (evt && evt->Delay <= SchedCycles)
|
||||
{
|
||||
evt->Func(evt->Param);
|
||||
evt->Func = NULL;
|
||||
SchedCycles -= evt->Delay;
|
||||
|
||||
evt = evt->NextEvent;
|
||||
}
|
||||
|
||||
SchedQueue = evt;
|
||||
if (evt) evt->PrevEvent = NULL;
|
||||
}
|
||||
|
||||
void CompensateARM7()
|
||||
{
|
||||
s32 c9 = ARM9->Cycles - CompensatedCycles;
|
||||
CompensatedCycles = ARM9->Cycles;
|
||||
|
||||
s32 c7 = ARM7->Execute((c9 - ARM7Cycles) >> 1) << 1;
|
||||
ARM7Cycles = c7 - c9;
|
||||
|
||||
RunEvents(c9);
|
||||
}
|
||||
|
||||
|
||||
void Halt()
|
||||
{
|
||||
@ -182,6 +328,73 @@ void TriggerIRQ(u32 cpu, u32 irq)
|
||||
|
||||
|
||||
|
||||
const s32 TimerPrescaler[4] = {2, 128, 512, 2048};
|
||||
|
||||
void TimerIncrement(u32 param)
|
||||
{
|
||||
Timer* timer = &Timers[param];
|
||||
|
||||
u32 tid = param & 0x3;
|
||||
u32 cpu = param >> 2;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
timer->Counter++;
|
||||
if (param==7)printf("timer%d increment %04X %04X %04X\n", param, timer->Control, timer->Counter, timer->Reload);
|
||||
if (tid == (param&0x3))
|
||||
timer->Event = ScheduleEvent(TimerPrescaler[timer->Control&0x3], TimerIncrement, param);
|
||||
|
||||
if (timer->Counter == 0)
|
||||
{
|
||||
timer->Counter = timer->Reload;
|
||||
|
||||
if (timer->Control & (1<<6))
|
||||
TriggerIRQ(cpu, IRQ_Timer0 + tid);
|
||||
|
||||
// cascade
|
||||
if (tid == 3)
|
||||
break;
|
||||
timer++;
|
||||
if ((timer->Control & 0x84) != 0x84)
|
||||
break;
|
||||
tid++;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TimerStart(u32 id, u16 cnt)
|
||||
{
|
||||
Timer* timer = &Timers[id];
|
||||
u16 curstart = timer->Control & (1<<7);
|
||||
u16 newstart = cnt & (1<<7);
|
||||
|
||||
printf("timer%d start: %04X %04X\n", id, timer->Control, cnt);
|
||||
|
||||
timer->Control = cnt;
|
||||
|
||||
if ((!curstart) && newstart)
|
||||
{
|
||||
// start the timer, if it's not a cascading timer
|
||||
if (!(cnt & (1<<2)))
|
||||
{
|
||||
timer->Counter = timer->Reload;
|
||||
timer->Event = ScheduleEvent(TimerPrescaler[cnt&0x3], TimerIncrement, id);
|
||||
}
|
||||
else
|
||||
timer->Event = NULL;
|
||||
}
|
||||
else if (curstart && !newstart)
|
||||
{
|
||||
if (timer->Event)
|
||||
CancelEvent(timer->Event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
u8 ARM9Read8(u32 addr)
|
||||
{
|
||||
if ((addr & 0xFFFFF000) == 0xFFFF0000)
|
||||
@ -245,6 +458,15 @@ u16 ARM9Read16(u32 addr)
|
||||
case 0x04000000:
|
||||
switch (addr)
|
||||
{
|
||||
case 0x04000100: return Timers[0].Counter;
|
||||
case 0x04000102: return Timers[0].Control;
|
||||
case 0x04000104: return Timers[1].Counter;
|
||||
case 0x04000106: return Timers[1].Control;
|
||||
case 0x04000108: return Timers[2].Counter;
|
||||
case 0x0400010A: return Timers[2].Control;
|
||||
case 0x0400010C: return Timers[3].Counter;
|
||||
case 0x0400010E: return Timers[3].Control;
|
||||
|
||||
case 0x04000180: return IPCSync9;
|
||||
}
|
||||
}
|
||||
@ -268,6 +490,20 @@ u32 ARM9Read32(u32 addr)
|
||||
return *(u32*)&ARM9DTCM[(addr - ARM9DTCMBase) & 0x3FFF];
|
||||
}
|
||||
|
||||
if (addr >= 0xFFFF1000)
|
||||
{
|
||||
Halt();
|
||||
/*FILE* f = fopen("ram.bin", "wb");
|
||||
fwrite(MainRAM, 0x400000, 1, f);
|
||||
fclose(f);
|
||||
fopen("wram.bin", "wb");
|
||||
fwrite(ARM7WRAM, 0x10000, 1, f);
|
||||
fclose(f);
|
||||
fopen("swram.bin", "wb");
|
||||
fwrite(ARM7WRAM, 0x8000, 1, f);
|
||||
fclose(f);*/
|
||||
}
|
||||
|
||||
switch (addr & 0xFF000000)
|
||||
{
|
||||
case 0x02000000:
|
||||
@ -280,13 +516,18 @@ u32 ARM9Read32(u32 addr)
|
||||
case 0x04000000:
|
||||
switch (addr)
|
||||
{
|
||||
case 0x04000100: return Timers[0].Counter | (Timers[0].Control << 16);
|
||||
case 0x04000104: return Timers[1].Counter | (Timers[1].Control << 16);
|
||||
case 0x04000108: return Timers[2].Counter | (Timers[2].Control << 16);
|
||||
case 0x0400010C: return Timers[3].Counter | (Timers[3].Control << 16);
|
||||
|
||||
case 0x04000208: return IME[0];
|
||||
case 0x04000210: return IE[0];
|
||||
case 0x04000214: return IF[0];
|
||||
}
|
||||
}
|
||||
|
||||
printf("unknown arm9 read32 %08X | %08X\n", addr, ARM9->R[15]);
|
||||
printf("unknown arm9 read32 %08X | %08X %08X %08X\n", addr, ARM9->R[15], ARM9->R[12], ARM9Read32(0x027FF820));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -352,6 +593,15 @@ void ARM9Write16(u32 addr, u16 val)
|
||||
case 0x04000000:
|
||||
switch (addr)
|
||||
{
|
||||
case 0x04000100: Timers[0].Reload = val; return;
|
||||
case 0x04000102: TimerStart(0, val); return;
|
||||
case 0x04000104: Timers[1].Reload = val; return;
|
||||
case 0x04000106: TimerStart(1, val); return;
|
||||
case 0x04000108: Timers[2].Reload = val; return;
|
||||
case 0x0400010A: TimerStart(2, val); return;
|
||||
case 0x0400010C: Timers[3].Reload = val; return;
|
||||
case 0x0400010E: TimerStart(3, val); return;
|
||||
|
||||
case 0x04000180:
|
||||
IPCSync7 &= 0xFFF0;
|
||||
IPCSync7 |= ((val & 0x0F00) >> 8);
|
||||
@ -361,6 +611,7 @@ void ARM9Write16(u32 addr, u16 val)
|
||||
{
|
||||
TriggerIRQ(1, IRQ_IPCSync);
|
||||
}
|
||||
CompensateARM7();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -394,6 +645,23 @@ void ARM9Write32(u32 addr, u32 val)
|
||||
case 0x04000000:
|
||||
switch (addr)
|
||||
{
|
||||
case 0x04000100:
|
||||
Timers[0].Reload = val & 0xFFFF;
|
||||
TimerStart(0, val>>16);
|
||||
return;
|
||||
case 0x04000104:
|
||||
Timers[1].Reload = val & 0xFFFF;
|
||||
TimerStart(1, val>>16);
|
||||
return;
|
||||
case 0x04000108:
|
||||
Timers[2].Reload = val & 0xFFFF;
|
||||
TimerStart(2, val>>16);
|
||||
return;
|
||||
case 0x0400010C:
|
||||
Timers[3].Reload = val & 0xFFFF;
|
||||
TimerStart(3, val>>16);
|
||||
return;
|
||||
|
||||
case 0x04000208: IME[0] = val; return;
|
||||
case 0x04000210: IE[0] = val; return;
|
||||
case 0x04000214: IF[0] &= ~val; return;
|
||||
@ -462,14 +730,25 @@ u16 ARM7Read16(u32 addr)
|
||||
case 0x04000000:
|
||||
switch (addr)
|
||||
{
|
||||
case 0x04000100: return Timers[4].Counter;
|
||||
case 0x04000102: return Timers[4].Control;
|
||||
case 0x04000104: return Timers[5].Counter;
|
||||
case 0x04000106: return Timers[5].Control;
|
||||
case 0x04000108: return Timers[6].Counter;
|
||||
case 0x0400010A: return Timers[6].Control;
|
||||
case 0x0400010C: return Timers[7].Counter;
|
||||
case 0x0400010E: return Timers[7].Control;
|
||||
|
||||
case 0x04000180: return IPCSync7;
|
||||
|
||||
case 0x040001C0: return SPI::ReadCnt();
|
||||
case 0x040001C2: return SPI::ReadData();
|
||||
|
||||
case 0x04000504: return _soundbias;
|
||||
}
|
||||
}
|
||||
|
||||
printf("unknown arm7 read16 %08X\n", addr);
|
||||
printf("unknown arm7 read16 %08X %08X\n", addr, ARM7->R[15]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -495,6 +774,11 @@ u32 ARM7Read32(u32 addr)
|
||||
case 0x04000000:
|
||||
switch (addr)
|
||||
{
|
||||
case 0x04000100: return Timers[4].Counter | (Timers[4].Control << 16);
|
||||
case 0x04000104: return Timers[5].Counter | (Timers[5].Control << 16);
|
||||
case 0x04000108: return Timers[6].Counter | (Timers[6].Control << 16);
|
||||
case 0x0400010C: return Timers[7].Counter | (Timers[7].Control << 16);
|
||||
|
||||
case 0x040001A4:
|
||||
return 0x00800000; // hax
|
||||
|
||||
@ -507,6 +791,7 @@ u32 ARM7Read32(u32 addr)
|
||||
}
|
||||
}
|
||||
if ((addr&0xFF000000) == 0xEA000000) Halt();
|
||||
|
||||
printf("unknown arm7 read32 %08X | %08X\n", addr, ARM7->R[15]);
|
||||
return 0;
|
||||
}
|
||||
@ -545,6 +830,19 @@ void ARM7Write8(u32 addr, u8 val)
|
||||
}
|
||||
}
|
||||
|
||||
if (addr==0xA20)
|
||||
{
|
||||
/*FILE* f = fopen("ram.bin", "wb");
|
||||
fwrite(MainRAM, 0x400000, 1, f);
|
||||
fclose(f);
|
||||
fopen("wram.bin", "wb");
|
||||
fwrite(ARM7WRAM, 0x10000, 1, f);
|
||||
fclose(f);
|
||||
fopen("swram.bin", "wb");
|
||||
fwrite(ARM7WRAM, 0x8000, 1, f);
|
||||
fclose(f);*/
|
||||
}
|
||||
|
||||
printf("unknown arm7 write8 %08X %02X | %08X | %08X %08X %08X %08X\n", addr, val, ARM7->R[15], IME[1], IE[1], ARM7->R[0], ARM7->R[1]);
|
||||
}
|
||||
|
||||
@ -568,6 +866,15 @@ void ARM7Write16(u32 addr, u16 val)
|
||||
case 0x04000000:
|
||||
switch (addr)
|
||||
{
|
||||
case 0x04000100: Timers[4].Reload = val; return;
|
||||
case 0x04000102: TimerStart(4, val); return;
|
||||
case 0x04000104: Timers[5].Reload = val; return;
|
||||
case 0x04000106: TimerStart(5, val); return;
|
||||
case 0x04000108: Timers[6].Reload = val; return;
|
||||
case 0x0400010A: TimerStart(6, val); return;
|
||||
case 0x0400010C: Timers[7].Reload = val; return;
|
||||
case 0x0400010E: TimerStart(7, val); return;
|
||||
|
||||
case 0x04000180:
|
||||
IPCSync9 &= 0xFFF0;
|
||||
IPCSync9 |= ((val & 0x0F00) >> 8);
|
||||
@ -586,6 +893,10 @@ void ARM7Write16(u32 addr, u16 val)
|
||||
case 0x040001C2:
|
||||
SPI::WriteData(val & 0xFF);
|
||||
return;
|
||||
|
||||
case 0x04000504:
|
||||
_soundbias = val & 0x3FF;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -612,13 +923,30 @@ void ARM7Write32(u32 addr, u32 val)
|
||||
case 0x04000000:
|
||||
switch (addr)
|
||||
{
|
||||
case 0x04000100:
|
||||
Timers[4].Reload = val & 0xFFFF;
|
||||
TimerStart(4, val>>16);
|
||||
return;
|
||||
case 0x04000104:
|
||||
Timers[5].Reload = val & 0xFFFF;
|
||||
TimerStart(5, val>>16);
|
||||
return;
|
||||
case 0x04000108:
|
||||
Timers[6].Reload = val & 0xFFFF;
|
||||
TimerStart(6, val>>16);
|
||||
return;
|
||||
case 0x0400010C:
|
||||
Timers[7].Reload = val & 0xFFFF;
|
||||
TimerStart(7, val>>16);
|
||||
return;
|
||||
|
||||
case 0x04000208: IME[1] = val; return;
|
||||
case 0x04000210: IE[1] = val; return;
|
||||
case 0x04000214: IF[1] &= ~val; printf("IRQ ack %08X\n", val);return;
|
||||
}
|
||||
}
|
||||
|
||||
printf("unknown arm7 write32 %08X %08X | %08X\n", addr, val, ARM7->R[15]);
|
||||
printf("unknown arm7 write32 %08X %08X | %08X %08X\n", addr, val, ARM7->R[15], ARM7->CurInstr);
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user