diff --git a/CHANGES b/CHANGES index c7c94ee4c..3d0f61df1 100644 --- a/CHANGES +++ b/CHANGES @@ -35,6 +35,7 @@ Misc: - 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: diff --git a/include/mgba/internal/gba/gba.h b/include/mgba/internal/gba/gba.h index 4bd899fe6..f1b3fa2f5 100644 --- a/include/mgba/internal/gba/gba.h +++ b/include/mgba/internal/gba/gba.h @@ -143,8 +143,8 @@ void GBADestroy(struct GBA* gba); 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); diff --git a/src/gba/dma.c b/src/gba/dma.c index eb66635c4..7ab7a85c7 100644 --- a/src/gba/dma.c +++ b/src/gba/dma.c @@ -193,7 +193,7 @@ void _dmaEvent(struct mTiming* timing, void* context, uint32_t cyclesLate) { dma->nextDest = dma->dest; } if (GBADMARegisterIsDoIRQ(dma->reg)) { - GBARaiseIRQ(gba, IRQ_DMA0 + memory->activeDMA); + GBARaiseIRQ(gba, IRQ_DMA0 + memory->activeDMA, cyclesLate); } GBADMAUpdate(gba); } diff --git a/src/gba/extra/battlechip.c b/src/gba/extra/battlechip.c index 94d591efa..b76247cd0 100644 --- a/src/gba/extra/battlechip.c +++ b/src/gba/extra/battlechip.c @@ -101,7 +101,7 @@ void _battlechipTransferEvent(struct mTiming* timing, void* user, uint32_t cycle 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 @@ void _battlechipTransferEvent(struct mTiming* timing, void* user, uint32_t cycle 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); } } diff --git a/src/gba/gba.c b/src/gba/gba.c index 357910767..e144ce45a 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -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 @@ void GBAInterruptHandlerInit(struct ARMInterruptHandler* irqh) { 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 @@ void GBAApplyPatch(struct GBA* gba, struct Patch* patch) { 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 @@ void GBATestKeypadIRQ(struct GBA* gba) { 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); } } diff --git a/src/gba/hardware.c b/src/gba/hardware.c index e981a9649..c2c19d50e 100644 --- a/src/gba/hardware.c +++ b/src/gba/hardware.c @@ -585,7 +585,7 @@ void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLat 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; diff --git a/src/gba/io.c b/src/gba/io.c index c3561dd50..7b7c4ba3a 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -548,16 +548,16 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t 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 diff --git a/src/gba/sio.c b/src/gba/sio.c index 800af8aea..95e860363 100644 --- a/src/gba/sio.c +++ b/src/gba/sio.c @@ -158,7 +158,7 @@ void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) { 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; } diff --git a/src/gba/sio/joybus.c b/src/gba/sio/joybus.c index e7aa934e6..8d6fc2d77 100644 --- a/src/gba/sio/joybus.c +++ b/src/gba/sio/joybus.c @@ -37,7 +37,7 @@ int GBASIOJOYSendCommand(struct GBASIODriver* sio, enum GBASIOJOYCommand 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 @@ int GBASIOJOYSendCommand(struct GBASIODriver* sio, enum GBASIOJOYCommand command 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 @@ int GBASIOJOYSendCommand(struct GBASIODriver* sio, enum GBASIOJOYCommand command 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; } diff --git a/src/gba/sio/lockstep.c b/src/gba/sio/lockstep.c index c196fc3fa..848dc9b4d 100644 --- a/src/gba/sio/lockstep.c +++ b/src/gba/sio/lockstep.c @@ -166,7 +166,7 @@ static void _finishTransfer(struct GBASIOLockstepNode* node) { 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 @@ static void _finishTransfer(struct GBASIOLockstepNode* node) { 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 @@ static void _finishTransfer(struct GBASIOLockstepNode* node) { 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: diff --git a/src/gba/timer.c b/src/gba/timer.c index c0a6fb81d..9e097eff6 100644 --- a/src/gba/timer.c +++ b/src/gba/timer.c @@ -22,7 +22,7 @@ static void GBATimerUpdate(struct GBA* gba, int timerId, uint32_t cyclesLate) { } if (GBATimerFlagsIsDoIrq(timer->flags)) { - GBARaiseIRQ(gba, IRQ_TIMER0 + timerId); + GBARaiseIRQ(gba, IRQ_TIMER0 + timerId, cyclesLate); } if (gba->audio.enable && timerId < 2) { diff --git a/src/gba/video.c b/src/gba/video.c index ade66932a..ee9a8306c 100644 --- a/src/gba/video.c +++ b/src/gba/video.c @@ -133,7 +133,7 @@ void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) { 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 @@ void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) { } 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 @@ void _startHblank(struct mTiming* timing, void* context, uint32_t cyclesLate) { 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; }