Skip to content

gba: the open BIOS's Div returns |quotient| in r3 (Minish Cap's file select) - #10

Merged
finger563 merged 1 commit into
mainfrom
fix/gba-bios-div-r3
Oct 24, 2026
Merged

finger563 merged 1 commit into
mainfrom
fix/gba-bios-div-r3

Conversation

@finger563

Copy link
Copy Markdown
Contributor

Fixes The Legend of Zelda: The Minish Cap's file select screen. It stayed half slid in, with the file slots and the language menu off screen.

Cause

gpSP's built-in open-source BIOS computes |quotient| into r3 in swi_Div, but its SWI dispatcher restores the caller's r2 and r3 on the way out (swi_complete: ldmfd sp!, {r2, r3, lr}). So Div and DivArm never return r3. The real BIOS does, and Minish Cap uses it.

Fix

One instruction in the BIOS image, at offset 0x17F0. mov r3, r2 becomes str r2, [sp, #4] (0xE58D2004), which writes |quotient| into the saved-r3 stack slot that the dispatcher returns. A comment at the top of open_gba_bios.c documents the patch.

How it was found and tested

I ran the game headless on the Mac with scripted input, through the libretro API:

Core BIOS File select
upstream gpSP open broken
our gpSP open broken
mGBA HLE correct
mGBA gpSP's open BIOS broken
mGBA HLE, with Div not returning r3 broken
mGBA HLE, with Sqrt clobbering r1 correct
mGBA patched open BIOS correct
our gpSP patched open BIOS correct

Regression check: the 11 other GBA games in the library render byte-identical frames with and without the patch (2,100 frames each, same scripted input).

Not tested on the Tab5 yet.

🤖 Generated with Claude Code

…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) <noreply@anthropic.com>
@finger563
finger563 merged commit 5140134 into main Oct 24, 2026
1 check passed
@finger563
finger563 deleted the fix/gba-bios-div-r3 branch October 24, 2026 07:48
@github-actions

Copy link
Copy Markdown

ESP-IDF Size Report for 'Tab5 Emu'

Metric Base PR Delta
FLASH 0 bytes (0.00%) 0 bytes (0.00%) 0 bytes (0.00%)
DRAM 267,182 bytes (60.54%) 267,182 bytes (60.54%) 0 bytes (0.00%)
IRAM 0 bytes 0 bytes 0 bytes
RAM (DRAM+IRAM) 267,182 bytes 267,182 bytes 0 bytes (0.00%)

FLASH uses app .bin size or json2 flash sum. RAM sums DRAM+IRAM via idf_size. Percentages shown when totals are available.
DRAM/IRAM usage does not include memory used by the heap allocator at runtime.
This report was generated by esp-idf-size-delta.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant