From 9248dcb07a9f5f0a39501a799f2d1a4fbcc7a555 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 5 Nov 2017 21:46:10 -0800 Subject: [PATCH] GB Memory: HDMAs should not start when LCD is off (fixes #310) --- CHANGES | 1 + include/mgba/internal/gb/memory.h | 2 +- src/gb/io.c | 3 +-- src/gb/memory.c | 7 +++++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index a011999cd..08941f4b3 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,7 @@ Bugfixes: - GBA Cheats: Fix PARv3 slide codes (fixes mgba.io/i/919) - GBA Video: OBJWIN can change blend params after OBJ is drawn (fixes mgba.io/i/921) - GBA Savedata: Fix crash when resizing flash + - GB Memory: HDMAs should not start when LCD is off (fixes mgba.io/i/310) Misc: - GBA: Improve multiboot image detection - GB MBC: Remove erroneous bank 0 wrapping diff --git a/include/mgba/internal/gb/memory.h b/include/mgba/internal/gb/memory.h index d28338cff..81d0febd4 100644 --- a/include/mgba/internal/gb/memory.h +++ b/include/mgba/internal/gb/memory.h @@ -177,7 +177,7 @@ int GBCurrentSegment(struct LR35902Core* cpu, uint16_t address); uint8_t GBView8(struct LR35902Core* cpu, uint16_t address, int segment); void GBMemoryDMA(struct GB* gb, uint16_t base); -void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value); +uint8_t GBMemoryWriteHDMA5(struct GB* gb, uint8_t value); void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old, int segment); diff --git a/src/gb/io.c b/src/gb/io.c index 5d5450de7..c84db0095 100644 --- a/src/gb/io.c +++ b/src/gb/io.c @@ -410,8 +410,7 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) { // Handled transparently by the registers break; case REG_HDMA5: - GBMemoryWriteHDMA5(gb, value); - value &= 0x7F; + value = GBMemoryWriteHDMA5(gb, value); break; case REG_BCPS: gb->video.bcpIndex = value & 0x3F; diff --git a/src/gb/memory.c b/src/gb/memory.c index 8fec73745..953588990 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -449,7 +449,7 @@ void GBMemoryDMA(struct GB* gb, uint16_t base) { gb->memory.dmaRemaining = 0xA0; } -void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) { +uint8_t GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) { gb->memory.hdmaSource = gb->memory.io[REG_HDMA1] << 8; gb->memory.hdmaSource |= gb->memory.io[REG_HDMA2]; gb->memory.hdmaDest = gb->memory.io[REG_HDMA3] << 8; @@ -457,7 +457,7 @@ void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) { gb->memory.hdmaSource &= 0xFFF0; if (gb->memory.hdmaSource >= 0x8000 && gb->memory.hdmaSource < 0xA000) { mLOG(GB_MEM, GAME_ERROR, "Invalid HDMA source: %04X", gb->memory.hdmaSource); - return; + return value | 0x80; } gb->memory.hdmaDest &= 0x1FF0; gb->memory.hdmaDest |= 0x8000; @@ -471,7 +471,10 @@ void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) { } gb->cpuBlocked = true; mTimingSchedule(&gb->timing, &gb->memory.hdmaEvent, 0); + } else if (gb->memory.isHdma && !GBRegisterLCDCIsEnable(gb->memory.io[REG_LCDC])) { + return 0x80 | ((value + 1) & 0x7F); } + return value & 0x7F; } void _GBMemoryDMAService(struct mTiming* timing, void* context, uint32_t cyclesLate) {