GBA DMA: Fix ordering and timing of overlapping DMAs

This commit is contained in:
Vicki Pfau 2020-08-21 04:42:50 -07:00
parent 7df5b67a71
commit 66842997dc
2 changed files with 12 additions and 1 deletions

View File

@ -28,6 +28,7 @@ Emulation fixes:
- GBA BIOS: Fix reloading video registers after reset (fixes mgba.io/i/1808) - GBA BIOS: Fix reloading video registers after reset (fixes mgba.io/i/1808)
- GBA BIOS: Make HLE BIOS calls interruptable (fixes mgba.io/i/1711 and mgba.io/i/1823) - GBA BIOS: Make HLE BIOS calls interruptable (fixes mgba.io/i/1711 and mgba.io/i/1823)
- GBA DMA: Linger last DMA on bus (fixes mgba.io/i/301 and mgba.io/i/1320) - GBA DMA: Linger last DMA on bus (fixes mgba.io/i/301 and mgba.io/i/1320)
- GBA DMA: Fix ordering and timing of overlapping DMAs
- GBA Hardware: Fix GB Player detection on big endian platforms - GBA Hardware: Fix GB Player detection on big endian platforms
- GBA Memory: Improve gamepak prefetch timing - GBA Memory: Improve gamepak prefetch timing
- GBA Memory: Stall on VRAM access in mode 2 (fixes mgba.io/i/190) - GBA Memory: Stall on VRAM access in mode 2 (fixes mgba.io/i/190)

View File

@ -219,7 +219,7 @@ void GBADMAUpdate(struct GBA* gba) {
struct GBADMA* dma = &memory->dma[i]; struct GBADMA* dma = &memory->dma[i];
if (GBADMARegisterIsEnable(dma->reg) && dma->nextCount) { if (GBADMARegisterIsEnable(dma->reg) && dma->nextCount) {
int32_t time = dma->when - currentTime; int32_t time = dma->when - currentTime;
if (memory->activeDMA == -1 || (dma->count == dma->nextCount && time < leastTime)) { if (memory->activeDMA == -1 || time < leastTime) {
leastTime = time; leastTime = time;
memory->activeDMA = i; memory->activeDMA = i;
} }
@ -303,6 +303,16 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) {
info->nextCount = wordsRemaining; info->nextCount = wordsRemaining;
info->nextSource = source; info->nextSource = source;
info->nextDest = dest; info->nextDest = dest;
int i;
for (i = 0; i < 4; ++i) {
struct GBADMA* dma = &memory->dma[i];
int32_t time = dma->when - info->when;
if (time < 0 && GBADMARegisterIsEnable(dma->reg) && dma->nextCount) {
dma->when = info->when;
}
}
if (!wordsRemaining) { if (!wordsRemaining) {
info->nextCount |= 0x80000000; info->nextCount |= 0x80000000;
if (sourceRegion < REGION_CART0 || destRegion < REGION_CART0) { if (sourceRegion < REGION_CART0 || destRegion < REGION_CART0) {