fix(bios): preserve documented protected-read words at firmware exits
Place skipped compatibility data at boot, SoftReset, SWI, and IRQ exit PC+8 locations. Preserve the real IRQ callback return instruction as its readback word. Keep CPU and memory behavior image-derived, including caller-supplied images. Add original boundary, load-lane, caller-state, wait, supplied-image, and builder-fixup regressions. Document the historical failures, research decision, passing public BIOS checkpoint, and remaining fetch-history limits. Validated on Darwin arm64: 868 workspace tests in debug and release; 799 core/demo tests separately in both profiles; 39 preparation tests; native ROM window tests in both profiles; ten graphics/window smoke modes; fmt, clippy, and rustdoc. Hash-verified public ARM, Thumb, memory, and BIOS suites pass unchanged with identical debug/release reports. BIOS: r12=0, 17606 steps, 197456 nominal cycles, one IRQ entry.
This commit is contained in:
parent
b16588aa4c
commit
efdc288db6
15 changed files with 387 additions and 34 deletions
|
|
@ -125,6 +125,7 @@ The repository is a Cargo workspace with three crates:
|
|||
| `crates/gba-core/tests/bios/stop.rs` | ARM/Thumb Stop calls, caller preservation, keypad wake, and stopped frame running |
|
||||
| `crates/gba-core/tests/halt.rs` | HALT wake masks, idle timing, BIOS-only power writes, DMA progress, and validation |
|
||||
| `crates/gba-core/tests/bios.rs` | ARM/Thumb service calls, copy/fill boundaries, wait races, callback contracts, and boot |
|
||||
| `crates/gba-core/tests/bios/readback.rs` | Image-derived boot/reset/SWI/IRQ compatibility words, load lanes, caller state, and supplied-image isolation |
|
||||
| `crates/gba-core/tests/bios/ram_reset.rs` | Selective RAM boundaries, flag combinations, I/O reset, display rendering, DMA/timer latches, and diagnostics |
|
||||
| `crates/gba-core/tests/bios/reset.rs` | All restart flags, exact RAM boundaries, CPU banks, restart execution, device continuity, and IRQ masking |
|
||||
| `crates/gba-core/tests/bios/arithmetic.rs` | Arithmetic boundaries, wide-integer references, status restoration, and zero-division diagnostics |
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
# BIOS replacement
|
||||
|
||||
The original, Nintendo-free BIOS image built by `crates/gba-core/src/bios/` and the services it implements.
|
||||
The original BIOS replacement built by `crates/gba-core/src/bios/` and the services it implements.
|
||||
|
||||
`crates/gba-core/src/bios.rs` builds a deterministic 16 KiB image from original ARM instructions and mathematically generated data.
|
||||
No Nintendo firmware bytes are included.
|
||||
No Nintendo firmware routines or dumped image are included. Documented protected-read words are explicit compatibility data.
|
||||
A compile-time integer calculation generates the 512-byte sine table at `0x3e00..0x3fff`.
|
||||
The image builder checks that code and literal pools do not overlap this table.
|
||||
Literal pools follow unconditional branches and stay within each load instruction's address range.
|
||||
|
|
@ -108,8 +108,21 @@ The current interpreter implements a bounded ARM prefetch model:
|
|||
|
||||
The initial history is unknown. Direct cartridge startup with `Cpu::new` does not manufacture boot prefetch data.
|
||||
Use BIOS execution, such as `bios::boot`, to establish supported history.
|
||||
All retained words come from the supplied image. No Nintendo opcode constants are substituted.
|
||||
The original replacement's boot and return paths therefore produce different values from Nintendo firmware.
|
||||
All retained words come from the supplied image. The bus never substitutes a firmware-specific constant.
|
||||
Our generated image places documented compatibility data at PC+8 of its non-fallthrough exits:
|
||||
|
||||
| Boundary | Retained word |
|
||||
| --- | --- |
|
||||
| Boot and SoftReset | `0xe129f000` |
|
||||
| SWI return | `0xe3a02004` |
|
||||
| IRQ callback entry | `0xe25ef004` |
|
||||
| IRQ return | `0xe55ec002` |
|
||||
|
||||
Boot, SoftReset, SWI return, and IRQ return skip a diagnostic trap at PC+4 and the data word at PC+8.
|
||||
The callback branch instead has the real `SUBS pc,lr,#4` return instruction at PC+8.
|
||||
Builder fixups preserve this layout without adding executed instructions or host-side service hooks.
|
||||
Other supplied BIOS images retain their own values; their data is not rewritten.
|
||||
See the [root-cause research](../research/bios-readback.md) for evidence and the firmware-versus-bus distinction.
|
||||
|
||||
Host/debug reads and ROM-suite memory assertions still inspect raw mapped bytes and do not initialize or change the history.
|
||||
Instruction fetches remain strict mapped reads outside the CPU data-access context.
|
||||
|
|
@ -118,7 +131,8 @@ Missing BIOS images remain unmapped. The unused-memory ARM open-bus snapshot is
|
|||
|
||||
This models neither a persistent fetch pipeline nor exact bus history across Thumb BIOS code and DMA.
|
||||
Original regressions cover synthetic images, boot, exception returns, access widths, alignment, modes, and diagnostics.
|
||||
The [public BIOS ROM](../public-bios-tests.md) still fails its firmware-specific test 1; this feature is not a public BIOS pass.
|
||||
The [public BIOS ROM](../public-bios-tests.md) passes its unchanged protected-read assertions in debug and release builds.
|
||||
This result covers these firmware boundaries, not full BIOS service compatibility.
|
||||
|
||||
## Stop
|
||||
|
||||
|
|
|
|||
|
|
@ -112,7 +112,8 @@ See the bounded [ARM open-bus implementation](hardware/cpu.md#arm-unused-memory-
|
|||
This is a passing result for this pinned ARM ROM, not proof of complete instruction, memory, or timing compatibility.
|
||||
The [pinned public Thumb ROM](public-thumb-tests.md) also passes its verified checkpoint.
|
||||
The [pinned public memory ROM](public-memory-tests.md) passes its limited mirror and video-byte checks.
|
||||
No public timing, BIOS, graphics, save, or unsafe suite has been claimed as passing.
|
||||
The [public BIOS read-protection ROM](public-bios-tests.md) has a separate bounded passing result.
|
||||
No public timing, graphics, save, or unsafe suite has been claimed as passing.
|
||||
These results do not establish Pokémon Emerald compatibility.
|
||||
|
||||
## References
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Pinned public BIOS read-protection test
|
||||
|
||||
The headless runner executes the unmodified BIOS test ROM from [jsmolka/gba-tests](https://github.com/jsmolka/gba-tests).
|
||||
It currently fails test 1 on Darwin arm64 in debug and release builds.
|
||||
It passes its unchanged protected-read assertions on Darwin arm64 in debug and release builds.
|
||||
This ROM tests protected BIOS reads against Nintendo firmware opcode values, not the complete BIOS service set.
|
||||
Our runner uses the original replacement BIOS. It neither supplies nor loads Nintendo firmware.
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ direnv exec . python3 tools/prepare_gba_tests.py /tmp/gba-public-bios-offline --
|
|||
```
|
||||
|
||||
ARM remains the default suite. The Thumb and memory selections remain unchanged.
|
||||
Preparation is not a passing result. The BIOS run currently exits nonzero and writes a failed assertion report.
|
||||
Preparation is not a passing result. A successful BIOS run exits zero and reports `r12 == 0` at the verified checkpoint.
|
||||
|
||||
## Provenance and checkpoint
|
||||
|
||||
|
|
@ -51,6 +51,8 @@ Timeouts, diagnostics, STOP, and nonzero r12 remain failures under the [normal r
|
|||
|
||||
## Observed result on Darwin arm64
|
||||
|
||||
### Historical failures
|
||||
|
||||
Before BIOS read protection:
|
||||
|
||||
- Both builds reach `eval` after 64 successful steps and 543 nominal cycles.
|
||||
|
|
@ -68,12 +70,27 @@ After the bounded ARM BIOS read-protection implementation:
|
|||
- The test still expects `0xe129f000`. No assertion, checkpoint, ROM byte, or returned constant was changed to force a pass.
|
||||
- Tests 2–4 remain unreached. Their SWI and IRQ cases have not passed independently.
|
||||
|
||||
The initial failure exposed both a missing bus-protection rule and a firmware-specific expectation.
|
||||
The supported protection subset now derives data from the actual supplied image.
|
||||
The original BIOS has a different layout, so its retained prefetch data differs from Nintendo firmware.
|
||||
See [CPU BIOS read protection and its limits](hardware/bios.md#cpu-bios-read-protection).
|
||||
No public BIOS pass is claimed. The ARM, Thumb, and memory suites remain separate passing results.
|
||||
Exact fetch-pipeline behavior and full BIOS compatibility remain unverified.
|
||||
### Current passing result
|
||||
|
||||
After correcting the replacement firmware's exit layout:
|
||||
|
||||
- Both builds reach `eval` at `0x08000248` after 17,606 successful steps and 197,456 nominal cycles.
|
||||
- The CPU is in System/ARM state, with CPSR `0x6000001f` and r12 = 0.
|
||||
- The report says `reason: checkpoint`, with no emulator diagnostic and one IRQ entry.
|
||||
- Boot, returning Sqrt, external IRQ callback, and IRQ return checks all execute and pass.
|
||||
- The ROM, checkpoint, r12 assertion, and step budget remain unchanged.
|
||||
- Debug and release reports match exactly for the same fixture path.
|
||||
|
||||
The initial failure exposed both a missing bus-protection rule and a firmware layout difference.
|
||||
The protected-read bus still derives its retained word from the actual supplied image.
|
||||
Our generated firmware now places documented compatibility words at its exit instructions' PC+8 locations.
|
||||
These words are skipped data, not copied firmware routines. No bus override or ROM-specific condition was added.
|
||||
The IRQ callback uses its existing real return instruction as the readback word.
|
||||
See the [root-cause research](research/bios-readback.md) and [CPU BIOS read-protection limits](hardware/bios.md#cpu-bios-read-protection).
|
||||
|
||||
The ARM, Thumb, and memory suites remain separate passing results.
|
||||
This BIOS result covers boundary readback values, not complete BIOS services, exact fetch history, or commercial-game compatibility.
|
||||
Thumb BIOS execution, full pipeline behavior, and exact firmware timing remain unverified.
|
||||
|
||||
## References
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,8 @@ Adjacent halfwords must remain unchanged. Ignored stores still pay their nominal
|
|||
Halfword and word stores still modify object video RAM and object attribute memory.
|
||||
These are implementation regressions based on documented rules, not new hardware measurements.
|
||||
|
||||
No public BIOS, timing, graphics, save, or unsafe suite is claimed as passing.
|
||||
The [public BIOS read-protection ROM](public-bios-tests.md) has a separate bounded passing result.
|
||||
No public timing, graphics, save, or unsafe suite is claimed as passing.
|
||||
Pokémon Emerald compatibility remains unverified.
|
||||
|
||||
## References
|
||||
|
|
|
|||
|
|
@ -82,7 +82,8 @@ Existing empty-list expectations that incorrectly required PC+4 were corrected;
|
|||
See [CPU transfer semantics](hardware/cpu.md#instruction-demo-and-execution-rules).
|
||||
This proves only the pinned suites' checkpoints and assertions, not complete CPU, bus, or timing compatibility.
|
||||
The [pinned public memory ROM](public-memory-tests.md) also passes, with documented video-byte coverage limits.
|
||||
No public timing, BIOS, graphics, save, or unsafe suite is claimed as passing.
|
||||
The [public BIOS read-protection ROM](public-bios-tests.md) has a separate bounded passing result.
|
||||
No public timing, graphics, save, or unsafe suite is claimed as passing.
|
||||
These results do not establish Pokémon Emerald compatibility.
|
||||
|
||||
## References
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
## Finding
|
||||
|
||||
The remaining public BIOS failure comes from the replacement firmware's exit layout, not its protected-load byte lanes.
|
||||
The memory bus correctly returns the replacement image's retained ARM PC+8 word.
|
||||
That word differs from the documented value left by the standard GBA firmware.
|
||||
The public BIOS failure came from the replacement firmware's exit layout, not its protected-load byte lanes.
|
||||
The memory bus correctly returned the replacement image's retained ARM PC+8 word.
|
||||
Before the layout fix, that word differed from the documented value left by the standard GBA firmware.
|
||||
Matching the bus mechanism alone does not make replacement firmware's observable outputs compatible.
|
||||
|
||||
At the initial failing checkpoint:
|
||||
Before the firmware-layout fix, at the initial failing checkpoint:
|
||||
|
||||
- The unmodified public ROM expects `0xe129f000` after boot.
|
||||
- Our replacement's final boot instruction is at `0x60`; its PC+8 word at `0x68` is `0xe59f1320`.
|
||||
|
|
@ -68,6 +68,22 @@ This corrects the earlier overly broad claim that reproducing any documented opc
|
|||
Arbitrarily overriding a read to satisfy an assertion would be wrong.
|
||||
Reproducing documented firmware boundary outputs for all callers is a legitimate compatibility feature, provided its scope is explicit.
|
||||
|
||||
## Implemented result
|
||||
|
||||
`ArmImage::prefetch_tail` adds skipped compatibility data after boot, SoftReset, SWI return, and IRQ return.
|
||||
The change adds 32 image bytes without adding normally executed instructions.
|
||||
The callback path retains its actual `SUBS pc,lr,#4` at the branch's PC+8.
|
||||
No CPU or memory-bus implementation changed.
|
||||
|
||||
Original regressions in `crates/gba-core/tests/bios/readback.rs` reproduced the boundary failures before the fix.
|
||||
They now pass for ARM/Thumb callers, load lanes and widths, User/System state, both reset targets, and interrupt waits.
|
||||
A supplied-image variant keeps its own changed word, proving that no compatibility constant overrides image data.
|
||||
Builder regressions verify branch and literal relocation around the skipped data.
|
||||
|
||||
The [unchanged public BIOS ROM](../public-bios-tests.md) passes in debug and release on Darwin arm64.
|
||||
It reaches its checkpoint with r12 = 0 and one IRQ entry. Public ARM, Thumb, and memory results remain passing.
|
||||
Workspace tests, preparation tests, lint checks, rustdoc, native ROM windows, and graphics smoke tests also pass.
|
||||
|
||||
## Validation requirements and limits
|
||||
|
||||
- Run the pinned BIOS ROM unchanged, with its original budget, checkpoint, and r12 assertion.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ Use `--test-suite PATH.json` to run repeatable ROM checks without opening a wind
|
|||
Each case has a machine-step budget, a completion address, and explicit assertions.
|
||||
A timeout never counts as a pass. Existing `--rom ... --steps ...` remains a diagnostic mode, not a test verdict.
|
||||
|
||||
Original programs cover the runner itself. Pinned public [ARM](public-arm-tests.md), [Thumb](public-thumb-tests.md), and [memory](public-memory-tests.md) ROMs provide independent compatibility results.
|
||||
Original programs cover the runner itself. Pinned public [ARM](public-arm-tests.md), [Thumb](public-thumb-tests.md), [memory](public-memory-tests.md), and [BIOS](public-bios-tests.md) ROMs provide independent compatibility results.
|
||||
These pinned ROMs pass their checkpoints on Darwin arm64 in debug and release builds.
|
||||
The memory ROM has documented assertion and mode-selection limits; a pass is not exhaustive memory validation.
|
||||
Passing the runner's unit tests does not mean an external suite passes.
|
||||
|
|
@ -137,8 +137,9 @@ The first public integration is [jsmolka/gba-tests ARM](public-arm-tests.md), wi
|
|||
The pinned ARM ROM now passes this checkpoint on Darwin arm64. Historical failures remain documented.
|
||||
The [pinned Thumb ROM](public-thumb-tests.md) also passes its verified r7 checkpoint after the empty-list store correction.
|
||||
The [pinned memory ROM](public-memory-tests.md) also passes, without a core change and with explicit coverage limits.
|
||||
The [pinned BIOS read-protection ROM](public-bios-tests.md) reaches its checkpoint but fails test 1 with the original replacement BIOS.
|
||||
Its expected values depend on Nintendo firmware. Record that failure rather than changing the assertion or returning guessed constants.
|
||||
The [pinned BIOS read-protection ROM](public-bios-tests.md) also passes with the original replacement BIOS.
|
||||
Its documented boundary values come from compatibility data in our firmware's exit layout, not a bus override.
|
||||
The ROM, assertions, checkpoint, and budget remain unchanged. This is not a complete BIOS service test.
|
||||
For further public ARM7TDMI/GBA tests, inspect their source, license, entry assumptions, and result protocol.
|
||||
Pin source revisions and build instructions before comparing emulator changes.
|
||||
Adapt suites to verified completion addresses and result locations; do not guess them or treat timeouts as passes.
|
||||
|
|
|
|||
|
|
@ -67,9 +67,9 @@ Update this file when a feature lands or a limit is removed.
|
|||
- ROM windows with scanline capture, keyboard input, focus-loss release, bounded execution slices, and interactive keypad wake from STOP.
|
||||
- Optional ROM-window frame limits and an original input-test ROM generator.
|
||||
- Headless JSON ROM suites with per-case checkpoints, register/CPSR/memory assertions, bounded budgets, and structured failure reports.
|
||||
- Hash-pinned preparation of public `jsmolka/gba-tests` ARM, Thumb, and memory ROMs, with verified result-register checkpoints.
|
||||
- Hash-pinned preparation of public `jsmolka/gba-tests` ARM, Thumb, memory, and BIOS ROMs, with verified result-register checkpoints.
|
||||
- These pinned ROMs pass their checkpoints on Darwin arm64 in debug and release builds; coverage limits remain documented.
|
||||
- A pinned public BIOS read-protection ROM has a verified checkpoint and an explicit failing baseline with the original BIOS.
|
||||
- The original BIOS exposes documented boot, SoftReset, SWI, and IRQ protected-read words through its actual exit layout.
|
||||
- ARM test/compare Rd=15 status restoration, without a PC result write or nominal refill.
|
||||
- ARM unused-memory data reads return a PC+8 word snapshot, with normal byte lanes and load rotation.
|
||||
- Little-endian byte, halfword, and word reads/writes.
|
||||
|
|
@ -96,7 +96,7 @@ The ARMv4T high-register format requires at least one high register; low-to-low
|
|||
`LDRT`/`STRT` single-transfer variants and invalid register combinations return errors.
|
||||
CPU BIOS reads are protected by the executing address using a bounded ARM prefetch snapshot.
|
||||
Thumb BIOS execution and missing lookahead invalidate that history; protected reads with unknown history remain diagnostics.
|
||||
This is not a full fetch pipeline, and the original BIOS does not reproduce Nintendo's opcode-specific retained values.
|
||||
This is not a full fetch pipeline. The original BIOS reproduces documented boundary readback words, not all firmware side effects.
|
||||
Multiply flags N/Z are implemented. Unspecified multiply C/V outputs are preserved deterministically, not hardware-verified.
|
||||
Instruction and memory errors are development diagnostics, not emulated CPU exceptions.
|
||||
Block transfers validate all accesses before committing register, RAM, or I/O changes.
|
||||
|
|
@ -122,7 +122,8 @@ The [ROM suite runner](rom-tests.md) has original regressions and a [pinned publ
|
|||
The pinned public ARM ROM passes its result checkpoint in debug and release builds.
|
||||
The [pinned public Thumb ROM](public-thumb-tests.md) also passes after correcting its empty-list store PC value.
|
||||
The [pinned public memory ROM](public-memory-tests.md) passes without a core change; its video-byte assertions have documented limits.
|
||||
The [pinned BIOS read-protection ROM](public-bios-tests.md) fails test 1; it expects Nintendo firmware opcode values.
|
||||
The [pinned BIOS read-protection ROM](public-bios-tests.md) passes after correcting the replacement firmware's exit layout.
|
||||
The bus still derives retained words from the actual image; no test-specific override or ROM patch is used.
|
||||
Other public suites remain unverified. These results do not establish full CPU or memory compatibility.
|
||||
The runner requires known completion addresses and has no debug-port protocol, scripted input, or rendered-image assertions.
|
||||
|
||||
|
|
@ -137,8 +138,8 @@ Writes to cartridge addresses return errors instead of modeling cartridge hardwa
|
|||
|
||||
## Next steps
|
||||
|
||||
1. Extend BIOS prefetch history to Thumb execution and validate firmware-specific reads with a lawfully supplied BIOS.
|
||||
The desktop runner still uses only the original BIOS. Do not force the public test to pass with guessed opcode constants.
|
||||
1. Extend BIOS prefetch history to Thumb execution and validate broader fetch-history behavior with independent tests.
|
||||
The desktop runner still uses only the original BIOS. Keep protected reads image-derived for all supplied images.
|
||||
Extend general open-bus support with verified Thumb region/alignment rules and bus history.
|
||||
2. Refine nominal timing with a fetch pipeline, Game Pak prefetch, per-access device updates, and verified timer/IRQ delays.
|
||||
3. Validate keypad retrigger behavior with hardware tests and add remaining device registers; extend BIOS reset coverage as sound/serial support becomes available.
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ Additional tests cover DMA/IRQ accounting, HALT/STOP, diagnostic state, case iso
|
|||
These original tests validate the runner. The [public ARM adapter](public-arm-tests.md) provides a separate passing checkpoint result for its pinned ROM.
|
||||
The [public Thumb adapter](public-thumb-tests.md) uses a separate lock and r7 assertion after its return to ARM state.
|
||||
The [public memory adapter](public-memory-tests.md) uses its own lock and an ARM-state r12 checkpoint.
|
||||
The [public BIOS adapter](public-bios-tests.md) also uses an ARM-state r12 checkpoint, but currently reports test 1 as failed.
|
||||
The [public BIOS adapter](public-bios-tests.md) also passes its ARM-state r12 checkpoint in debug and release builds.
|
||||
Preparation tests use only synthetic original bytes and no network:
|
||||
|
||||
```sh
|
||||
|
|
@ -76,7 +76,7 @@ Separate original CPU tests check exact video-byte results across supported mode
|
|||
They require unchanged nonzero sentinels for ignored writes and unchanged adjacent halfwords for duplicated writes.
|
||||
They also check forced blank, full source-value preservation, CPU halfword readback, nominal data costs, and device progress.
|
||||
Halfword/word stores remain writable in object regions. No emulator behavior change was needed for these tests.
|
||||
These results do not establish public timing, graphics, BIOS, save, or commercial-game compatibility.
|
||||
These results do not establish full BIOS, timing, graphics, save, or commercial-game compatibility.
|
||||
|
||||
ROM-runner tests use temporary files containing original instructions, without Nintendo assets or a desktop session.
|
||||
They check file-size boundaries, bounded reads, short reads, I/O errors, paths, symlinks, and read-only loading.
|
||||
|
|
@ -223,7 +223,11 @@ Original BIOS-access regressions check retained ARM PC+8 data for ARM/Thumb call
|
|||
They verify direct reads while executing inside BIOS, re-entry, SWI/IRQ returns, host-inspection isolation, and original-boot provenance.
|
||||
Unknown history, Thumb BIOS execution, missing lookahead, and diagnostic-step retention have explicit checks.
|
||||
Protected loads keep normal nominal costs and advance devices only through machine stepping.
|
||||
The pinned public BIOS ROM remains a failed assertion, not a conformance pass.
|
||||
Firmware readback regressions separately verify documented boot, SoftReset, returning SWI, IRQ callback, and IRQ return words.
|
||||
They execute ARM/Thumb loads across widths and lanes, check caller state, and trace actual exits to their image data.
|
||||
Interrupt waits replace callback readback with SWI readback on return. Builder tests check branch/literal relocation around exit data.
|
||||
A modified original image verifies that the bus retains supplied data rather than forcing compatibility constants.
|
||||
The pinned public BIOS ROM passes unchanged; this is a bounded protected-read result, not complete BIOS conformance.
|
||||
Display tests cover color conversion, framebuffer bounds, cursor movement, pause behavior, and animation wraparound.
|
||||
Input regression tests check focused arrow keys, focused Space presses, and ignored input when unfocused.
|
||||
Command-line tests cover mode selection and invalid arguments.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue