GBA: Improve delayed IRQ timing
@@ -35,6 +35,7 @@ - Qt: Don't unload ROM immediately if it crashes
- GBA Video: Improve sprite cycle counting (fixes mgba.io/i/1274) - Debugger: Add breakpoint and watchpoint listing - Qt: Updated Italian translation (by Vecna) + - GBA: Improve delayed IRQ timing 0.7.0: (2019-01-26) Features:
@@ -143,8 +143,8 @@
void GBAReset(struct ARMCore* cpu); void GBASkipBIOS(struct GBA* gba); -void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq); -void GBATestIRQ(struct ARMCore* cpu); +void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq, uint32_t cyclesLate); +void GBATestIRQ(struct GBA* gba, uint32_t cyclesLate); void GBAHalt(struct GBA* gba); void GBAStop(struct GBA* gba); void GBADebug(struct GBA* gba, uint16_t value);
@@ -193,7 +193,7 @@ if (GBADMARegisterGetDestControl(dma->reg) == GBA_DMA_INCREMENT_RELOAD) {
dma->nextDest = dma->dest; } if (GBADMARegisterIsDoIRQ(dma->reg)) { - GBARaiseIRQ(gba, IRQ_DMA0 + memory->activeDMA); + GBARaiseIRQ(gba, IRQ_DMA0 + memory->activeDMA, cyclesLate); } GBADMAUpdate(gba); }
@@ -101,7 +101,7 @@ gate->d.p->p->memory.io[REG_SIODATA32_LO >> 1] = 0;
gate->d.p->p->memory.io[REG_SIODATA32_HI >> 1] = 0; gate->d.p->normalControl.start = 0; if (gate->d.p->normalControl.irq) { - GBARaiseIRQ(gate->d.p->p, IRQ_SIO); + GBARaiseIRQ(gate->d.p->p, IRQ_SIO, cyclesLate); } return; }@@ -193,6 +193,6 @@
gate->d.p->p->memory.io[REG_SIOMULTI1 >> 1] = reply; if (gate->d.p->multiplayerControl.irq) { - GBARaiseIRQ(gate->d.p->p, IRQ_SIO); + GBARaiseIRQ(gate->d.p->p, IRQ_SIO, cyclesLate); } }
@@ -46,6 +46,7 @@ static void GBAProcessEvents(struct ARMCore* cpu);
static void GBAHitStub(struct ARMCore* cpu, uint32_t opcode); static void GBAIllegal(struct ARMCore* cpu, uint32_t opcode); static void GBABreakpoint(struct ARMCore* cpu, int immediate); +static void GBATestIRQNoDelay(struct ARMCore* cpu); static void _triggerIRQ(struct mTiming*, void* user, uint32_t cyclesLate);@@ -180,7 +181,7 @@ irqh->processEvents = GBAProcessEvents;
irqh->swi16 = GBASwi16; irqh->swi32 = GBASwi32; irqh->hitIllegal = GBAIllegal; - irqh->readCPSR = GBATestIRQ; + irqh->readCPSR = GBATestIRQNoDelay; irqh->hitStub = GBAHitStub; irqh->bkpt16 = GBABreakpoint; irqh->bkpt32 = GBABreakpoint;@@ -433,7 +434,7 @@ void GBAYankROM(struct GBA* gba) {
gba->yankedRomSize = gba->memory.romSize; gba->memory.romSize = 0; gba->memory.romMask = 0; - GBARaiseIRQ(gba, IRQ_GAMEPAK); + GBARaiseIRQ(gba, IRQ_GAMEPAK, 0); } void GBALoadBIOS(struct GBA* gba, struct VFile* vf) {@@ -486,16 +487,20 @@ gba->memory.romMask = SIZE_CART0 - 1;
gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize); } -void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq) { +void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq, uint32_t cyclesLate) { gba->memory.io[REG_IF >> 1] |= 1 << irq; - GBATestIRQ(gba->cpu); + GBATestIRQ(gba, cyclesLate); } -void GBATestIRQ(struct ARMCore* cpu) { +void GBATestIRQNoDelay(struct ARMCore* cpu) { struct GBA* gba = (struct GBA*) cpu->master; + GBATestIRQ(gba, 0); +} + +void GBATestIRQ(struct GBA* gba, uint32_t cyclesLate) { if (gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) { if (!mTimingIsScheduled(&gba->timing, &gba->irqEvent)) { - mTimingSchedule(&gba->timing, &gba->irqEvent, GBA_IRQ_DELAY); + mTimingSchedule(&gba->timing, &gba->irqEvent, GBA_IRQ_DELAY - cyclesLate); } } }@@ -846,9 +851,9 @@ keycnt &= 0x3FF;
uint16_t keyInput = *gba->keySource & keycnt; if (isAnd && keycnt == keyInput) { - GBARaiseIRQ(gba, IRQ_KEYPAD); + GBARaiseIRQ(gba, IRQ_KEYPAD, 0); } else if (!isAnd && keyInput) { - GBARaiseIRQ(gba, IRQ_KEYPAD); + GBARaiseIRQ(gba, IRQ_KEYPAD, 0); } }
@@ -585,7 +585,7 @@ ++gbp->p->gbpTxPosition;
gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] = tx; gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16; if (gbp->d.p->normalControl.irq) { - GBARaiseIRQ(gbp->p->p, IRQ_SIO); + GBARaiseIRQ(gbp->p->p, IRQ_SIO, cyclesLate); } gbp->d.p->normalControl.start = 0; gbp->p->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt & ~0x0080;
@@ -548,16 +548,16 @@ GBAAdjustWaitstates(gba, value);
break; case REG_IE: gba->memory.io[REG_IE >> 1] = value; - GBATestIRQ(gba->cpu); + GBATestIRQ(gba->cpu, 1); return; case REG_IF: value = gba->memory.io[REG_IF >> 1] & ~value; gba->memory.io[REG_IF >> 1] = value; - GBATestIRQ(gba->cpu); + GBATestIRQ(gba->cpu, 1); return; case REG_IME: gba->memory.io[REG_IME >> 1] = value; - GBATestIRQ(gba->cpu); + GBATestIRQ(gba->cpu, 1); return; case REG_MAX: // Some bad interrupt libraries will write to this
@@ -158,7 +158,7 @@ value |= 0x0004;
if ((value & 0x0081) == 0x0081) { if (value & 0x4000) { // TODO: Test this on hardware to see if this is correct - GBARaiseIRQ(sio->p, IRQ_SIO); + GBARaiseIRQ(sio->p, IRQ_SIO, 0); } value &= ~0x0080; }
@@ -37,7 +37,7 @@ switch (command) {
case JOY_RESET: sio->p->p->memory.io[REG_JOYCNT >> 1] |= 1; if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) { - GBARaiseIRQ(sio->p->p, IRQ_SIO); + GBARaiseIRQ(sio->p->p, IRQ_SIO, 0); } // Fall through case JOY_POLL:@@ -55,7 +55,7 @@
data[0] = sio->p->p->memory.io[REG_JOYSTAT >> 1]; if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) { - GBARaiseIRQ(sio->p->p, IRQ_SIO); + GBARaiseIRQ(sio->p->p, IRQ_SIO, 0); } return 1; case JOY_TRANS:@@ -68,7 +68,7 @@ data[3] = sio->p->p->memory.io[REG_JOY_TRANS_HI >> 1] >> 8;
data[4] = sio->p->p->memory.io[REG_JOYSTAT >> 1]; if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) { - GBARaiseIRQ(sio->p->p, IRQ_SIO); + GBARaiseIRQ(sio->p->p, IRQ_SIO, 0); } return 5; }
@@ -166,7 +166,7 @@ sio->rcnt |= 1;
sio->multiplayerControl.busy = 0; sio->multiplayerControl.id = node->id; if (sio->multiplayerControl.irq) { - GBARaiseIRQ(sio->p, IRQ_SIO); + GBARaiseIRQ(sio->p, IRQ_SIO, 0); } break; case SIO_NORMAL_8:@@ -179,7 +179,7 @@ } else {
node->d.p->p->memory.io[REG_SIODATA8 >> 1] = 0xFFFF; } if (sio->multiplayerControl.irq) { - GBARaiseIRQ(sio->p, IRQ_SIO); + GBARaiseIRQ(sio->p, IRQ_SIO, 0); } break; case SIO_NORMAL_32:@@ -194,7 +194,7 @@ node->d.p->p->memory.io[REG_SIODATA32_LO >> 1] = 0xFFFF;
node->d.p->p->memory.io[REG_SIODATA32_HI >> 1] = 0xFFFF; } if (sio->multiplayerControl.irq) { - GBARaiseIRQ(sio->p, IRQ_SIO); + GBARaiseIRQ(sio->p, IRQ_SIO, 0); } break; default:
@@ -22,7 +22,7 @@ GBATimerUpdateRegister(gba, timerId, TIMER_RELOAD_DELAY + cyclesLate);
} if (GBATimerFlagsIsDoIrq(timer->flags)) { - GBARaiseIRQ(gba, IRQ_TIMER0 + timerId); + GBARaiseIRQ(gba, IRQ_TIMER0 + timerId, cyclesLate); } if (gba->audio.enable && timerId < 2) {
@@ -133,7 +133,7 @@
if (video->vcount == GBARegisterDISPSTATGetVcountSetting(dispstat)) { dispstat = GBARegisterDISPSTATFillVcounter(dispstat); if (GBARegisterDISPSTATIsVcounterIRQ(dispstat)) { - GBARaiseIRQ(video->p, IRQ_VCOUNTER); + GBARaiseIRQ(video->p, IRQ_VCOUNTER, cyclesLate); } } else { dispstat = GBARegisterDISPSTATClearVcounter(dispstat);@@ -152,7 +152,7 @@ video->renderer->finishFrame(video->renderer);
} GBADMARunVblank(video->p, -cyclesLate); if (GBARegisterDISPSTATIsVblankIRQ(dispstat)) { - GBARaiseIRQ(video->p, IRQ_VBLANK); + GBARaiseIRQ(video->p, IRQ_VBLANK, cyclesLate); } GBAFrameEnded(video->p); mCoreSyncPostFrame(video->p->sync);@@ -188,7 +188,7 @@ if (video->vcount >= 2 && video->vcount < VIDEO_VERTICAL_PIXELS + 2) {
GBADMARunDisplayStart(video->p, -cyclesLate); } if (GBARegisterDISPSTATIsHblankIRQ(dispstat)) { - GBARaiseIRQ(video->p, IRQ_HBLANK); + GBARaiseIRQ(video->p, IRQ_HBLANK, cyclesLate); } video->p->memory.io[REG_DISPSTAT >> 1] = dispstat; }