From bc1c4a0684cff51a02d09243617d96e249938e9c Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Sat, 24 Oct 2026 00:43:36 -0700 Subject: [PATCH] gba: the open BIOS's Div returns |quotient| in r3 (Minish Cap's file select) gpSP's open-source BIOS replacement computes |quotient| into r3 in swi_Div, but its SWI dispatcher restores the caller's r2 / r3 from the stack on the way out, so Div and DivArm never returned it. The real BIOS does, and The Legend of Zelda: The Minish Cap uses it: its file select screen stayed half slid in, with the file slots and the language menu off screen. One instruction in the image (0x17F0): `mov r3, r2` becomes `str r2, [sp, #4]`, which writes |quotient| into the saved r3 slot the dispatcher returns. Found by running the game headless on the Mac: upstream gpSP and ours both showed the broken screen, mGBA (HLE BIOS) did not, mGBA with this open BIOS did, and mGBA with its HLE Div not returning r3 did too. With the patch both gpSP and mGBA (open BIOS) reach the language menu and the file slots. The 11 other GBA games in the library render byte-identical frames (2100 frames each, scripted input) with and without the patch. Co-Authored-By: Claude Opus 5.5 (1M context) --- components/gba/gpsp/open_gba_bios.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/components/gba/gpsp/open_gba_bios.c b/components/gba/gpsp/open_gba_bios.c index 1caae47..c82b496 100644 --- a/components/gba/gpsp/open_gba_bios.c +++ b/components/gba/gpsp/open_gba_bios.c @@ -1,4 +1,12 @@ // generated from bios/open_gba_bios.bin (gpSP's open-source BIOS replacement) +// with one patch (tab5-emu): Div / DivArm return |quotient| in r3, as the +// real BIOS does. swi_Div computes it (`mov r3, r2` at 0x17F0), but the SWI +// dispatcher restores the caller's r2 / r3 from the stack on the way out +// (swi_complete: ldmfd sp!, {r2, r3, lr}), so the value never came back. +// The instruction now stores it into that saved r3 slot instead +// (`str r2, [sp, #4]`, 0xE58D2004), which the dispatcher then returns. +// The Legend of Zelda: The Minish Cap reads it: without it the file select +// screen stays half slid in, with no file slots and no language menu. #include const uint8_t open_gba_bios_rom[16384] = { 0x0c,0x00,0x00,0xea,0x15,0x00,0x00,0xea,0x15,0x00,0x00,0xea,0x13,0x00,0x00,0xea, @@ -384,7 +392,7 @@ const uint8_t open_gba_bios_rom[16384] = { 0x01,0x30,0xa0,0xe3,0x00,0x00,0x51,0xe1,0x81,0x10,0xa0,0x91,0x83,0x30,0xa0,0x91, 0xfb,0xff,0xff,0x9a,0x01,0x00,0x50,0xe1,0x01,0x00,0x40,0x20,0x03,0x20,0x82,0x21, 0xa3,0x30,0xb0,0xe1,0xa1,0x10,0xa0,0x31,0xf9,0xff,0xff,0x3a,0x00,0x10,0xa0,0xe1, - 0x02,0x30,0xa0,0xe1,0x02,0x00,0xa0,0xe1,0x02,0x01,0x1c,0xe3,0x00,0x00,0x60,0x42, + 0x04,0x20,0x8d,0xe5,0x02,0x00,0xa0,0xe1,0x02,0x01,0x1c,0xe3,0x00,0x00,0x60,0x42, 0x1e,0xff,0x2f,0xe1,0x01,0x33,0xa0,0xe3,0x06,0x20,0x53,0xe5,0x07,0x00,0x00,0xeb, 0x00,0x00,0x52,0xe3,0xff,0x1f,0x13,0xe9,0x02,0xe4,0xa0,0x13,0x02,0xe3,0xa0,0x03, 0x1f,0x00,0xa0,0xe3,0x00,0xf0,0x29,0xe1,0x00,0x00,0xa0,0xe3,0x1e,0xff,0x2f,0xe1,