diff --git a/src/gb/gb.c b/src/gb/gb.c index 9d85b02e2..bd2726e70 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -425,6 +425,7 @@ void GBReset(struct LR35902Core* cpu) { cpu->pc = 0x100; } + gb->cpuBlocked = false; gb->eiPending = INT_MAX; gb->doubleSpeed = 0; @@ -546,7 +547,11 @@ void GBProcessEvents(struct LR35902Core* cpu) { } } - cpu->nextEvent = mTimingTick(&gb->timing, cycles); + nextEvent = cycles; + do { + nextEvent = mTimingTick(&gb->timing, nextEvent); + } while (gb->cpuBlocked); + cpu->nextEvent = nextEvent; if (cpu->halted) { cpu->cycles = cpu->nextEvent; diff --git a/src/gb/gb.h b/src/gb/gb.h index 584ce4bba..2ec4a3234 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -78,6 +78,7 @@ struct GB { struct mCoreCallbacks* coreCallbacks; struct mAVStream* stream; + bool cpuBlocked; int32_t eiPending; unsigned doubleSpeed; }; diff --git a/src/gb/memory.c b/src/gb/memory.c index ebcd107b5..1fb24f1cf 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -381,6 +381,7 @@ void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) { gb->memory.isHdma = value & 0x80; if ((!wasHdma && !gb->memory.isHdma) || gb->video.mode == 0) { gb->memory.hdmaRemaining = ((value & 0x7F) + 1) * 0x10; + gb->cpuBlocked = true; mTimingSchedule(&gb->timing, &gb->memory.hdmaEvent, 0); gb->cpu->nextEvent = gb->cpu->cycles; } @@ -404,14 +405,17 @@ void _GBMemoryDMAService(struct mTiming* timing, void* context, uint32_t cyclesL void _GBMemoryHDMAService(struct mTiming* timing, void* context, uint32_t cyclesLate) { struct GB* gb = context; + gb->cpuBlocked = true; uint8_t b = gb->cpu->memory.load8(gb->cpu, gb->memory.hdmaSource); gb->cpu->memory.store8(gb->cpu, gb->memory.hdmaDest, b); ++gb->memory.hdmaSource; ++gb->memory.hdmaDest; --gb->memory.hdmaRemaining; if (gb->memory.hdmaRemaining) { + mTimingDeschedule(timing, &gb->memory.hdmaEvent); mTimingSchedule(timing, &gb->memory.hdmaEvent, 2 - cyclesLate); } else { + gb->cpuBlocked = false; gb->memory.io[REG_HDMA1] = gb->memory.hdmaSource >> 8; gb->memory.io[REG_HDMA2] = gb->memory.hdmaSource; gb->memory.io[REG_HDMA3] = gb->memory.hdmaDest >> 8; @@ -425,7 +429,6 @@ void _GBMemoryHDMAService(struct mTiming* timing, void* context, uint32_t cycles gb->memory.io[REG_HDMA5] = 0xFF; } } - gb->cpu->cycles += 2; } struct OAMBlock { diff --git a/src/gb/video.c b/src/gb/video.c index b54d96d1e..ef8bb95c5 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -206,6 +206,7 @@ void _endMode3(struct mTiming* timing, void* context, uint32_t cyclesLate) { } if (video->ly < GB_VIDEO_VERTICAL_PIXELS && video->p->memory.isHdma && video->p->memory.io[REG_HDMA5] != 0xFF) { video->p->memory.hdmaRemaining = 0x10; + mTimingDeschedule(timing, &video->p->memory.hdmaEvent); mTimingSchedule(timing, &video->p->memory.hdmaEvent, 0); } video->mode = 0;