RTC revamp (#1867)

* get this started

* implement DSi RTC commands

* set up RTC clock timer. lay down basic idea of a clock.

* make the date/time registers writable

* move RTC state to its own structure, to make it easier to deal with

* more RTC work
lay base for date/time dialog

* get the bulk of the RTC functionality going

* much simpler design for RTC stuff

* aha, that is what it is

* start working on the RTC IRQ

* implement all types of RTC IRQ

* start refining sleep mode. code still kinda sucks.

* implement keypad IRQ

* refine it some more

* shut the fuck uuuuuupppppppppppppp
This commit is contained in:
Arisotura
2023-10-30 18:37:49 +01:00
committed by GitHub
parent 21590b0709
commit 9a450f5f28
21 changed files with 1470 additions and 214 deletions

View File

@ -167,7 +167,7 @@ u32 SqrtVal[2];
u32 SqrtRes;
u32 KeyInput;
u16 KeyCnt;
u16 KeyCnt[2];
u16 RCnt;
bool Running;
@ -612,7 +612,8 @@ void Reset()
SchedListMask = 0;
KeyInput = 0x007F03FF;
KeyCnt = 0;
KeyCnt[0] = 0;
KeyCnt[1] = 0;
RCnt = 0;
NDSCart::Reset();
@ -715,6 +716,7 @@ bool DoSavestate_Scheduler(Savestate* file)
GPU::StartScanline, GPU::StartHBlank, GPU::FinishFrame,
SPU::Mix,
Wifi::USTimer,
RTC::ClockTimer,
GPU::DisplayFIFO,
NDSCart::ROMPrepareData, NDSCart::ROMEndTransfer,
@ -887,7 +889,7 @@ bool DoSavestate(Savestate* file)
file->Bool32(&LagFrameFlag);
// TODO: save KeyInput????
file->Var16(&KeyCnt);
file->VarArray(KeyCnt, 2*sizeof(u16));
file->Var16(&RCnt);
file->Var8(&WRAMCnt);
@ -1059,93 +1061,192 @@ void RunSystem(u64 timestamp)
}
}
u64 NextTargetSleep()
{
u64 minEvent = UINT64_MAX;
u32 mask = SchedListMask;
for (int i = 0; i < Event_MAX; i++)
{
if (!mask) break;
if (i == Event_SPU || i == Event_RTC)
{
if (mask & 0x1)
{
if (SchedList[i].Timestamp < minEvent)
minEvent = SchedList[i].Timestamp;
}
}
mask >>= 1;
}
return minEvent;
}
void RunSystemSleep(u64 timestamp)
{
u64 offset = timestamp - SysTimestamp;
SysTimestamp = timestamp;
u32 mask = SchedListMask;
for (int i = 0; i < Event_MAX; i++)
{
if (!mask) break;
if (i == Event_SPU || i == Event_RTC)
{
if (mask & 0x1)
{
if (SchedList[i].Timestamp <= SysTimestamp)
{
SchedListMask &= ~(1<<i);
u32 param;
if (i == Event_SPU)
param = 1;
else
param = SchedList[i].Param;
SchedList[i].Func(param);
}
}
}
else if (mask & 0x1)
{
if (SchedList[i].Timestamp <= SysTimestamp)
{
SchedList[i].Timestamp += offset;
}
}
mask >>= 1;
}
}
template <bool EnableJIT, int ConsoleType>
u32 RunFrame()
{
FrameStartTimestamp = SysTimestamp;
GPU::TotalScanlines = 0;
LagFrameFlag = true;
bool runFrame = Running && !(CPUStop & 0x40000000);
if (runFrame)
bool runFrame = Running && !(CPUStop & CPUStop_Sleep);
while (Running)
{
ARM9->CheckGdbIncoming();
ARM7->CheckGdbIncoming();
u64 frametarget = SysTimestamp + 560190;
GPU::StartFrame();
while (Running && GPU::TotalScanlines==0)
if (CPUStop & CPUStop_Sleep)
{
u64 target = NextTarget();
ARM9Target = target << ARM9ClockShift;
CurCPU = 0;
// we are running in sleep mode
// we still need to run the RTC during this mode
// we also keep outputting audio, so that frontends using audio sync don't skyrocket to 1000+FPS
if (CPUStop & 0x80000000)
while (Running && (SysTimestamp < frametarget))
{
// GXFIFO stall
s32 cycles = GPU3D::CyclesToRunFor();
u64 target = NextTargetSleep();
if (target > frametarget)
target = frametarget;
ARM9Timestamp = std::min(ARM9Target, ARM9Timestamp+(cycles<<ARM9ClockShift));
}
else if (CPUStop & 0x0FFF)
{
DMAs[0]->Run<ConsoleType>();
if (!(CPUStop & 0x80000000)) DMAs[1]->Run<ConsoleType>();
if (!(CPUStop & 0x80000000)) DMAs[2]->Run<ConsoleType>();
if (!(CPUStop & 0x80000000)) DMAs[3]->Run<ConsoleType>();
if (ConsoleType == 1) DSi::RunNDMAs(0);
}
else
{
#ifdef JIT_ENABLED
if (EnableJIT)
ARM9->ExecuteJIT();
else
#endif
ARM9->Execute();
ARM9Timestamp = target << ARM9ClockShift;
ARM7Timestamp = target;
TimerTimestamp[0] = target;
TimerTimestamp[1] = target;
GPU3D::Timestamp = target;
RunSystemSleep(target);
if (!(CPUStop & CPUStop_Sleep))
break;
}
RunTimers(0);
GPU3D::Run();
if (SysTimestamp >= frametarget)
GPU::BlankFrame();
}
else
{
ARM9->CheckGdbIncoming();
ARM7->CheckGdbIncoming();
target = ARM9Timestamp >> ARM9ClockShift;
CurCPU = 1;
while (ARM7Timestamp < target)
if (!(CPUStop & CPUStop_Wakeup))
{
ARM7Target = target; // might be changed by a reschedule
GPU::StartFrame();
}
CPUStop &= ~CPUStop_Wakeup;
if (CPUStop & 0x0FFF0000)
while (Running && GPU::TotalScanlines==0)
{
u64 target = NextTarget();
ARM9Target = target << ARM9ClockShift;
CurCPU = 0;
if (CPUStop & CPUStop_GXStall)
{
DMAs[4]->Run<ConsoleType>();
DMAs[5]->Run<ConsoleType>();
DMAs[6]->Run<ConsoleType>();
DMAs[7]->Run<ConsoleType>();
if (ConsoleType == 1) DSi::RunNDMAs(1);
// GXFIFO stall
s32 cycles = GPU3D::CyclesToRunFor();
ARM9Timestamp = std::min(ARM9Target, ARM9Timestamp+(cycles<<ARM9ClockShift));
}
else if (CPUStop & CPUStop_DMA9)
{
DMAs[0]->Run<ConsoleType>();
if (!(CPUStop & CPUStop_GXStall)) DMAs[1]->Run<ConsoleType>();
if (!(CPUStop & CPUStop_GXStall)) DMAs[2]->Run<ConsoleType>();
if (!(CPUStop & CPUStop_GXStall)) DMAs[3]->Run<ConsoleType>();
if (ConsoleType == 1) DSi::RunNDMAs(0);
}
else
{
#ifdef JIT_ENABLED
if (EnableJIT)
ARM7->ExecuteJIT();
ARM9->ExecuteJIT();
else
#endif
ARM7->Execute();
ARM9->Execute();
}
RunTimers(1);
}
RunTimers(0);
GPU3D::Run();
RunSystem(target);
target = ARM9Timestamp >> ARM9ClockShift;
CurCPU = 1;
if (CPUStop & 0x40000000)
{
// checkme: when is sleep mode effective?
CancelEvent(Event_LCD);
GPU::TotalScanlines = 263;
break;
while (ARM7Timestamp < target)
{
ARM7Target = target; // might be changed by a reschedule
if (CPUStop & CPUStop_DMA7)
{
DMAs[4]->Run<ConsoleType>();
DMAs[5]->Run<ConsoleType>();
DMAs[6]->Run<ConsoleType>();
DMAs[7]->Run<ConsoleType>();
if (ConsoleType == 1) DSi::RunNDMAs(1);
}
else
{
#ifdef JIT_ENABLED
if (EnableJIT)
ARM7->ExecuteJIT();
else
#endif
ARM7->Execute();
}
RunTimers(1);
}
RunSystem(target);
if (CPUStop & CPUStop_Sleep)
{
break;
}
}
}
if (GPU::TotalScanlines == 0)
continue;
#ifdef DEBUG_CHECK_DESYNC
Log(LogLevel::Debug, "[%08X%08X] ARM9=%ld, ARM7=%ld, GPU=%ld\n",
(u32)(SysTimestamp>>32), (u32)SysTimestamp,
@ -1154,6 +1255,7 @@ u32 RunFrame()
GPU3D::Timestamp-SysTimestamp);
#endif
SPU::TransferOutput();
break;
}
// In the context of TASes, frame count is traditionally the primary measure of emulated time,
@ -1162,7 +1264,7 @@ u32 RunFrame()
if (LagFrameFlag)
NumLagFrames++;
if (runFrame)
if (Running)
return GPU::TotalScanlines;
else
return 263;
@ -1276,13 +1378,47 @@ void ReleaseScreen()
}
void CheckKeyIRQ(u32 cpu, u32 oldkey, u32 newkey)
{
u16 cnt = KeyCnt[cpu];
if (!(cnt & (1<<14))) // IRQ disabled
return;
u32 mask = (cnt & 0x03FF);
oldkey &= mask;
newkey &= mask;
bool oldmatch, newmatch;
if (cnt & (1<<15))
{
// logical AND
oldmatch = (oldkey == 0);
newmatch = (newkey == 0);
}
else
{
// logical OR
oldmatch = (oldkey != mask);
newmatch = (newkey != mask);
}
if ((!oldmatch) && newmatch)
SetIRQ(cpu, IRQ_Keypad);
}
void SetKeyMask(u32 mask)
{
u32 key_lo = mask & 0x3FF;
u32 key_hi = (mask >> 10) & 0x3;
u32 oldkey = KeyInput;
KeyInput &= 0xFFFCFC00;
KeyInput |= key_lo | (key_hi << 16);
CheckKeyIRQ(0, oldkey, KeyInput);
CheckKeyIRQ(1, oldkey, KeyInput);
}
bool IsLidClosed()
@ -1301,8 +1437,6 @@ void SetLidClosed(bool closed)
{
KeyInput &= ~(1<<23);
SetIRQ(1, IRQ_LidOpen);
CPUStop &= ~0x40000000;
GPU3D::RestartFrame();
}
}
@ -1467,6 +1601,16 @@ void SetIRQ(u32 cpu, u32 irq)
{
IF[cpu] |= (1 << irq);
UpdateIRQ(cpu);
if ((cpu == 1) && (CPUStop & CPUStop_Sleep))
{
if (IE[1] & (1 << irq))
{
CPUStop &= ~CPUStop_Sleep;
CPUStop |= CPUStop_Wakeup;
GPU3D::RestartFrame();
}
}
}
void ClearIRQ(u32 cpu, u32 irq)
@ -1526,9 +1670,9 @@ void ResumeCPU(u32 cpu, u32 mask)
void GXFIFOStall()
{
if (CPUStop & 0x80000000) return;
if (CPUStop & CPUStop_GXStall) return;
CPUStop |= 0x80000000;
CPUStop |= CPUStop_GXStall;
if (CurCPU == 1) ARM9->Halt(2);
else
@ -1543,14 +1687,14 @@ void GXFIFOStall()
void GXFIFOUnstall()
{
CPUStop &= ~0x80000000;
CPUStop &= ~CPUStop_GXStall;
}
void EnterSleepMode()
{
if (CPUStop & 0x40000000) return;
if (CPUStop & CPUStop_Sleep) return;
CPUStop |= 0x40000000;
CPUStop |= CPUStop_Sleep;
ARM7->Halt(2);
}
@ -2017,7 +2161,7 @@ void debug(u32 param)
// printf("VRAM %c: %02X\n", 'A'+i, GPU::VRAMCNT[i]);
FILE*
shit = fopen("debug/crayon.bin", "wb");
shit = fopen("debug/DSfirmware.bin", "wb");
fwrite(ARM9->ITCM, 0x8000, 1, shit);
for (u32 i = 0x02000000; i < 0x02400000; i+=4)
{
@ -2942,8 +3086,8 @@ u8 ARM9IORead8(u32 addr)
{
case 0x04000130: LagFrameFlag = false; return KeyInput & 0xFF;
case 0x04000131: LagFrameFlag = false; return (KeyInput >> 8) & 0xFF;
case 0x04000132: return KeyCnt & 0xFF;
case 0x04000133: return KeyCnt >> 8;
case 0x04000132: return KeyCnt[0] & 0xFF;
case 0x04000133: return KeyCnt[0] >> 8;
case 0x040001A2:
if (!(ExMemCnt[0] & (1<<11)))
@ -3079,7 +3223,7 @@ u16 ARM9IORead16(u32 addr)
case 0x0400010E: return Timers[3].Cnt;
case 0x04000130: LagFrameFlag = false; return KeyInput & 0xFFFF;
case 0x04000132: return KeyCnt;
case 0x04000132: return KeyCnt[0];
case 0x04000180: return IPCSync9;
case 0x04000184:
@ -3221,7 +3365,7 @@ u32 ARM9IORead32(u32 addr)
case 0x04000108: return TimerGetCounter(2) | (Timers[2].Cnt << 16);
case 0x0400010C: return TimerGetCounter(3) | (Timers[3].Cnt << 16);
case 0x04000130: LagFrameFlag = false; return (KeyInput & 0xFFFF) | (KeyCnt << 16);
case 0x04000130: LagFrameFlag = false; return (KeyInput & 0xFFFF) | (KeyCnt[0] << 16);
case 0x04000180: return IPCSync9;
case 0x04000184: return ARM9IORead16(addr);
@ -3341,10 +3485,10 @@ void ARM9IOWrite8(u32 addr, u8 val)
case 0x0400106D: GPU::GPU2D_B.Write8(addr, val); return;
case 0x04000132:
KeyCnt = (KeyCnt & 0xFF00) | val;
KeyCnt[0] = (KeyCnt[0] & 0xFF00) | val;
return;
case 0x04000133:
KeyCnt = (KeyCnt & 0x00FF) | (val << 8);
KeyCnt[0] = (KeyCnt[0] & 0x00FF) | (val << 8);
return;
case 0x04000188:
@ -3454,7 +3598,7 @@ void ARM9IOWrite16(u32 addr, u16 val)
case 0x0400010E: TimerStart(3, val); return;
case 0x04000132:
KeyCnt = val;
KeyCnt[0] = val;
return;
case 0x04000180:
@ -3647,7 +3791,7 @@ void ARM9IOWrite32(u32 addr, u32 val)
return;
case 0x04000130:
KeyCnt = val >> 16;
KeyCnt[0] = val >> 16;
return;
case 0x04000180:
@ -3800,8 +3944,8 @@ u8 ARM7IORead8(u32 addr)
{
case 0x04000130: return KeyInput & 0xFF;
case 0x04000131: return (KeyInput >> 8) & 0xFF;
case 0x04000132: return KeyCnt & 0xFF;
case 0x04000133: return KeyCnt >> 8;
case 0x04000132: return KeyCnt[1] & 0xFF;
case 0x04000133: return KeyCnt[1] >> 8;
case 0x04000134: return RCnt & 0xFF;
case 0x04000135: return RCnt >> 8;
case 0x04000136: return (KeyInput >> 16) & 0xFF;
@ -3894,7 +4038,7 @@ u16 ARM7IORead16(u32 addr)
case 0x0400010E: return Timers[7].Cnt;
case 0x04000130: return KeyInput & 0xFFFF;
case 0x04000132: return KeyCnt;
case 0x04000132: return KeyCnt[1];
case 0x04000134: return RCnt;
case 0x04000136: return KeyInput >> 16;
@ -3986,8 +4130,8 @@ u32 ARM7IORead32(u32 addr)
case 0x04000108: return TimerGetCounter(6) | (Timers[6].Cnt << 16);
case 0x0400010C: return TimerGetCounter(7) | (Timers[7].Cnt << 16);
case 0x04000130: return (KeyInput & 0xFFFF) | (KeyCnt << 16);
case 0x04000134: return RCnt | (KeyCnt & 0xFFFF0000);
case 0x04000130: return (KeyInput & 0xFFFF) | (KeyCnt[1] << 16);
case 0x04000134: return RCnt | (KeyInput & 0xFFFF0000);
case 0x04000138: return RTC::Read();
case 0x04000180: return IPCSync7;
@ -4068,10 +4212,10 @@ void ARM7IOWrite8(u32 addr, u8 val)
switch (addr)
{
case 0x04000132:
KeyCnt = (KeyCnt & 0xFF00) | val;
KeyCnt[1] = (KeyCnt[1] & 0xFF00) | val;
return;
case 0x04000133:
KeyCnt = (KeyCnt & 0x00FF) | (val << 8);
KeyCnt[1] = (KeyCnt[1] & 0x00FF) | (val << 8);
return;
case 0x04000134:
RCnt = (RCnt & 0xFF00) | val;
@ -4165,7 +4309,7 @@ void ARM7IOWrite16(u32 addr, u16 val)
case 0x0400010C: Timers[7].Reload = val; return;
case 0x0400010E: TimerStart(7, val); return;
case 0x04000132: KeyCnt = val; return;
case 0x04000132: KeyCnt[1] = val; return;
case 0x04000134: RCnt = val; return;
case 0x04000138: RTC::Write(val, false); return;
@ -4334,7 +4478,7 @@ void ARM7IOWrite32(u32 addr, u32 val)
TimerStart(7, val>>16);
return;
case 0x04000130: KeyCnt = val >> 16; return;
case 0x04000130: KeyCnt[1] = val >> 16; return;
case 0x04000134: RCnt = val & 0xFFFF; return;
case 0x04000138: RTC::Write(val & 0xFFFF, false); return;