diff --git a/src/gba/gba-io.c b/src/gba/gba-io.c index 11552f3f5..640c67880 100644 --- a/src/gba/gba-io.c +++ b/src/gba/gba-io.c @@ -366,11 +366,23 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16)); break; + // TODO: Confirm this behavior on real hardware case REG_FIFO_A_LO: case REG_FIFO_B_LO: + if (gba->performingDMA) { + GBAAudioWriteFIFO16(&gba->audio, address, value); + } else { + GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value); + } + break; + case REG_FIFO_A_HI: case REG_FIFO_B_HI: - GBAAudioWriteFIFO16(&gba->audio, address, value); + if (gba->performingDMA) { + GBAAudioWriteFIFO16(&gba->audio, address, value); + } else { + GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16)); + } break; // DMA diff --git a/src/gba/gba-memory.c b/src/gba/gba-memory.c index 1405b9516..82508cd2f 100644 --- a/src/gba/gba-memory.c +++ b/src/gba/gba-memory.c @@ -172,7 +172,7 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { #define LOAD_BAD \ GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load32: 0x%08X", address); \ - if (cpu->cycles >= cpu->nextEvent) { \ + if (gba->performingDMA) { \ value = gba->bus; \ } else { \ value = cpu->prefetch[1]; \ @@ -301,7 +301,7 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { } } else { GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load16: 0x%08X", address); - if (cpu->cycles >= cpu->nextEvent) { + if (gba->performingDMA) { LOAD_16(value, address & 2, &gba->bus); } else { LOAD_16(value, address & 2, &cpu->prefetch[1]); @@ -363,7 +363,7 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { break; default: GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load16: 0x%08X", address); - if (cpu->cycles >= cpu->nextEvent) { + if (gba->performingDMA) { LOAD_16(value, address & 2, &gba->bus); } else { LOAD_16(value, address & 2, &cpu->prefetch[1]); @@ -396,7 +396,7 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { } } else { GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load8: 0x%08x", address); - if (cpu->cycles >= cpu->nextEvent) { + if (gba->performingDMA) { value = ((uint8_t*) &gba->bus)[address & 3]; } else { value = ((uint8_t*) &cpu->prefetch[1])[address & 3]; @@ -460,7 +460,7 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { break; default: GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load8: 0x%08x", address); - if (cpu->cycles >= cpu->nextEvent) { + if (gba->performingDMA) { value = ((uint8_t*) &gba->bus)[address & 3]; } else { value = ((uint8_t*) &cpu->prefetch[1])[address & 3]; @@ -1138,6 +1138,7 @@ void GBAMemoryServiceDMA(struct GBA* gba, int number, struct GBADMA* info) { } } + gba->performingDMA = true; int32_t word; if (width == 4) { word = cpu->memory.load32(cpu, source, 0); @@ -1174,6 +1175,7 @@ void GBAMemoryServiceDMA(struct GBA* gba, int number, struct GBADMA* info) { --wordsRemaining; } } + gba->performingDMA = false; if (!wordsRemaining) { if (!GBADMARegisterIsRepeat(info->reg) || GBADMARegisterGetTiming(info->reg) == DMA_TIMING_NOW) { diff --git a/src/gba/gba.c b/src/gba/gba.c index 1b5f39b7b..aca3af985 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -76,6 +76,7 @@ static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component) { gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS); gba->busyLoop = -1; + gba->performingDMA = false; } void GBADestroy(struct GBA* gba) { diff --git a/src/gba/gba.h b/src/gba/gba.h index a7b13ed3a..c518fdf8c 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -112,6 +112,7 @@ struct GBA { struct ARMDebugger* debugger; uint32_t bus; + bool performingDMA; int timersEnabled; struct GBATimer timers[4];