From c056acb98fa851bd6f92ed0bf634217bfd02831a Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 7 Oct 2016 12:29:10 -0700 Subject: [PATCH] GBA Memory: Convert DMAs to mTiming --- src/gba/gba.c | 31 ++++++++++---------------- src/gba/gba.h | 1 + src/gba/memory.c | 57 ++++++++++++++++++++++++++---------------------- src/gba/memory.h | 6 ++--- 4 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/gba/gba.c b/src/gba/gba.c index 4c875ace6..aaf2849c0 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -183,6 +183,7 @@ void GBAReset(struct ARMCore* cpu) { GBASavedataUnmask(&gba->memory.savedata); } + gba->cpuBlocked = false; if (gba->yankedRomSize) { gba->memory.romSize = gba->yankedRomSize; gba->memory.romMask = toPow2(gba->memory.romSize) - 1; @@ -234,9 +235,9 @@ static void GBAProcessEvents(struct ARMCore* cpu) { gba->springIRQ = 0; } + int32_t nextEvent; do { int32_t cycles = cpu->cycles; - int32_t nextEvent; int32_t testEvent; cpu->cycles = 0; @@ -247,9 +248,11 @@ static void GBAProcessEvents(struct ARMCore* cpu) { mLOG(GBA, FATAL, "Negative cycles passed: %i", cycles); } #endif - - mTimingTick(&gba->timing, cycles); - nextEvent = cpu->nextEvent; + nextEvent = cycles; + do { + mTimingTick(&gba->timing, nextEvent); + nextEvent = cpu->nextEvent; + } while (gba->cpuBlocked); testEvent = GBAVideoProcessEvents(&gba->video, cycles); if (testEvent < nextEvent) { @@ -271,16 +274,6 @@ static void GBAProcessEvents(struct ARMCore* cpu) { nextEvent = testEvent; } - testEvent = GBAMemoryRunDMAs(gba, cycles); - if (testEvent < nextEvent) { -#ifndef NDEBUG - if (testEvent == 0) { - mLOG(GBA, ERROR, "DMAs requiring 0 cycles"); - } -#endif - nextEvent = testEvent; - } - testEvent = GBASIOProcessEvents(&gba->sio, cycles); if (testEvent < nextEvent) { nextEvent = testEvent; @@ -288,21 +281,21 @@ static void GBAProcessEvents(struct ARMCore* cpu) { cpu->nextEvent = nextEvent; + if (nextEvent == 0) { + break; + } if (cpu->halted) { - cpu->cycles = cpu->nextEvent; + cpu->cycles = nextEvent; if (!gba->memory.io[REG_IME >> 1] || !gba->memory.io[REG_IE >> 1]) { break; } } - if (nextEvent == 0) { - break; - } #ifndef NDEBUG else if (nextEvent < 0) { mLOG(GBA, FATAL, "Negative cycles will pass: %i", nextEvent); } #endif - } while (cpu->cycles >= cpu->nextEvent); + } while (cpu->cycles >= nextEvent); } void GBAAttachDebugger(struct GBA* gba, struct mDebugger* debugger) { diff --git a/src/gba/gba.h b/src/gba/gba.h index 571b28d0f..8ff475fab 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -105,6 +105,7 @@ struct GBA { uint32_t idleLoop; uint32_t lastJump; bool haltPending; + bool cpuBlocked; int idleDetectionStep; int idleDetectionFailures; int32_t cachedRegisters[16]; diff --git a/src/gba/memory.c b/src/gba/memory.c index 2bf4a4cba..c800b3a3d 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -19,6 +19,7 @@ mLOG_DEFINE_CATEGORY(GBA_MEM, "GBA Memory"); static void _pristineCow(struct GBA* gba); +static void _dmaEvent(struct mTiming* timing, void* context, uint32_t cyclesLate); static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t region); @@ -83,6 +84,10 @@ void GBAMemoryInit(struct GBA* gba) { gba->memory.biosPrefetch = 0; gba->memory.mirroring = false; + gba->memory.dmaEvent.name = "GBA DMA"; + gba->memory.dmaEvent.callback = _dmaEvent; + gba->memory.dmaEvent.context = gba; + GBAVFameInit(&gba->memory.vfame); } @@ -123,8 +128,6 @@ void GBAMemoryReset(struct GBA* gba) { } gba->memory.dma[3].count = 0x10000; gba->memory.activeDMA = -1; - gba->memory.nextDMA = INT_MAX; - gba->memory.eventDiff = 0; gba->memory.prefetch = false; gba->memory.lastPrefetchedPc = 0; @@ -1549,10 +1552,10 @@ uint16_t GBAMemoryWriteDMACNT_HI(struct GBA* gba, int dma, uint16_t control) { }; void GBAMemoryScheduleDMA(struct GBA* gba, int number, struct GBADMA* info) { - struct ARMCore* cpu = gba->cpu; + info->hasStarted = 0; switch (GBADMARegisterGetTiming(info->reg)) { case DMA_TIMING_NOW: - info->nextEvent = cpu->cycles + 2; + info->nextEvent = 2; GBAMemoryUpdateDMAs(gba, -1); break; case DMA_TIMING_HBLANK: @@ -1587,7 +1590,7 @@ void GBAMemoryRunHblankDMAs(struct GBA* gba, int32_t cycles) { for (i = 0; i < 4; ++i) { dma = &memory->dma[i]; if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_HBLANK) { - dma->nextEvent = cycles; + dma->nextEvent = 2 + cycles; } } GBAMemoryUpdateDMAs(gba, 0); @@ -1600,46 +1603,40 @@ void GBAMemoryRunVblankDMAs(struct GBA* gba, int32_t cycles) { for (i = 0; i < 4; ++i) { dma = &memory->dma[i]; if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_VBLANK) { - dma->nextEvent = cycles; + dma->nextEvent = 2 + cycles; } } GBAMemoryUpdateDMAs(gba, 0); } -int32_t GBAMemoryRunDMAs(struct GBA* gba, int32_t cycles) { +void _dmaEvent(struct mTiming* timing, void* context, uint32_t cyclesLate) { + UNUSED(timing); + struct GBA* gba = context; struct GBAMemory* memory = &gba->memory; - if (memory->nextDMA == INT_MAX) { - return INT_MAX; - } - memory->nextDMA -= cycles; - memory->eventDiff += cycles; - while (memory->nextDMA <= 0) { - struct GBADMA* dma = &memory->dma[memory->activeDMA]; - GBAMemoryServiceDMA(gba, memory->activeDMA, dma); - GBAMemoryUpdateDMAs(gba, memory->eventDiff); - memory->eventDiff = 0; - } - return memory->nextDMA; + struct GBADMA* dma = &memory->dma[memory->activeDMA]; + dma->nextEvent = -cyclesLate; + GBAMemoryServiceDMA(gba, memory->activeDMA, dma); } void GBAMemoryUpdateDMAs(struct GBA* gba, int32_t cycles) { int i; struct GBAMemory* memory = &gba->memory; - struct ARMCore* cpu = gba->cpu; memory->activeDMA = -1; - memory->nextDMA = INT_MAX; for (i = 3; i >= 0; --i) { struct GBADMA* dma = &memory->dma[i]; if (dma->nextEvent != INT_MAX) { dma->nextEvent -= cycles; if (GBADMARegisterIsEnable(dma->reg)) { memory->activeDMA = i; - memory->nextDMA = dma->nextEvent; } } } - if (memory->nextDMA < cpu->nextEvent) { - cpu->nextEvent = memory->nextDMA; + + if (memory->activeDMA >= 0) { + mTimingDeschedule(&gba->timing, &memory->dmaEvent); + mTimingSchedule(&gba->timing, &memory->dmaEvent, memory->dma[memory->activeDMA].nextEvent); + } else { + gba->cpuBlocked = false; } } @@ -1656,7 +1653,8 @@ void GBAMemoryServiceDMA(struct GBA* gba, int number, struct GBADMA* info) { uint32_t destRegion = dest >> BASE_OFFSET; int32_t cycles = 2; - if (source == info->source && dest == info->dest && wordsRemaining == info->count) { + gba->cpuBlocked = true; + if (info->hasStarted < 2) { if (sourceRegion < REGION_CART0 || destRegion < REGION_CART0) { cycles += 2; } @@ -1667,6 +1665,13 @@ void GBAMemoryServiceDMA(struct GBA* gba, int number, struct GBADMA* info) { } else { cycles += memory->waitstatesNonseq16[sourceRegion] + memory->waitstatesNonseq16[destRegion]; } + if (info->hasStarted < 1) { + info->hasStarted = wordsRemaining; + info->nextEvent = 0; + GBAMemoryUpdateDMAs(gba, -cycles); + return; + } + info->hasStarted = 2; } else { if (width == 4) { cycles += memory->waitstatesSeq32[sourceRegion] + memory->waitstatesSeq32[destRegion]; @@ -1740,7 +1745,7 @@ void GBAMemoryServiceDMA(struct GBA* gba, int number, struct GBADMA* info) { if (info->nextEvent != INT_MAX) { info->nextEvent += cycles; } - cpu->cycles += cycles; + GBAMemoryUpdateDMAs(gba, 0); } int32_t GBAMemoryStall(struct ARMCore* cpu, int32_t wait) { diff --git a/src/gba/memory.h b/src/gba/memory.h index de3bba160..bffa61374 100644 --- a/src/gba/memory.h +++ b/src/gba/memory.h @@ -9,6 +9,7 @@ #include "util/common.h" #include "arm/arm.h" +#include "core/timing.h" #include "gba/hardware.h" #include "gba/savedata.h" @@ -108,6 +109,7 @@ struct GBADMA { uint32_t nextDest; int32_t nextCount; int32_t nextEvent; + int32_t hasStarted; }; struct GBAMemory { @@ -139,9 +141,8 @@ struct GBAMemory { uint32_t biosPrefetch; struct GBADMA dma[4]; + struct mTimingEvent dmaEvent; int activeDMA; - int32_t nextDMA; - int32_t eventDiff; bool mirroring; }; @@ -185,7 +186,6 @@ void GBAMemoryScheduleDMA(struct GBA* gba, int number, struct GBADMA* info); void GBAMemoryRunHblankDMAs(struct GBA* gba, int32_t cycles); void GBAMemoryRunVblankDMAs(struct GBA* gba, int32_t cycles); void GBAMemoryUpdateDMAs(struct GBA* gba, int32_t cycles); -int32_t GBAMemoryRunDMAs(struct GBA* gba, int32_t cycles); struct GBASerializedState; void GBAMemorySerialize(const struct GBAMemory* memory, struct GBASerializedState* state);