GBA DMA: Cache cycle estimation on first DMA

This commit is contained in:
Vicki Pfau 2024-10-18 02:58:19 -07:00
parent afff68cfc0
commit 4a5a25e90c
5 changed files with 38 additions and 5 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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) {