From 5bd5a8d998b4449bc85e606f48be3cc18d280ef1 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 20 Dec 2023 22:05:17 -0800 Subject: [PATCH] GBA I/O: Fix HALTCNT access behavior (fixes #2309) --- CHANGES | 3 ++- src/gba/io.c | 34 +++++++++++++++++----------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/CHANGES b/CHANGES index e5f40a5ff..30d8b9dff 100644 --- a/CHANGES +++ b/CHANGES @@ -21,8 +21,9 @@ Emulation fixes: - GBA Audio: Fix sample timing drifting when changing sample interval - GBA Audio: Fix initial channel 3 wave RAM (fixes mgba.io/i/2947) - GBA Audio: Fix sample position issues when rate changes (fixes mgba.io/i/3006) - - GBA GPIO: Fix tilt scale and orientation (fixes mgba.io/i/2703) - GBA BIOS: Fix clobbering registers with word-sized CpuSet + - GBA GPIO: Fix tilt scale and orientation (fixes mgba.io/i/2703) + - GBA I/O: Fix HALTCNT access behavior (fixes mgba.io/i/2309) - GBA SIO: Fix normal mode SI/SO semantics (fixes mgba.io/i/2925) - GBA Video: Disable BG target 1 blending when OBJ blending (fixes mgba.io/i/2722) Other fixes: diff --git a/src/gba/io.c b/src/gba/io.c index 10eb9fb4c..184146511 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -531,6 +531,21 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { case GBA_REG_MAX: // Some bad interrupt libraries will write to this break; + case GBA_REG_POSTFLG: + if (gba->memory.activeRegion == GBA_REGION_BIOS) { + if (gba->memory.io[address >> 1]) { + if (value & 0x8000) { + GBAStop(gba); + } else { + GBAHalt(gba); + } + } + value &= ~0x8000; + } else { + mLOG(GBA_IO, GAME_ERROR, "Write to BIOS-only I/O register: %03X", address); + return; + } + break; case GBA_REG_EXWAITCNT_HI: // This register sits outside of the normal I/O block, so we need to stash it somewhere unused address = GBA_REG_INTERNAL_EXWAITCNT_HI; @@ -563,19 +578,6 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { } void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) { - if (address == GBA_REG_HALTCNT) { - value &= 0x80; - if (!value) { - GBAHalt(gba); - } else { - GBAStop(gba); - } - return; - } - if (address == GBA_REG_POSTFLG) { - gba->memory.io[(address & (GBA_SIZE_IO - 1)) >> 1] = value; - return; - } if (address >= GBA_REG_DEBUG_STRING && address - GBA_REG_DEBUG_STRING < sizeof(gba->debugString)) { gba->debugString[address - GBA_REG_DEBUG_STRING] = value; return; @@ -806,10 +808,6 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { gba->memory.io[GBA_REG(JOYSTAT)] &= ~JOYSTAT_RECV; break; - case GBA_REG_POSTFLG: - mLOG(GBA_IO, STUB, "Stub I/O register read: %03x", address); - break; - // Wave RAM can be written and read even if the audio hardware is disabled. // However, it is not possible to switch between the two banks because it // isn't possible to write to register SOUND3CNT_LO. @@ -883,6 +881,7 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { case GBA_REG_IF: case GBA_REG_WAITCNT: case GBA_REG_IME: + case GBA_REG_POSTFLG: // Handled transparently by registers break; case 0x066: @@ -897,6 +896,7 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { case 0x142: case 0x15A: case 0x206: + case 0x302: mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); return 0; // These registers sit outside of the normal I/O block, so we need to stash them somewhere unused