77 lines
4.9 KiB
Markdown
77 lines
4.9 KiB
Markdown
# Thumb BIOS prefetch snapshots
|
|
|
|
## Decision
|
|
|
|
Retain the full mapped word at `(executing PC + 4) & !3` after a successful Thumb BIOS instruction.
|
|
Keep ARM's existing PC+8 rule. Keep this BIOS history separate from general unused-memory open bus.
|
|
|
|
BIOS has a 32-bit bus. A Thumb instruction fetch selects a halfword, but the BIOS bus drives both word lanes.
|
|
This gives the following snapshot for an instruction at address P:
|
|
|
|
| Executing address | Low halfword | High halfword |
|
|
| --- | --- | --- |
|
|
| P aligned to four bytes | BIOS[P+4] | BIOS[P+6] |
|
|
| P aligned to two bytes only | BIOS[P+2] | BIOS[P+4] |
|
|
|
|
The two halfwords need not match. Do not repeat the fetched halfword, zero-extend it, or read an unaligned word at P+4.
|
|
Do not use ARM's PC+8 offset for Thumb execution.
|
|
|
|
## Evidence and confidence
|
|
|
|
[GBATEK](https://problemkaputt.de/gbatek-gba-unpredictable-things.htm) documents two related behaviors:
|
|
|
|
- Protected BIOS reads return the most recently fetched BIOS opcode.
|
|
- Thumb open bus while executing in BIOS exposes the two aligned word lanes shown above.
|
|
|
|
Its Thumb table describes unused-memory reads, not a dedicated Thumb protected-BIOS test.
|
|
The retained-word rule combines that bus-width evidence with the documented BIOS latch behavior.
|
|
We have not measured it on physical hardware.
|
|
|
|
[NanoBoyAdvance's bus implementation](https://github.com/nba-emu/NanoBoyAdvance/blob/55b5cf0ae3d929582ac5bfd486558173502b8354/src/nba/src/bus/bus.cc) corroborates the full-word latch.
|
|
`ReadBIOS` aligns a permitted address down to four bytes and updates its BIOS latch with a full word.
|
|
It then selects the requested lanes. A halfword access does not reduce the retained latch to 16 bits.
|
|
Its [ARM7TDMI execution loop](https://github.com/nba-emu/NanoBoyAdvance/blob/55b5cf0ae3d929582ac5bfd486558173502b8354/src/nba/src/arm/arm7tdmi.hh) fetches the Thumb PC+4 halfword before dispatching the instruction.
|
|
This is a source comparison, not a differential emulator run. No implementation code was copied.
|
|
|
|
[mGBA's memory implementation](https://github.com/mgba-emu/mgba/blob/master/src/gba/memory.c) was also reviewed.
|
|
Its region-exit path saves `cpu->prefetch[1]`, while its [Thumb execution loop](https://github.com/mgba-emu/mgba/blob/master/src/arm/arm.c) fetches a halfword.
|
|
That path does not independently establish both retained word lanes. Its general Thumb BIOS open-bus path also notes an alignment approximation.
|
|
Do not treat agreement between all emulators, or exact hardware conformance, as established.
|
|
|
|
## Implementation scope
|
|
|
|
`Memory::begin_cpu_access` now consumes the pipeline's new fetch sample, using the incoming instruction state.
|
|
The [shared sampler](shared-fetch-samples.md) captures strict mapped bytes before execution.
|
|
`end_cpu_access` commits BIOS history only after success. Failed instructions preserve previous history.
|
|
Thumb execution outside BIOS neither initializes nor replaces BIOS history.
|
|
Host reads remain raw inspection. CPU data loads outside BIOS select lanes from retained history as before.
|
|
Snapshots add no data accesses or nominal cycles.
|
|
|
|
The snapshot does not create a persistent instruction pipeline.
|
|
It does not model refill-time latches, BIOS data-access ordering within an instruction, or DMA bus transitions.
|
|
A subsequent [Thumb open-bus subset](../hardware/cpu.md#thumb-unused-memory-data-reads) adds region-dependent snapshots outside protected BIOS reads.
|
|
At BIOS boundaries, unavailable lookahead invalidates history under the existing diagnostic policy.
|
|
A branch can still succeed; a later protected read reports unknown history rather than exposing stale bytes.
|
|
This boundary policy is conservative, not a hardware claim.
|
|
|
|
## Regression coverage
|
|
|
|
Original tests in `crates/gba-core/src/cpu/thumb_bios_access_tests.rs` cover:
|
|
|
|
- Both Thumb instruction alignments and both output instruction states.
|
|
- Full words, byte lanes, halfwords, sign extension, rotation, and all processor modes.
|
|
- Sequential history, ARM/Thumb transitions, SWI entry, and POP-to-PC exits with RAM stack data.
|
|
- Raw reads inside BIOS and protected reads outside it.
|
|
- The last complete fetch word, unavailable lookahead, and failure retention.
|
|
- Separate host reads, independent cold-IWRAM fetch history, nominal costs, and device progression.
|
|
|
|
## Validation result
|
|
|
|
The Thumb boundary-read regressions failed on the old history-invalidation path and pass with aligned-word snapshots.
|
|
Darwin arm64 workspace and core/demo tests pass in debug and release builds.
|
|
Preparation tests, formatting, lint checks, rustdoc, native ROM windows, and graphics smoke tests also pass.
|
|
The pinned public ARM, Thumb, memory, and BIOS reports match their previous passing reports exactly.
|
|
Debug and release reports also match each other for the same fixture paths.
|
|
|
|
The pinned public BIOS ROM uses ARM firmware paths. Its unchanged pass is regression evidence, not independent Thumb BIOS coverage.
|
|
Full pipeline timing and commercial-game compatibility remain outside this change.
|