all repos — mgba @ f9f105a8520813a5d6300bc082e5bf98d6c01d95

mGBA Game Boy Advance Emulator

GBA: Improve delayed IRQ timing
Vicki Pfau vi@endrift.com
Sun, 24 Feb 2019 00:28:49 -0800
commit

f9f105a8520813a5d6300bc082e5bf98d6c01d95

parent

cf0881534714464312cf38ef5f4ae7c00d2dceee

M CHANGESCHANGES

@@ -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:
M include/mgba/internal/gba/gba.hinclude/mgba/internal/gba/gba.h

@@ -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);
M src/gba/dma.csrc/gba/dma.c

@@ -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); }
M src/gba/extra/battlechip.csrc/gba/extra/battlechip.c

@@ -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); } }
M src/gba/gba.csrc/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 @@ 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); } }
M src/gba/hardware.csrc/gba/hardware.c

@@ -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;
M src/gba/io.csrc/gba/io.c

@@ -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
M src/gba/sio.csrc/gba/sio.c

@@ -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; }
M src/gba/sio/joybus.csrc/gba/sio/joybus.c

@@ -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; }
M src/gba/sio/lockstep.csrc/gba/sio/lockstep.c

@@ -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:
M src/gba/timer.csrc/gba/timer.c

@@ -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) {
M src/gba/video.csrc/gba/video.c

@@ -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; }