feat(cpu): use actual fetch regions for boundary bus snapshots
This commit is contained in:
parent
f2c532f8f6
commit
0a696ea3e7
14 changed files with 465 additions and 28 deletions
101
docs/research/fetch-region-boundaries.md
Normal file
101
docs/research/fetch-region-boundaries.md
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# Instruction fetches across memory-region boundaries
|
||||
|
||||
## Finding
|
||||
|
||||
The shared sampler already selected bus width from the new fetch address.
|
||||
However, `Memory::begin_cpu_access` rejected every Thumb sample whose upper address byte differed from the executing PC.
|
||||
It also selected the IWRAM latch from the executing PC rather than the actual fetch address.
|
||||
This prevented mapped boundary fetches from supplying an otherwise known bus value.
|
||||
|
||||
The boundary extension removes that blanket restriction.
|
||||
Thumb unused-memory reads now use the bus observation at the newly fetched address P+4.
|
||||
ARM continues to use its fetched PC+8 word.
|
||||
This is a bounded entry-snapshot model, not a complete general-bus or cycle-accurate implementation.
|
||||
|
||||
## Evidence and limits
|
||||
|
||||
A boundary-focused web search revisited [nocash's open-bus discussion](https://www.ngemu.com/threads/gba-open-bus.170809/).
|
||||
It describes repeated Thumb halfwords, full BIOS/OAM words, and history-dependent IWRAM lanes.
|
||||
The search did not identify a dedicated physical-hardware boundary result for this implementation.
|
||||
Those formulas alone do not establish every boundary or timing case.
|
||||
|
||||
The stronger implementation evidence is address-based bus dispatch:
|
||||
|
||||
- [ares bus at 6f6786e0](https://github.com/ares-emulator/ares/blob/6f6786e04f0822a3475463df284f313ab8518d51/ares/gba/cpu/bus.cpp) selects the bus using the actual access address.
|
||||
It assigns the full result to `mdr` before selecting the addressed CPU halfword/byte.
|
||||
It does not reject a mapped fetch because the executing instruction occupies another region.
|
||||
- [ares memory helpers](https://github.com/ares-emulator/ares/blob/6f6786e04f0822a3475463df284f313ab8518d51/ares/gba/cpu/memory.cpp) return repeated halfwords from 16-bit regions and the complete local latch from IWRAM.
|
||||
- [ares OAM helper](https://github.com/ares-emulator/ares/blob/6f6786e04f0822a3475463df284f313ab8518d51/ares/gba/ppu/memory.cpp) returns the aligned word before CPU halfword selection.
|
||||
- [jgenesis bus at fab6e2cc](https://github.com/jsgroth/jgenesis/blob/fab6e2ccc60e492dd68b7f1e927b0829a6d80195/backend/gba-core/src/bus.rs) independently updates general open bus from access width and the addressed memory helper.
|
||||
Its `iwram_update_open_bus` drives the complete local IWRAM word after a partial-lane update.
|
||||
That revision marks OAM behavior as a TODO, so it is not independent confirmation of the full OAM rule.
|
||||
- [NanoBoyAdvance's loop/refill helpers](https://github.com/nba-emu/NanoBoyAdvance/blob/55b5cf0ae3d929582ac5bfd486558173502b8354/src/nba/src/arm/arm7tdmi.hh) place the new fetch before execution and refill target pairs in order.
|
||||
Its [open-bus helper](https://github.com/nba-emu/NanoBoyAdvance/blob/55b5cf0ae3d929582ac5bfd486558173502b8354/src/nba/src/bus/bus.cc) uses opcode-based approximations with a BIOS/OAM TODO.
|
||||
We do not treat that helper as an exact boundary oracle.
|
||||
|
||||
These are source comparisons, not physical-hardware measurements or external-emulator differential runs.
|
||||
No external code, BIOS image, or test ROM was imported. All regression programs are original.
|
||||
|
||||
## Supported behavior
|
||||
|
||||
The instruction buffer and bus history consume the same captured new fetch.
|
||||
The consumer does not reread memory or replay observations from retained instructions.
|
||||
|
||||
| Lookahead transition | Thumb unused-memory snapshot |
|
||||
| --- | --- |
|
||||
| Palette to VRAM | Newly fetched halfword repeated in both lanes |
|
||||
| VRAM to OAM | Full aligned OAM word |
|
||||
| OAM to mapped ROM | Newly fetched ROM halfword repeated in both lanes |
|
||||
| Mapped ROM page or wait-window boundary | Halfword from the normal mapped cartridge offset, repeated |
|
||||
| EWRAM to IWRAM | Persistent IWRAM word after the new fetch drives its addressed halfword |
|
||||
|
||||
The existing ROM mapping applies across all three wait-state windows.
|
||||
A 16-bit fetch needs only its two mapped bytes, not an adjacent full word.
|
||||
This includes OAM-to-ROM crossings, despite the executing instruction still residing on a 32-bit bus.
|
||||
|
||||
IWRAM does not acquire guessed lanes from adjacent memory.
|
||||
At P=`0x02fffffc`, only the low half has been fetched from IWRAM; the high half needs prior observed history.
|
||||
Without that history, an unused-memory load remains diagnostic.
|
||||
At P=`0x02fffffe`, a cold fill or target-pair refill can capture IWRAM's low half before the high lookahead fetch.
|
||||
The resulting complete local word is then available.
|
||||
A preceding CPU data access or successful DMA can also establish the required lanes.
|
||||
|
||||
A refill can span two regions. Each actual IWRAM target sample updates only its addressed lanes.
|
||||
Later host writes do not replace those captured lanes; the target instruction's new lookahead updates its own lane normally.
|
||||
Diagnostic failures discard staged fetch/history changes and preserve the previous instruction buffer.
|
||||
A retry takes a new lookahead sample from current memory.
|
||||
|
||||
## Preserved diagnostics and timing
|
||||
|
||||
- Missing ROM bytes and unmapped instruction reads remain strict errors or deferred fetch diagnostics.
|
||||
- Unsupported I/O fetch observations do not borrow known IWRAM lanes or another region's bus value.
|
||||
- Unknown IWRAM lanes do not become zero or fabricated history.
|
||||
- An ordinary instruction or mapped data load does not require a complete unused-memory snapshot.
|
||||
- A branch can discard an unavailable sequential path without failing early.
|
||||
- Host reads, instruction fetches, and DMA do not inherit CPU unused-memory fallback.
|
||||
- Protected BIOS history remains separate and image-derived.
|
||||
- All data reads within an instruction still use one entry snapshot.
|
||||
|
||||
Nominal timing remains based on the current instruction address and existing refill summaries.
|
||||
Crossing a wait-state window does not yet schedule code cost at the actual lookahead address.
|
||||
Per-access device updates, video-bus contention, general DMA handoff, and Game Pak prefetch remain incomplete.
|
||||
No boundary timing accuracy is claimed.
|
||||
|
||||
## Original regression coverage
|
||||
|
||||
Tests cover both Thumb alignments and cold/retained pipelines at mapped video/ROM boundaries.
|
||||
Load matrices check byte, halfword, word, signed and unaligned results without flag changes.
|
||||
Other tests cover block/stack writeback, CPU/DMA-seeded IWRAM lanes, unknown lanes, split refills, and failed-step retry.
|
||||
ROM tests span mapped page and wait-window boundaries with distinct wait settings.
|
||||
Short-ROM tests require exactly the fetched halfword.
|
||||
Unsupported I/O, missing ROM, discarded branch paths, strict host reads, and unchanged ARM snapshots remain covered.
|
||||
|
||||
The mapped-crossing regressions failed under the old upper-address-byte guard, then passed with fetch-address selection.
|
||||
|
||||
## Validation result
|
||||
|
||||
Workspace and core/demo tests pass in debug and release on Darwin arm64.
|
||||
Formatting, lint checks, rustdoc, preparation tests, native ROM windows, and graphics smoke modes pass.
|
||||
Public ARM, Thumb, memory, and BIOS reports match the prior persistent-IWRAM reports exactly, including nominal cycle counts.
|
||||
Debug and release reports also match for the same fixture paths.
|
||||
These checks are regression results, not physical-hardware boundary or timing conformance tests.
|
||||
|
|
@ -57,8 +57,8 @@ Host inspection and setup never drive the latch.
|
|||
Initial lanes remain unknown until observed accesses establish them.
|
||||
Byte/halfword accesses may establish only part of the word; a word access establishes all lanes.
|
||||
All unused-memory reads within an instruction still use one entry snapshot.
|
||||
A Thumb fetch crossing a 16 MiB region boundary leaves that instruction's unused-memory snapshot unsupported.
|
||||
Successful IWRAM accesses still update the local latch independently of this conservative snapshot policy.
|
||||
The [boundary extension](fetch-region-boundaries.md) selects the bus observation from the actual new fetch region.
|
||||
An EWRAM-to-IWRAM lookahead uses the resulting local lanes; incomplete lanes still leave that instruction's snapshot unknown.
|
||||
|
||||
## Thumb IWRAM refill extension
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ Sub-instruction arbitration and DMA during CPU internal cycles remain unmodeled.
|
|||
This is persistent local IWRAM history, not a complete general-bus implementation or cycle-accurate pipeline.
|
||||
ARM unused-memory reads still use their supported PC+8 snapshot.
|
||||
BIOS protection remains separately retained and image-derived.
|
||||
General DMA open bus, unused/write-only I/O, disabled RAM, exact region-crossing snapshots, and per-access timing remain incomplete.
|
||||
General DMA open bus, unused/write-only I/O, disabled RAM, unsupported-region snapshots, and per-access timing remain incomplete.
|
||||
Nominal CPU/DMA costs do not change.
|
||||
|
||||
Original tests cover:
|
||||
|
|
@ -117,7 +117,7 @@ Original tests cover:
|
|||
|
||||
The persistent-history regressions failed under the previous Thumb-continuation-only implementation.
|
||||
Existing cold-entry tests now assert captured lane values instead of the removed unsupported-history diagnostic.
|
||||
Region-crossing and strict unmapped-fetch diagnostics remain covered.
|
||||
Unknown-lane boundary cases and strict unmapped-fetch diagnostics remain covered.
|
||||
|
||||
## Validation result
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,8 @@ Strict instruction reads never use protected BIOS or unused-memory data fallback
|
|||
## Current scope and limits
|
||||
|
||||
- Cold fills and cross-state local IWRAM history are now implemented in the [persistent-latch extension](iwram-bus-history.md).
|
||||
- Thumb 16 MiB region crossings remain unsupported for bus snapshots.
|
||||
- Mapped Thumb region crossings now use the actual fetched bus in the [boundary extension](fetch-region-boundaries.md).
|
||||
- Unknown IWRAM lanes and unavailable/unsupported fetch observations remain diagnostic.
|
||||
- BIOS history commits after successful BIOS instruction execution; target refills do not establish additional BIOS history.
|
||||
- All unused-memory data reads within an instruction still use its entry snapshot.
|
||||
- DMA remains scheduled between whole instructions. Sampling does not add an interleaving point.
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ Refill bus history and instruction buffering now consume the same captured targe
|
|||
Buffer samples add no nominal cycles or data accesses.
|
||||
Timed and untimed execution use the same buffer logic.
|
||||
Destination-based refill summaries and one-shot non-sequential CPU resume costs remain unchanged.
|
||||
Complete fetch-driven bus history, exact region crossings, per-access timing, Game Pak prefetch, and sub-instruction DMA arbitration remain incomplete.
|
||||
Mapped boundary snapshots now follow the [actual fetch region](fetch-region-boundaries.md).
|
||||
Complete bus history, exact boundary timing, Game Pak prefetch, and sub-instruction DMA arbitration remain incomplete.
|
||||
Instruction-state-changing compare quirks also remain hardware-unverified.
|
||||
|
||||
## Original regression coverage
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue