* begin adding POWCNT2, only applies to wifi for now

* begin work on wifi scheduler
This commit is contained in:
Arisotura 2022-09-01 22:24:20 +02:00
parent fb73b80674
commit cc68017f52
7 changed files with 340 additions and 51 deletions

View File

@ -1198,6 +1198,25 @@ void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 para
Reschedule(evt->Timestamp);
}
void ScheduleEvent(u32 id, u64 timestamp, void (*func)(u32), u32 param)
{
if (SchedListMask & (1<<id))
{
printf("!! 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);
}
void CancelEvent(u32 id)
{
SchedListMask &= ~(1<<id);
@ -2396,6 +2415,7 @@ u8 ARM7Read8(u32 addr)
case 0x04800000:
if (addr < 0x04810000)
{
if (!(PowerControl7 & (1<<1))) return 0;
if (addr & 0x1) return Wifi::Read(addr-1) >> 8;
return Wifi::Read(addr) & 0xFF;
}
@ -2460,6 +2480,7 @@ u16 ARM7Read16(u32 addr)
case 0x04800000:
if (addr < 0x04810000)
{
if (!(PowerControl7 & (1<<1))) return 0;
return Wifi::Read(addr);
}
break;
@ -2523,6 +2544,7 @@ u32 ARM7Read32(u32 addr)
case 0x04800000:
if (addr < 0x04810000)
{
if (!(PowerControl7 & (1<<1))) return 0;
return Wifi::Read(addr) | (Wifi::Read(addr+2) << 16);
}
break;
@ -2663,6 +2685,7 @@ void ARM7Write16(u32 addr, u16 val)
case 0x04800000:
if (addr < 0x04810000)
{
if (!(PowerControl7 & (1<<1))) return;
Wifi::Write(addr, val);
return;
}
@ -2740,6 +2763,7 @@ void ARM7Write32(u32 addr, u32 val)
case 0x04800000:
if (addr < 0x04810000)
{
if (!(PowerControl7 & (1<<1))) return;
Wifi::Write(addr, val & 0xFFFF);
Wifi::Write(addr+2, val >> 16);
return;
@ -3751,6 +3775,7 @@ u8 ARM7IORead8(u32 addr)
case 0x04000241: return WRAMCnt;
case 0x04000300: return PostFlag7;
case 0x04000304: return PowerControl7;
}
if (addr >= 0x04000400 && addr < 0x04000520)
@ -3833,7 +3858,9 @@ u16 ARM7IORead16(u32 addr)
case 0x040001C2: return SPI::ReadData();
case 0x04000204: return ExMemCnt[1];
case 0x04000206: return WifiWaitCnt;
case 0x04000206:
if (!(PowerControl7 & (1<<1))) return 0;
return WifiWaitCnt;
case 0x04000208: return IME[1];
case 0x04000210: return IE[1] & 0xFFFF;
@ -3915,6 +3942,7 @@ u32 ARM7IORead32(u32 addr)
case 0x04000210: return IE[1];
case 0x04000214: return IF[1];
case 0x04000304: return PowerControl7;
case 0x04000308: return ARM7BIOSProt;
case 0x04100000:
@ -4143,6 +4171,7 @@ void ARM7IOWrite16(u32 addr, u16 val)
return;
}
case 0x04000206:
if (!(PowerControl7 & (1<<1))) return;
SetWifiWaitCnt(val);
return;
@ -4158,7 +4187,11 @@ void ARM7IOWrite16(u32 addr, u16 val)
PostFlag7 = val & 0x01;
return;
case 0x04000304: PowerControl7 = val; return;
case 0x04000304:
PowerControl7 = val & 0x0003;
SPU::SetPowerCnt(val & 0x0001);
Wifi::SetPowerCnt(val & 0x0002);
return;
case 0x04000308:
if (ARM7BIOSProt == 0)
@ -4280,7 +4313,11 @@ void ARM7IOWrite32(u32 addr, u32 val)
case 0x04000210: IE[1] = val; UpdateIRQ(1); return;
case 0x04000214: IF[1] &= ~val; UpdateIRQ(1); return;
case 0x04000304: PowerControl7 = val & 0xFFFF; return;
case 0x04000304:
PowerControl7 = val & 0x0003;
SPU::SetPowerCnt(val & 0x0001);
Wifi::SetPowerCnt(val & 0x0002);
return;
case 0x04000308:
if (ARM7BIOSProt == 0)

View File

@ -52,6 +52,8 @@ enum
Event_DSi_CamTransfer,
Event_DSi_DSP,
Event_WifiLegacy,
Event_MAX
};
@ -263,6 +265,7 @@ void SetLidClosed(bool closed);
void MicInputFrame(s16* data, int samples);
void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param);
void ScheduleEvent(u32 id, u64 timestamp, void (*func)(u32), u32 param);
void CancelEvent(u32 id);
void debug(u32 p);

View File

@ -184,6 +184,12 @@ void DoSavestate(Savestate* file)
}
void SetPowerCnt(u32 val)
{
// TODO
}
void SetInterpolation(int type)
{
InterpType = type;

View File

@ -31,6 +31,8 @@ void Stop();
void DoSavestate(Savestate* file);
void SetPowerCnt(u32 val);
// 0=none 1=linear 2=cosine 3=cubic
void SetInterpolation(int type);

View File

@ -46,11 +46,20 @@ const u8 MPCmdMAC[6] = {0x03, 0x09, 0xBF, 0x00, 0x00, 0x00};
const u8 MPReplyMAC[6] = {0x03, 0x09, 0xBF, 0x00, 0x00, 0x10};
const u8 MPAckMAC[6] = {0x03, 0x09, 0xBF, 0x00, 0x00, 0x03};
bool Enabled;
bool PowerOn;
u16 Random;
// general, always-on microsecond counter
u64 USTimestamp;
u64 SchedTimestamp;
SchedEvent SchedList[Event_MAX];
u32 SchedListMask;
const u32 kRXCheckPeriod = 512;
u64 USCounter;
u64 USCompare;
bool BlockBeaconIRQ14;
@ -137,21 +146,35 @@ const u64 kMaxRunahead = 4096;
// 4 = switching from TX to RX
// 5 = MP host data sent, waiting for replies (RFPINS=0x0084)
// 6 = RX
// 7 = ??
// 7 = switching from RX reply to TX ack
// 8 = MP client sending reply, MP host sending ack (RFPINS=0x0046)
// 9 = idle
// wifi TODO:
// * power saving
// * RXSTAT, multiplay reply errors
// * RXSTAT
// * TX errors (if applicable)
void UpdateTimers();
void Reschedule();
void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param);
void CancelEvent(u32 id);
void StartTX_Beacon();
void PeriodicRXCheck(u32 time);
bool Init()
{
MPInited = false;
LANInited = false;
//MPInited = false;
//LANInited = false;
Platform::MP_Init();
MPInited = true;
Platform::LAN_Init();
LANInited = true;
WifiAP::Init();
@ -173,6 +196,9 @@ void Reset()
memset(RAM, 0, 0x2000);
memset(IO, 0, 0x1000);
Enabled = false;
PowerOn = false;
Random = 1;
memset(BBRegs, 0, 0x100);
@ -231,6 +257,10 @@ void Reset()
USTimestamp = 0;
RXTimestamp = 0;
SchedTimestamp = 0;
memset(SchedList, 0, sizeof(SchedList));
SchedListMask = 0;
USCounter = 0;
USCompare = 0;
BlockBeaconIRQ14 = false;
@ -290,6 +320,178 @@ void DoSavestate(Savestate* file)
}
void UpdatePowerOn();
void SetPowerCnt(u32 val)
{
Enabled = val & (1<<1);
UpdatePowerOn();
}
// wifi scheduling
// NOTE: this is technically inaccurate
// in the DS, the wifi system is driven by its own 22MHz clock, not by the system clock
// but in melonDS, we do need to drive it from the system scheduler, so it stays in sync
// with the rest of the system
inline u64 USToSysCycles(u64 us)
{
return (us * 33513982) / 1000000;
}
inline u64 SysCyclesToUS(u64 sys)
{
return ((sys + 16) * 1000000) / 33513982;
}
void UpdateTimers()
{
u64 oldts = SchedTimestamp;
SchedTimestamp = SysCyclesToUS(NDS::GetSysClockCycles(0));
u64 diff = SchedTimestamp - oldts;
if (diff == 0) return;
USTimestamp += diff;
if (IOPORT(W_USCountCnt))
{
USCounter += diff;
}
}
void UpdatePowerOn()
{
bool on = Enabled;
if (NDS::ConsoleType == 1)
{
// TODO for DSi:
// * W_POWER_US doesn't work (atleast on DWM-W024)
// * other registers like GPIO_WIFI may also control wifi power/clock
// * turning wifi off via POWCNT2 while sending breaks further attempts at sending frames
}
else
{
on = on && ((IOPORT(W_PowerUS) & 0x1) == 0);
}
if (on == PowerOn)
return;
PowerOn = on;
if (on)
{
printf("WIFI: ON\n");
u64 oldts = SchedTimestamp;
SchedTimestamp = SysCyclesToUS(NDS::GetSysClockCycles(0));
u64 diff = SchedTimestamp - oldts;
for (int i = 0; i < Event_MAX; i++)
{
if (!(SchedListMask & (1<<i)))
continue;
if (SchedList[i].Timestamp >= oldts)
{
SchedList[i].Timestamp += diff;
}
}
ScheduleEvent(Event_RXCheck, false, kRXCheckPeriod, PeriodicRXCheck, 0);
Platform::MP_Begin();
}
else
{
printf("WIFI: OFF\n");
CancelEvent(Event_RXCheck);
UpdateTimers();
NDS::CancelEvent(NDS::Event_Wifi);
Platform::MP_End();
}
}
void RunEvents(u32 param)
{
UpdateTimers();
//printf("[%016llX] RUN EVENTS, MASK=%08X\n", SchedTimestamp, SchedListMask);
u32 mask = SchedListMask;
for (int i = 0; i < Event_MAX; i++)
{
if (!mask) break;
if (mask & 0x1)
{
if (SchedList[i].Timestamp <= SchedTimestamp)
{
SchedListMask &= ~(1<<i);
SchedList[i].Func(SchedList[i].Param);
}
}
mask >>= 1;
}
}
void Reschedule()
{
u64 next = UINT64_MAX;
u32 mask = SchedListMask;
for (int i = 0; i < Event_MAX; i++)
{
if (!mask) break;
if (mask & 0x1)
{
if (SchedList[i].Timestamp < next)
next = SchedList[i].Timestamp;
}
mask >>= 1;
}
//printf("[%016llX] RESCHEDULE: NEXT TIMESTAMP = %016llX\n", SchedTimestamp, next);
NDS::CancelEvent(NDS::Event_Wifi);
NDS::ScheduleEvent(NDS::Event_Wifi, USToSysCycles(next), RunEvents, 0);
}
void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param)
{
if (SchedListMask & (1<<id))
{
printf("wifi: !! EVENT %d ALREADY SCHEDULED\n", id);
return;
}
SchedEvent* evt = &SchedList[id];
if (periodic)
{
evt->Timestamp += delay;
}
else
{
UpdateTimers();
evt->Timestamp = SchedTimestamp + delay;
}
evt->Func = func;
evt->Param = param;
SchedListMask |= (1<<id);
//if(id==Event_MSTimer) printf("[%016llX] MSTIMER EVENT SCHEDULED: %d,%d , TIMESTAMP=%016llX\n", SchedTimestamp, periodic, delay, evt->Timestamp);
Reschedule();
}
void CancelEvent(u32 id)
{
SchedListMask &= ~(1<<id);
}
void PowerDown();
void SetIRQ(u32 irq)
@ -346,7 +548,7 @@ void SetIRQ14(int source) // 0=USCOMPARE 1=BEACONCOUNT 2=forced
IOPORT(W_ListenCount)--;
}
void SetIRQ15()
void SetIRQ15(u32 param)
{
SetIRQ(15);
@ -1343,7 +1545,18 @@ bool CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames
}
void MSTimer()
void PeriodicRXCheck(u32 time)
{
if (!time) WifiAP::MSTimer();
// TODO: actual RX check!!
time += kRXCheckPeriod;
time &= 0x3FF;
ScheduleEvent(Event_RXCheck, true, kRXCheckPeriod, PeriodicRXCheck, time);
}
void MSTimer(u32 param)
{
if (IOPORT(W_USCompareCnt))
{
@ -1355,6 +1568,12 @@ void MSTimer()
}
IOPORT(W_BeaconCount1)--;
if (IOPORT(W_BeaconCount1) == ((IOPORT(W_PreBeacon) >> 10) + 1))
{
s32 delay = (IOPORT(W_BeaconCount1) << 10) - IOPORT(W_PreBeacon);
CancelEvent(Event_IRQ15);
ScheduleEvent(Event_IRQ15, false, delay, SetIRQ15, 0);
}
if (IOPORT(W_BeaconCount1) == 0)
{
SetIRQ14(1);
@ -1365,11 +1584,18 @@ void MSTimer()
IOPORT(W_BeaconCount2)--;
if (IOPORT(W_BeaconCount2) == 0) SetIRQ13();
}
printf("MSTimer %016llX %016llX\n", SchedTimestamp, USCounter);
ScheduleEvent(Event_MSTimer, true, 1024, MSTimer, 0);
}
void USTimer(u32 param)
{
USTimestamp++;
/*USTimestamp++;
u64 sys = NDS::GetSysClockCycles(0);
u64 ts = SysCyclesToUS(sys);
ts = USTimestamp - ts;
printf("diff=%016llX\n", ts);
if (IsMPClient)
{
@ -1386,10 +1612,10 @@ void USTimer(u32 param)
CheckRX(2);
}
}
}
}*/
WifiAP::USTimer();
//WifiAP::USTimer();
bool switchOffPowerSaving = false;
if (USUntilPowerOn < 0)
@ -1406,7 +1632,7 @@ void USTimer(u32 param)
SetIRQ(11);
}
if (IOPORT(W_USCountCnt))
/*if (IOPORT(W_USCountCnt))
{
USCounter++;
u32 uspart = (USCounter & 0x3FF);
@ -1418,7 +1644,7 @@ void USTimer(u32 param)
}
if (!uspart) MSTimer();
}
}*/
if (IOPORT(W_CmdCountCnt) & 0x0001)
{
@ -1590,8 +1816,10 @@ void USTimer(u32 param)
// TODO: make it more accurate, eventually
// in the DS, the wifi system has its own 22MHz clock and doesn't use the system clock
// measurement: 16715us per frame
// calculation: 16715.113113088143330744761992174us per frame
//NDS::ScheduleEvent(NDS::Event_Wifi, true, 33, USTimer, 0);
NDS::ScheduleEvent(NDS::Event_Wifi, true, 34, USTimer, 0);
NDS::ScheduleEvent(NDS::Event_WifiLegacy, true, 34, USTimer, 0);
}
@ -1654,10 +1882,10 @@ u16 Read(u32 addr)
case W_Preamble:
return IOPORT(W_Preamble) & 0x0003;
case W_USCount0: return (u16)(USCounter & 0xFFFF);
case W_USCount1: return (u16)((USCounter >> 16) & 0xFFFF);
case W_USCount2: return (u16)((USCounter >> 32) & 0xFFFF);
case W_USCount3: return (u16)(USCounter >> 48);
case W_USCount0: UpdateTimers(); return (u16)(USCounter & 0xFFFF);
case W_USCount1: UpdateTimers(); return (u16)((USCounter >> 16) & 0xFFFF);
case W_USCount2: UpdateTimers(); return (u16)((USCounter >> 32) & 0xFFFF);
case W_USCount3: UpdateTimers(); return (u16)(USCounter >> 48);
case W_USCompare0: return (u16)(USCompare & 0xFFFF);
case W_USCompare1: return (u16)((USCompare >> 16) & 0xFFFF);
@ -1894,31 +2122,9 @@ void Write(u32 addr, u16 val)
}
break;
case W_PowerUS:
// schedule timer event when the clock is enabled
// TODO: check whether this resets USCOUNT (and also which other events can reset it)
if ((IOPORT(W_PowerUS) & 0x0001) && !(val & 0x0001))
{
printf("WIFI ON\n");
NDS::ScheduleEvent(NDS::Event_Wifi, false, 33, USTimer, 0);
if (!MPInited)
{
Platform::MP_Init();
MPInited = true;
}
if (!LANInited)
{
Platform::LAN_Init();
LANInited = true;
}
Platform::MP_Begin();
}
else if (!(IOPORT(W_PowerUS) & 0x0001) && (val & 0x0001))
{
printf("WIFI OFF\n");
NDS::CancelEvent(NDS::Event_Wifi);
Platform::MP_End();
}
break;
IOPORT(W_PowerUS) = val & 0x0003;
UpdatePowerOn();
return;
case W_PowerUnk:
val &= 0x0003;
//printf("writing power unk %x\n", val);
@ -1928,16 +2134,29 @@ void Write(u32 addr, u16 val)
val = 3;
break;
case W_USCountCnt: val &= 0x0001; break;
case W_USCountCnt:
val &= 0x0001;
if (val && (!IOPORT(W_USCountCnt)))
{printf("[%016llX][%016llX] ON -> NEXT=%016llX\n", SchedTimestamp, USCounter, USCounter + 1024 - (USCounter & 0x3FF));
ScheduleEvent(Event_MSTimer, false, 1024 - (USCounter & 0x3FF), MSTimer, 0);
IOPORT(W_USCountCnt) = val;
}
else if ((!val) && IOPORT(W_USCountCnt))
{
UpdateTimers();printf("[%016llX][%016llX] OFF\n", SchedTimestamp, USCounter);
IOPORT(W_USCountCnt) = val;
CancelEvent(Event_MSTimer);
}
return;
case W_USCompareCnt:
if (val & 0x0002) SetIRQ14(2);
val &= 0x0001;
break;
case W_USCount0: USCounter = (USCounter & 0xFFFFFFFFFFFF0000) | (u64)val; return;
case W_USCount1: USCounter = (USCounter & 0xFFFFFFFF0000FFFF) | ((u64)val << 16); return;
case W_USCount2: USCounter = (USCounter & 0xFFFF0000FFFFFFFF) | ((u64)val << 32); return;
case W_USCount3: USCounter = (USCounter & 0x0000FFFFFFFFFFFF) | ((u64)val << 48); return;
case W_USCount0: UpdateTimers(); USCounter = (USCounter & 0xFFFFFFFFFFFF0000) | (u64)val; return;
case W_USCount1: UpdateTimers(); USCounter = (USCounter & 0xFFFFFFFF0000FFFF) | ((u64)val << 16); return;
case W_USCount2: UpdateTimers(); USCounter = (USCounter & 0xFFFF0000FFFFFFFF) | ((u64)val << 32); return;
case W_USCount3: UpdateTimers(); USCounter = (USCounter & 0x0000FFFFFFFFFFFF) | ((u64)val << 48); return;
case W_USCompare0:
USCompare = (USCompare & 0xFFFFFFFFFFFF0000) | (u64)(val & 0xFC00);

View File

@ -151,6 +151,27 @@ enum
W_RXTXAddr = 0x268,
};
enum
{
Event_RXCheck = 0,
Event_IRQ15,
Event_MSTimer,
Event_PowerOn,
Event_MPClientSync,
Event_TRX,
Event_RF,
Event_BB,
Event_MAX
};
struct SchedEvent
{
void (*Func)(u32 param);
u64 Timestamp;
u32 Param;
};
extern bool MPInited;
@ -160,7 +181,7 @@ void DeInit();
void Reset();
void DoSavestate(Savestate* file);
void StartTX_Beacon();
void SetPowerCnt(u32 val);
void USTimer(u32 param);

View File

@ -115,6 +115,7 @@ bool MACIsBroadcast(u8* a)
}
// REMOVE ME!!
void USTimer()
{
USCounter++;