GBA SIO: Convert to mTiming
@@ -184,6 +184,7 @@ GBASavedataUnmask(&gba->memory.savedata);
} gba->cpuBlocked = false; + gba->earlyExit = false; if (gba->yankedRomSize) { gba->memory.romSize = gba->yankedRomSize; gba->memory.romMask = toPow2(gba->memory.romSize) - 1;@@ -238,7 +239,6 @@
int32_t nextEvent = cpu->nextEvent; while (cpu->cycles >= nextEvent) { int32_t cycles = cpu->cycles; - int32_t testEvent; cpu->cycles = 0; cpu->nextEvent = INT_MAX;@@ -253,14 +253,10 @@ do {
nextEvent = mTimingTick(&gba->timing, nextEvent); } while (gba->cpuBlocked); - testEvent = GBASIOProcessEvents(&gba->sio, cycles); - if (testEvent < nextEvent) { - nextEvent = testEvent; - } - cpu->nextEvent = nextEvent; - if (nextEvent == 0) { + if (gba->earlyExit) { + gba->earlyExit = false; break; } if (cpu->halted) {
@@ -106,6 +106,7 @@ uint32_t idleLoop;
uint32_t lastJump; bool haltPending; bool cpuBlocked; + bool earlyExit; int idleDetectionStep; int idleDetectionFailures; int32_t cachedRegisters[16];
@@ -174,10 +174,3 @@ return sio->activeDriver->writeRegister(sio->activeDriver, address, value);
} return value; } - -int32_t GBASIOProcessEvents(struct GBASIO* sio, int32_t cycles) { - if (sio->activeDriver && sio->activeDriver->processEvents) { - return sio->activeDriver->processEvents(sio->activeDriver, cycles); - } - return INT_MAX; -}
@@ -78,6 +78,4 @@ void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value);
void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value); uint16_t GBASIOWriteRegister(struct GBASIO* sio, uint32_t address, uint16_t value); -int32_t GBASIOProcessEvents(struct GBASIO* sio, int32_t cycles); - #endif
@@ -17,8 +17,7 @@ static bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver);
static bool GBASIOLockstepNodeUnload(struct GBASIODriver* driver); static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value); static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value); -static int32_t GBASIOLockstepNodeProcessEvents(struct GBASIODriver* driver, int32_t cycles); -static int32_t GBASIOLockstepNodeProcessEvents(struct GBASIODriver* driver, int32_t cycles); +static void _GBASIOLockstepNodeProcessEvents(struct mTiming* timing, void* driver, uint32_t cyclesLate); void GBASIOLockstepInit(struct GBASIOLockstep* lockstep) { lockstep->players[0] = 0;@@ -47,7 +46,6 @@ node->d.deinit = GBASIOLockstepNodeDeinit;
node->d.load = GBASIOLockstepNodeLoad; node->d.unload = GBASIOLockstepNodeUnload; node->d.writeRegister = 0; - node->d.processEvents = GBASIOLockstepNodeProcessEvents; } bool GBASIOLockstepAttachNode(struct GBASIOLockstep* lockstep, struct GBASIOLockstepNode* node) {@@ -83,6 +81,9 @@ bool GBASIOLockstepNodeInit(struct GBASIODriver* driver) {
struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; node->d.p->multiplayerControl.slave = node->id > 0; mLOG(GBA_SIO, DEBUG, "Lockstep %i: Node init", node->id); + node->event.context = node; + node->event.name = "GBA SIO Lockstep"; + node->event.callback = _GBASIOLockstepNodeProcessEvents; return true; }@@ -94,6 +95,7 @@ bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver) {
struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; node->nextEvent = 0; node->eventDiff = 0; + mTimingSchedule(&driver->p->p->timing, &node->event, 0); node->mode = driver->p->mode; switch (node->mode) { case SIO_MULTI:@@ -130,6 +132,7 @@ default:
break; } node->p->unload(node->p, node->id); + mTimingDeschedule(&driver->p->p->timing, &node->event); return true; }@@ -142,7 +145,8 @@ if (!node->id && node->d.p->multiplayerControl.ready) {
mLOG(GBA_SIO, DEBUG, "Lockstep %i: Transfer initiated", node->id); node->p->transferActive = TRANSFER_STARTING; node->p->transferCycles = GBASIOCyclesPerTransfer[node->d.p->multiplayerControl.baud][node->p->attached - 1]; - node->nextEvent = 0; + mTimingDeschedule(&driver->p->p->timing, &node->event); + mTimingSchedule(&driver->p->p->timing, &node->event, 0); } else { value &= ~0x0080; }@@ -332,28 +336,33 @@ }
return 0; } -static int32_t GBASIOLockstepNodeProcessEvents(struct GBASIODriver* driver, int32_t cycles) { - struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; +static void _GBASIOLockstepNodeProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) { + struct GBASIOLockstepNode* node = user; if (node->p->attached < 2) { - return INT_MAX; + return; } - node->eventDiff += cycles; - node->nextEvent -= cycles; + int32_t cycles = 0; + node->nextEvent -= cyclesLate; if (node->nextEvent <= 0) { if (!node->id) { cycles = _masterUpdate(node); } else { cycles = _slaveUpdate(node); - node->nextEvent += node->p->useCycles(node->p, node->id, node->eventDiff); + cycles += node->p->useCycles(node->p, node->id, node->eventDiff); } node->eventDiff = 0; } else { cycles = node->nextEvent; } - if (cycles < 0) { - return 0; + if (cycles > 0) { + node->nextEvent = 0; + node->eventDiff += cycles; + mTimingDeschedule(timing, &node->event); + mTimingSchedule(timing, &node->event, cycles); + } else { + node->d.p->p->earlyExit = true; + mTimingSchedule(timing, &node->event, cyclesLate + 1); } - return cycles; } static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
@@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef SIO_LOCKSTEP_H #define SIO_LOCKSTEP_H +#include "core/timing.h" #include "gba/sio.h" enum GBASIOLockstepPhase {@@ -41,6 +42,7 @@
struct GBASIOLockstepNode { struct GBASIODriver d; struct GBASIOLockstep* p; + struct mTimingEvent event; volatile int32_t nextEvent; int32_t eventDiff;