gameboy-rust/docs/public-thumb-tests.md
0xrsydn 661f00d682 test(memory): integrate pinned public memory compatibility suite
Add --suite memory with verified source hashes, ARM eval checkpoint 0x08000350, and the r12 result assertion. Keep default ARM and explicit Thumb preparation unchanged. Extend offline adapter and CLI tests; retain public binaries outside tracked files.

The unmodified memory ROM passes in debug and release after 174 steps and 1478 nominal cycles, without changing core behavior. Document weak byte-write assertions and mode-selection caveats. Add original CPU-driven tests with exact sentinels, mode/mirror boundaries, byte lanes, forced blank, readback, and nominal device timing.

Validated on Darwin arm64: 851 workspace tests in debug and release; 782 core/demo tests separately; 30 Python tests; all three pinned public suites in both profiles; native ROM windows; all ten demo smoke tests; fmt, clippy, rustdoc, and local documentation links.
2026-10-05 21:19:32 +07:00

5.9 KiB

Pinned public Thumb test

The headless runner executes the unmodified Thumb ROM from jsmolka/gba-tests. It now passes its result checkpoint on Darwin arm64 in debug and release builds. The initial test 229 failure is retained below. This is an independent compatibility baseline, not complete ARM7TDMI conformance or a hardware measurement.

Prepare and run

direnv exec . python3 tools/prepare_gba_tests.py /tmp/gba-public-thumb --suite thumb
direnv exec . cargo run --locked --release -- --test-suite /tmp/gba-public-thumb/suite.json > /tmp/gba-public-thumb-report.json

Use a new directory outside the repository or inside ignored roms/. The parent directory must exist. The adapter checks every selected file's byte count and SHA-256 digest before creating output. It retains the upstream sources, license, README, ROM, generated suite.json, and source-lock.json. No source, binary, header, expected result, or instruction is patched or skipped. Downloaded binaries and header sources must not enter tracked files.

Offline preparation uses the same checks:

direnv exec . python3 tools/prepare_gba_tests.py /tmp/gba-public-thumb-offline --suite thumb --source-dir /path/to/gba-tests

The existing ARM command remains the default. Explicit --suite arm selects the same ARM lock. Each preparation creates one suite. The suite name does not select the checkpoint's instruction state. Python comes from Nix and requires no extra packages. Ordinary unit tests use original synthetic data, without downloads. Preparation is not a compatibility verdict. Inspect the runner's JSON result and exit status.

Provenance and result protocol

  • Repository: jsmolka/gba-tests.
  • Revision: a7113b67e63f83a9b321696ddd7042ccfad6c881.
  • Upstream project license: MIT, copyright Julian Smolka; retained with downloaded files.
  • ROM: thumb/thumb.gba, 3,680 bytes.
  • SHA-256: b5cb2291df4ab314b31c598acd9bff2ccfa0b38efff29daadfe97422ce369b67.
  • Selected file hashes and sizes: tools/gba-tests-thumb.lock.json.

The adapter uses the upstream committed binary. No FASMARM rebuild or source-to-binary reproduction was performed on Darwin. The entry code initializes the display, switches to Thumb, and initializes r7 to zero. Each m_exit failure writes its test number to r7 and calls tmain_end. Branch tests also use r7 as a progress marker, then reset it to zero on their successful path. Successful completion of the memory tests reaches the same tmain_end with r7 still zero.

At this revision:

  • tmain_end is Thumb code at 0x08000930.
  • ADR r0, eval (0xa000) and BX r0 (0x4700) switch execution back to ARM.
  • eval is ARM code at 0x08000934, starting with 0xe92d0003, the m_vsync register save.
  • The later result macro reads r7, not the ARM suite's r12.

The source exit paths and binary Thumb BL targets were checked against tmain_end. The adapter verifies the bridge and initial evaluation word, in addition to whole-file hashes. The manifest stops before eval, requires ARM state and r7 == 0, and allows 1,000,000 successful machine steps. The budget includes the original BIOS boot. Startup and CPU tests execute normally; result rendering does not execute. Diagnostics, timeouts, STOP, and nonzero r7 remain failures under the runner's normal rules.

Observed result on Darwin arm64

Initial integration, before fixing empty-list Thumb stores:

  • The runner reaches 0x08000934 after 771 successful steps and 3,858 nominal cycles.
  • The CPU is in System/ARM state with CPSR 0x0000001f and r7 = 229.
  • Both builds exit nonzero with reason: assertion_failed; there is no emulator diagnostic.
  • Test 229 executes STMIA r0!, {} (0xc000) at 0x080008ba.
  • The stored PC value is 0x080008be, but the following PC read expects 0x080008c0.
  • The public ARM ROM still passes its unchanged checkpoint.

After correcting the empty-list store PC offset:

  • Thumb empty-list stores use executing PC+6 instead of PC+4. ARM stores retain PC+12.
  • Test 229 and the later memory tests complete without taking their failure paths.
  • The runner reaches 0x08000934 after 807 successful steps and 4,170 nominal cycles.
  • The CPU is in System/ARM state with CPSR 0x0000001f and r7 = 0.
  • Debug and release builds exit zero with reason: checkpoint, no error, and the result assertion passing.
  • Both public ROMs pass with their original bytes, checkpoint addresses, budgets, and assertions unchanged.

Original regressions reproduce the stored-PC mismatch without public ROM bytes. They cover all low base registers, banked stack pointers, code/data alignment, ROM windows, timing, and atomic diagnostics. Existing empty-list expectations that incorrectly required PC+4 were corrected; empty loads and ARM stores retain their behavior. See CPU transfer semantics. This proves only the pinned suites' checkpoints and assertions, not complete CPU, bus, or timing compatibility. The pinned public memory ROM also passes, with documented video-byte coverage limits. No public timing, BIOS, graphics, save, or unsafe suite is claimed as passing. These results do not establish Pokémon Emerald compatibility.

References