GBA DMA: Remove `hasStarted` flag
Jeffrey Pfau jeffrey@endrift.com
Mon, 19 Dec 2016 16:55:47 -0800
2 files changed,
33 insertions(+),
36 deletions(-)
M
src/gba/dma.c
→
src/gba/dma.c
@@ -91,7 +91,7 @@
void GBADMASchedule(struct GBA* gba, int number, struct GBADMA* info) { switch (GBADMARegisterGetTiming(info->reg)) { case DMA_TIMING_NOW: - info->when = mTimingCurrentTime(&gba->timing) + 2 + 1; // XXX: Account for I cycle when writing + info->when = mTimingCurrentTime(&gba->timing) + 3; // DMAs take 3 cycles to start info->nextCount = info->count; break; case DMA_TIMING_HBLANK:@@ -121,8 +121,8 @@ struct GBADMA* dma;
int i; for (i = 0; i < 4; ++i) { dma = &memory->dma[i]; - if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_HBLANK && !dma->hasStarted) { - dma->when = mTimingCurrentTime(&gba->timing) + 2 + cycles; + if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_HBLANK && !dma->nextCount) { + dma->when = mTimingCurrentTime(&gba->timing) + 3 + cycles; dma->nextCount = dma->count; } }@@ -135,8 +135,8 @@ struct GBADMA* dma;
int i; for (i = 0; i < 4; ++i) { dma = &memory->dma[i]; - if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_VBLANK && !dma->hasStarted) { - dma->when = mTimingCurrentTime(&gba->timing) + 2 + cycles; + if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_VBLANK && !dma->nextCount) { + dma->when = mTimingCurrentTime(&gba->timing) + 3 + cycles; dma->nextCount = dma->count; } }@@ -149,7 +149,27 @@ UNUSED(cyclesLate);
struct GBA* gba = context; struct GBAMemory* memory = &gba->memory; struct GBADMA* dma = &memory->dma[memory->activeDMA]; - GBADMAService(gba, memory->activeDMA, dma); + if (dma->nextCount == dma->count) { + dma->when = mTimingCurrentTime(&gba->timing); + } + if (dma->nextCount & 0xFFFFF) { + GBADMAService(gba, memory->activeDMA, dma); + } else { + dma->nextCount = 0; + if (!GBADMARegisterIsRepeat(dma->reg) || GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_NOW) { + dma->reg = GBADMARegisterClearEnable(dma->reg); + + // Clear the enable bit in memory + memory->io[(REG_DMA0CNT_HI + memory->activeDMA * (REG_DMA1CNT_HI - REG_DMA0CNT_HI)) >> 1] &= 0x7FE0; + } + if (GBADMARegisterGetDestControl(dma->reg) == DMA_INCREMENT_RELOAD) { + dma->nextDest = dma->dest; + } + if (GBADMARegisterIsDoIRQ(dma->reg)) { + GBARaiseIRQ(gba, IRQ_DMA0 + memory->activeDMA); + } + GBADMAUpdate(gba); + } } void GBADMAUpdate(struct GBA* gba) {@@ -157,13 +177,11 @@ int i;
struct GBAMemory* memory = &gba->memory; memory->activeDMA = -1; uint32_t currentTime = mTimingCurrentTime(&gba->timing); - for (i = 3; i >= 0; --i) { + for (i = 0; i < 4; ++i) { struct GBADMA* dma = &memory->dma[i]; if (GBADMARegisterIsEnable(dma->reg) && dma->nextCount) { - if (dma->when < currentTime) { - dma->when = currentTime; - } memory->activeDMA = i; + break; } }@@ -187,7 +205,7 @@ uint32_t destRegion = dest >> BASE_OFFSET;
int32_t cycles = 2; gba->cpuBlocked = true; - if (info->hasStarted < 2) { + if (info->count == info->nextCount) { if (sourceRegion < REGION_CART0 || destRegion < REGION_CART0) { cycles += 2; }@@ -196,13 +214,6 @@ cycles += memory->waitstatesNonseq32[sourceRegion] + memory->waitstatesNonseq32[destRegion];
} else { cycles += memory->waitstatesNonseq16[sourceRegion] + memory->waitstatesNonseq16[destRegion]; } - if (info->hasStarted < 1) { - info->hasStarted = info->count << 1; - info->when = mTimingCurrentTime(&gba->timing) + cycles; - GBADMAUpdate(gba); - return; - } - info->hasStarted = 2; source &= -width; dest &= -width; } else {@@ -244,24 +255,11 @@ dest += destOffset;
--wordsRemaining; gba->performingDMA = 0; - if (!wordsRemaining) { - info->hasStarted = 0; - if (!GBADMARegisterIsRepeat(info->reg) || GBADMARegisterGetTiming(info->reg) == DMA_TIMING_NOW) { - info->reg = GBADMARegisterClearEnable(info->reg); - - // Clear the enable bit in memory - memory->io[(REG_DMA0CNT_HI + number * (REG_DMA1CNT_HI - REG_DMA0CNT_HI)) >> 1] &= 0x7FE0; - } - if (GBADMARegisterGetDestControl(info->reg) == DMA_INCREMENT_RELOAD) { - info->nextDest = info->dest; - } - if (GBADMARegisterIsDoIRQ(info->reg)) { - GBARaiseIRQ(gba, IRQ_DMA0 + number); - } - } else { - info->nextDest = dest; - } info->nextCount = wordsRemaining; info->nextSource = source; + info->nextDest = dest; + if (!wordsRemaining) { + info->nextCount |= 0x80000000; + } GBADMAUpdate(gba); }
M
src/gba/memory.h
→
src/gba/memory.h
@@ -109,7 +109,6 @@ uint32_t nextSource;
uint32_t nextDest; int32_t nextCount; uint32_t when; - int32_t hasStarted; }; struct GBAMemory {