From 4a5a25e90c5ab0909a283df8a9cb10d9807f6e7a Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 18 Oct 2024 02:58:19 -0700 Subject: [PATCH] GBA DMA: Cache cycle estimation on first DMA --- include/mgba/internal/gba/dma.h | 2 ++ src/gba/audio.c | 1 + src/gba/dma.c | 35 ++++++++++++++++++++++++++++----- src/gba/io.c | 1 + src/gba/memory.c | 4 ++++ 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/include/mgba/internal/gba/dma.h b/include/mgba/internal/gba/dma.h index 192b3995a..58d590948 100644 --- a/include/mgba/internal/gba/dma.h +++ b/include/mgba/internal/gba/dma.h @@ -48,6 +48,7 @@ struct GBADMA { uint32_t nextDest; int32_t nextCount; uint32_t when; + int32_t cycles; }; struct GBA; @@ -65,6 +66,7 @@ void GBADMARunHblank(struct GBA* gba, int32_t cycles); void GBADMARunVblank(struct GBA* gba, int32_t cycles); void GBADMARunDisplayStart(struct GBA* gba, int32_t cycles); void GBADMAUpdate(struct GBA* gba); +void GBADMARecalculateCycles(struct GBA* gba); CXX_GUARD_END diff --git a/src/gba/audio.c b/src/gba/audio.c index a6ebafbae..ac394e995 100644 --- a/src/gba/audio.c +++ b/src/gba/audio.c @@ -309,6 +309,7 @@ void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId, int32_t cycles) { if (GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_CUSTOM) { dma->when = mTimingCurrentTime(&audio->p->timing) - cycles; dma->nextCount = 4; + GBADMARecalculateCycles(audio->p); GBADMASchedule(audio->p, channel->dmaSource, dma); } } diff --git a/src/gba/dma.c b/src/gba/dma.c index 290341361..5971b1b03 100644 --- a/src/gba/dma.c +++ b/src/gba/dma.c @@ -256,15 +256,21 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { if (info->count == info->nextCount) { if (width == 4) { cycles += memory->waitstatesNonseq32[sourceRegion] + memory->waitstatesNonseq32[destRegion]; + info->cycles = memory->waitstatesSeq32[sourceRegion] + memory->waitstatesSeq32[destRegion]; } else { cycles += memory->waitstatesNonseq16[sourceRegion] + memory->waitstatesNonseq16[destRegion]; + info->cycles = memory->waitstatesSeq16[sourceRegion] + memory->waitstatesSeq16[destRegion]; } } else { - if (width == 4) { - cycles += memory->waitstatesSeq32[sourceRegion] + memory->waitstatesSeq32[destRegion]; - } else { - cycles += memory->waitstatesSeq16[sourceRegion] + memory->waitstatesSeq16[destRegion]; + // Crossed region boundary; recalculate cached cycles + if (UNLIKELY(!(source & 0x00FFFFFC) || !(dest & 0x00FFFFFC))) { + if (width == 4) { + info->cycles = memory->waitstatesSeq32[sourceRegion] + memory->waitstatesSeq32[destRegion]; + } else { + info->cycles = memory->waitstatesSeq16[sourceRegion] + memory->waitstatesSeq16[destRegion]; + } } + cycles += info->cycles; } info->when += cycles; @@ -281,7 +287,7 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { memory->dmaTransferRegister = cpu->memory.load16(cpu, source, 0); memory->dmaTransferRegister |= memory->dmaTransferRegister << 16; } - if (destRegion == GBA_REGION_ROM2_EX) { + if (UNLIKELY(destRegion == GBA_REGION_ROM2_EX)) { if (memory->savedata.type == GBA_SAVEDATA_AUTODETECT) { mLOG(GBA_MEM, INFO, "Detected EEPROM savegame"); GBASavedataInitEEPROM(&memory->savedata); @@ -327,3 +333,22 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { } GBADMAUpdate(gba); } + +void GBADMARecalculateCycles(struct GBA* gba) { + int i; + for (i = 0; i < 4; ++i) { + struct GBADMA* dma = &gba->memory.dma[i]; + if (!GBADMARegisterIsEnable(dma->reg)) { + continue; + } + + uint32_t width = GBADMARegisterGetWidth(dma->reg); + uint32_t sourceRegion = dma->nextSource >> BASE_OFFSET; + uint32_t destRegion = dma->nextDest >> BASE_OFFSET; + if (width) { + dma->cycles = gba->memory.waitstatesSeq32[sourceRegion] + gba->memory.waitstatesSeq32[destRegion]; + } else { + dma->cycles = gba->memory.waitstatesSeq16[sourceRegion] + gba->memory.waitstatesSeq16[destRegion]; + } + } +} diff --git a/src/gba/io.c b/src/gba/io.c index 8a4ea7fc2..cb6058f7f 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -1079,6 +1079,7 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) { LOAD_32(gba->dmaPC, 0, &state->dmaBlockPC); LOAD_32(gba->bus, 0, &state->bus); + GBADMARecalculateCycles(gba); GBADMAUpdate(gba); GBAHardwareDeserialize(&gba->memory.hw, state); } diff --git a/src/gba/memory.c b/src/gba/memory.c index 3243fc5a1..c818c75c8 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -1734,6 +1734,10 @@ void GBAAdjustWaitstates(struct GBA* gba, uint16_t parameters) { STORE_32(memory->agbPrintFuncBackup, AGB_PRINT_FLUSH_ADDR | base, memory->rom); } } + + if (gba->performingDMA) { + GBADMARecalculateCycles(gba); + } } void GBAAdjustEWRAMWaitstates(struct GBA* gba, uint16_t parameters) {