fix(memory): ignore emulated writes to mapped BIOS

This commit is contained in:
0xrsydn 2026-10-07 03:31:33 +07:00
commit a0516de748
16 changed files with 462 additions and 34 deletions

View file

@ -134,7 +134,8 @@ See the [root-cause research](../research/bios-readback.md) for evidence and the
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.
BIOS writes remain read-only diagnostics. DMA BIOS sources never read image bytes.
CPU and DMA writes to the mapped BIOS are ignored, as described below. Host writes remain read-only diagnostics.
DMA BIOS sources never read image bytes.
They reuse known [channel data](dma.md#retained-channel-data), or report an unsupported-source diagnostic when channel data is unknown.
Missing BIOS images remain unmapped. The unused-memory ARM open-bus snapshot is separate from this retained BIOS value.
@ -148,6 +149,38 @@ Original regressions cover synthetic images, boot, exception returns, access wid
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.
## Writes to the mapped BIOS
CPU stores to `0x00000000..0x00003fff` complete without changing the supplied BIOS image.
This applies to ARM and Thumb stores, all processor modes, block stores, and the write phase of swaps.
The rule depends on the destination, not the executing address or a particular BIOS service.
A swap must still complete its protected read; unknown read history remains diagnostic.
Ignored writes retain nominal data-access costs, instruction writeback, and normal machine clock advancement.
The write value does not replace BIOS read history. Instructions executed inside BIOS still update history through their ordinary fetches.
DMA writes follow the same discard rule, with source reads, channel data, address progression, completion IRQs, and nominal timing intact.
Host/debug `Memory::write*` calls remain strict and report `ReadOnly` for the mapped BIOS.
The bounded rule requires a supplied BIOS image and stops at `0x00003fff`.
Missing BIOS images, unmapped destinations beyond that boundary, and cartridge writes retain their existing diagnostics.
Whole-instruction validation still rejects a block store with a later unsupported destination before committing CPU state.
DMA retains earlier completed units when a later unit fails.
This is not a general model of ignored writes across unused address ranges.
`CpuSet` and `CpuFastSet` need no service-specific change: their original ARM stores obey these bus rules.
Tests use original programs and images to check immutable firmware, widths, lanes, modes, swaps, clocks, DMA, and failed-step retry.
The local Emerald caller supplies destination zero itself; the copy routine does not corrupt that argument.
See [the startup investigation](../research/emerald-reset.md).
### Write-behavior references
- [GBATEK memory map](https://mgba-emu.github.io/gbatek/): the 16 KiB BIOS system-ROM region and bus widths.
- [GBATEK memory-copy services](https://problemkaputt.de/gbatek-bios-memory-copy.htm): CpuSet/CpuFastSet arguments and executed copy operations.
- [mGBA memory implementation at 3a5e34be](https://github.com/mgba-emu/mgba/blob/3a5e34be33dc7f8f707e5bc9db69e8a430046f21/src/gba/memory.c): unsupported BIOS store cases log and continue without writing the image.
- [ares BIOS implementation at 728105b2](https://github.com/ares-emulator/ares/blob/728105b28ed6f1429841d5b2f5a38794d01d5c39/ares/gba/system/bios.cpp): the BIOS write handler discards writes separately from protected reads.
These are documentation and emulator comparisons, not new physical-hardware measurements. No reference implementation was copied.
## Stop
`Stop` (`SWI 0x03`) executes an original ARM byte store of `0x80` to HALTCNT.

View file

@ -146,7 +146,8 @@ Limits remain explicit:
- Unused/write-only I/O reads, general DMA-to-CPU bus handoff, and disabled-RAM reads are not modeled here.
[DMA channel data](dma.md#retained-channel-data) is separate and never overrides a CPU snapshot.
- Missing BIOS, truncated ROM, unsupported I/O, and save-memory accesses retain their existing diagnostics.
- Unused-memory writes remain diagnostics rather than ignored hardware writes. Swaps cannot silently discard their write.
- Unused-memory writes remain diagnostics rather than ignored hardware writes. Swaps to those ranges still fail.
- Writes to the mapped BIOS are a separate [ignored-write subset](bios.md#writes-to-the-mapped-bios), including swap write phases.
- ARM/Thumb instruction buffering is persistent, but these data snapshots remain a separate bounded model.
Thumb IWRAM bus-history samples do not share storage with retained instructions.
DMA updates IWRAM lanes at instruction boundaries, not during CPU accesses.

View file

@ -64,6 +64,9 @@ Timer-driven requests, repeat, and completion IRQs are described in [Direct Soun
Other special-mode pairings, video capture, Game Pak DRQ, and prohibited source mode 3 return `DmaError::UnsupportedControl`.
DMA reads below work RAM reuse known channel data as described below. They never expose BIOS bytes.
DMA writes to DMA registers return `DmaError::RegisterDestination`; self-modifying transfers are not supported.
Writes into the mapped 16 KiB BIOS [complete without changing its image](bios.md#writes-to-the-mapped-bios).
Source reads, channel data, address progression, timing, and completion IRQs still apply to these ignored writes.
DMA0–2 mask destination bit 27, so a programmed cartridge address can instead select the BIOS region.
Other accesses use the existing memory map, alignment checks, mirrors, and I/O write rules.
Other unmapped reads and cartridge writes remain diagnostics, not general DMA open-bus behavior.
A failed unit changes no memory, device state, or clock. Earlier units remain committed; the failed unit remains pending.