refactor(cpu): account for timing in bus-access order
This commit is contained in:
parent
86321f0071
commit
7f3ebd3a5d
14 changed files with 626 additions and 65 deletions
|
|
@ -51,15 +51,16 @@ The repository is a Cargo workspace with three crates:
|
|||
| `crates/gba-core/src/display.rs` | Display clock, scanline status, comparison edges, and display IRQ events |
|
||||
| `crates/gba-core/src/dma.rs` | DMA registers, internal pointers, retained channel data, trigger state, priority, and completion IRQs |
|
||||
| `crates/gba-core/src/machine.rs` | Timed CPU/DMA/device stepping and IRQ delivery |
|
||||
| `crates/gba-core/src/timing.rs` | Bus widths, wait-state costs, and timing breakdowns |
|
||||
| `crates/gba-core/src/timing.rs` | Bus widths, wait-state costs, ordered CPU timing transactions, and timing breakdowns |
|
||||
| `crates/gba-core/src/cpu/pipeline.rs` | CPU-owned ARM/Thumb instructions, PC/state tags, next fetch kind, deferred diagnostics, refills, and invalidation |
|
||||
| `crates/gba-core/src/cpu/arm_pipeline_tests.rs` | ARM self-modifying code, branches, target pairs, DMA isolation, exceptions, errors, and timing equivalence |
|
||||
| `crates/gba-core/src/cpu/thumb_pipeline_tests.rs` | Thumb retained halfwords, BL prefix/suffix, state-tagged refills, DMA isolation, rollback, and timing equivalence |
|
||||
| `crates/gba-core/src/cpu/timing.rs` | Source-fetch/target-pair costs, IRQ integration, next-fetch classification, and data accounting |
|
||||
| `crates/gba-core/src/cpu/timing.rs` | CPU timing transaction entry/exit, IRQ integration, and incoming instruction classification |
|
||||
| `crates/gba-core/src/cpu/fetch_timing_tests.rs` | Fetch-region/page/wait-window costs, DMA resume, WAITCNT stores, deferred errors, and timer/IRQ effects |
|
||||
| `crates/gba-core/src/cpu/refill_timing_tests.rs` | Refill source/target widths, wait settings, boundaries, DMA resume, and IRQ diagnostics |
|
||||
| `crates/gba-core/src/cpu/fetch_sequence_tests.rs` | Instruction-pair access kinds, transfer/internal-cycle breaks, refills, IRQ/DMA composition, and rollback |
|
||||
| `crates/gba-core/src/memory/irq_fetch_tests.rs` | Discarded IRQ fetch lanes, cold/retained entry, BIOS-history isolation, and deferred vector errors |
|
||||
| `crates/gba-core/src/memory/timing_event_tests.rs` | Ordered source/data/internal/refill events, WAITCNT snapshots, IRQ entry, rollback, and host/DMA isolation |
|
||||
| `crates/gba-core/src/cpu/dma_resume_tests.rs` | One-shot non-sequential DMA resume costs, wait settings, failures, idle, IRQs, and API isolation |
|
||||
| `crates/gba-core/src/cpu/timing_tests.rs` | Instruction timing and semantic-equivalence checks |
|
||||
| `crates/gba-demos/src/timer_demo.rs` | Original timer-configuration program and IRQ handler |
|
||||
|
|
|
|||
|
|
@ -356,6 +356,12 @@ The writable mask is `0x5fff`; the Game Pak type flag reads as GBA, and the uppe
|
|||
A CPU write to WAITCNT does not retroactively change that instruction's code-access cost.
|
||||
The new settings apply to subsequent code accesses.
|
||||
|
||||
Timed CPU execution uses an ordered `CpuTiming` transaction: source fetch, actual data accesses, internal work, then target-pair fetches.
|
||||
A failed instruction discards the entire transaction. Target samples do not add duplicate fetch or data costs.
|
||||
IRQ entry records its source fetch and vector pair in the same path.
|
||||
Device clocks still advance once after the successful step; this is not per-cycle scheduling.
|
||||
See [Game Pak prefetch research](../research/gamepak-prefetch.md) for this prerequisite and unresolved queue behavior.
|
||||
|
||||
### Nominal CPU resume after DMA
|
||||
|
||||
A successful DMA unit marks the next CPU instruction's nominal code access non-sequential.
|
||||
|
|
|
|||
|
|
@ -199,6 +199,16 @@ Persistent fetch access-kind research:
|
|||
See [persistent fetch access kinds](research/fetch-access-sequencing.md) for scope, cold-start policy, and regression-report changes.
|
||||
These are source comparisons, not hardware timing measurements or external-emulator test runs.
|
||||
|
||||
Game Pak prefetch research:
|
||||
|
||||
- [GBATEK GamePak Prefetch](https://www.problemkaputt.de/gbatek-gba-gamepak-prefetch.htm), for capacity, opcode-only service, and idle-bus progress.
|
||||
- [mGBA cycle counting and prefetch](https://mgba.io/2015/06/27/cycle-counting-prefetch/), for independent cartridge progress and original hardware-timing test leads.
|
||||
- The pinned NanoBoyAdvance bus timing above, for queued/in-progress/miss cases and completion-edge cancellation stalls.
|
||||
- [ares prefetch at 6f6786e0](https://github.com/ares-emulator/ares/blob/6f6786e04f0822a3475463df284f313ab8518d51/ares/gba/cpu/prefetch.cpp), compared with its pinned bus dispatcher above, for halfword ownership, full-buffer stopping, and page-boundary behavior.
|
||||
|
||||
See [prefetch evidence and timing prerequisites](research/gamepak-prefetch.md).
|
||||
The source differences remain validation questions. No Game Pak prefetch implementation or hardware conformance result is claimed yet.
|
||||
|
||||
Use [GBATEK](https://problemkaputt.de/gbatek.htm) and ARM7TDMI documentation for further hardware work.
|
||||
Only use game ROMs that you may lawfully use. Do not commit game ROMs, BIOS files, or game assets.
|
||||
The ignore file excludes `roms/`, common game ROM extensions, and save files.
|
||||
|
|
|
|||
|
|
@ -126,4 +126,5 @@ The timer therefore runs two additional cycles before the handler stops it.
|
|||
- Game Pak prefetch, configurable EWRAM timing, display contention, and DMA during internal cycles remain unimplemented.
|
||||
- IRQ synchronization delays and complete BIOS/general-bus latch history remain incomplete.
|
||||
|
||||
The next timing work is Game Pak prefetch, with explicit startup and invalidation rules and independent tests.
|
||||
The later [prefetch prerequisite](gamepak-prefetch.md) records source, data, internal, and refill costs in order without changing totals.
|
||||
The next timing work remains an active Game Pak queue, with verified startup and invalidation rules and independent tests.
|
||||
|
|
|
|||
115
docs/research/gamepak-prefetch.md
Normal file
115
docs/research/gamepak-prefetch.md
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
# Game Pak prefetch: evidence and timing prerequisites
|
||||
|
||||
## Current result
|
||||
|
||||
Game Pak prefetch is **not enabled in the core yet**.
|
||||
WAITCNT bit 14 remains stored without accelerating instruction fetches.
|
||||
This change prepares ordered CPU timing transactions without changing cycle totals or instruction results.
|
||||
|
||||
The previous timing path collected data costs during execution, then calculated source and refill costs afterward.
|
||||
That produced correct existing totals but could not directly advance a prefetch queue in bus-access order.
|
||||
A prefetch implementation needs to distinguish cartridge-bus occupation from time available for background fetching.
|
||||
An aggregate instruction cost cannot identify when to fill or invalidate a queue.
|
||||
|
||||
## Sources reviewed
|
||||
|
||||
- [GBATEK GamePak Prefetch](https://www.problemkaputt.de/gbatek-gba-gamepak-prefetch.htm) describes eight 16-bit entries, opcode-only service, and prefetch during internal or other-memory accesses.
|
||||
- [mGBA's cycle-counting article](https://mgba.io/2015/06/27/cycle-counting-prefetch/) explains independent cartridge-bus progress, partially completed fetches, and instruction-pair examples.
|
||||
Its examples and linked timing suite provide leads for independent validation, not a local hardware-test pass.
|
||||
- [NanoBoyAdvance bus timing at 55b5cf0a](https://github.com/nba-emu/NanoBoyAdvance/blob/55b5cf0ae3d929582ac5bfd486558173502b8354/src/nba/src/bus/timing.cc) distinguishes queue hits, in-progress fetches, misses, and cancellation stalls.
|
||||
- [ares prefetch at 6f6786e0](https://github.com/ares-emulator/ares/blob/6f6786e04f0822a3475463df284f313ab8518d51/ares/gba/cpu/prefetch.cpp) provides an independent halfword-queue implementation.
|
||||
Its [bus dispatcher](https://github.com/ares-emulator/ares/blob/6f6786e04f0822a3475463df284f313ab8518d51/ares/gba/cpu/bus.cpp) separates opcode requests, data requests, and other-region progress.
|
||||
|
||||
No external implementation or ROM was added to the repository.
|
||||
No physical-hardware measurement or external-emulator differential run was performed.
|
||||
|
||||
## Agreement and unresolved details
|
||||
|
||||
The sources agree on the main model:
|
||||
|
||||
- Prefetch is controlled by WAITCNT bit 14.
|
||||
- The buffer serves Game Pak opcodes, not arbitrary ROM data loads.
|
||||
- Internal CPU work and accesses to other memory can give the cartridge bus time to fetch ahead.
|
||||
- A matching ready entry avoids ordinary ROM waits.
|
||||
- A request for an in-progress fetch waits for the remaining work rather than restarting the full access.
|
||||
- Cartridge data traffic and nonmatching code requests interact with the active prefetch sequence.
|
||||
|
||||
However, the implementation details are not interchangeable:
|
||||
|
||||
| Area | Source observation | Required follow-up |
|
||||
| --- | --- | --- |
|
||||
| Entry granularity | NanoBoyAdvance groups ARM words; ares tracks halfwords | Verify partial ARM fetches and ARM/Thumb transitions |
|
||||
| Full buffer | ares stops production and restarts after draining; NanoBoyAdvance uses an instruction-sized countdown/count model | Establish capacity, pause, drain, and restart timing independently |
|
||||
| ROM page boundary | ares prevents background reads across the forced-N boundary; NanoBoyAdvance's queue step uses its retained duty | Verify 128 KiB boundaries without assuming a normal ready-entry hit |
|
||||
| Cancellation | Both contain completion-edge stall handling | Verify the exact halfword phase and which code/data requests trigger a stall |
|
||||
| DMA and idle | Prefetch shares cartridge time with other bus owners | Verify RAM-only DMA, cartridge DMA, HALT/STOP, and resume separately |
|
||||
| WAITCNT changes | Queue state and current transfer timing depend on register changes | Define enable, disable, and changed-wait behavior before integration |
|
||||
|
||||
These differences do not establish that either implementation is wrong.
|
||||
They show why copying one queue policy is not sufficient evidence for the entire subsystem.
|
||||
The first implementation should state its supported cases and retain explicit limits for unresolved behavior.
|
||||
|
||||
## Ordered CPU timing transactions
|
||||
|
||||
`CpuTiming` replaces the data-only accumulator.
|
||||
A timed CPU instruction now records these events in order:
|
||||
|
||||
1. Source instruction fetch, using the incoming access kind and instruction width.
|
||||
2. Actual data reads/writes, using their aligned bus addresses and widths.
|
||||
3. Internal CPU cycles from the incoming instruction classification.
|
||||
4. Refill target N and target+width S accesses, using the resulting instruction state.
|
||||
|
||||
S means sequential access; N means non-sequential access.
|
||||
An instruction without data, internal work, or a refill omits those events.
|
||||
The two refill events occur in `Cpu::refill_pipeline`, alongside its existing mapped target samples.
|
||||
No separate refill-cost formula runs after execution.
|
||||
IRQ entry records its discarded incoming-state source fetch before its ARM vector pair, without a data or internal event.
|
||||
|
||||
Code timing retains the entry WAITCNT snapshot.
|
||||
Data timing retains the settings observed at each actual bus access, including pre-write settings for a WAITCNT store.
|
||||
The next instruction uses the new WAITCNT settings.
|
||||
The existing data N/S rule and persistent CPU source-fetch kind are unchanged.
|
||||
|
||||
The transaction returns the same `StepTiming` fields as before.
|
||||
A diagnostic discards the entire transaction, including any data events recorded before a late failure.
|
||||
Missing lookahead or target bytes retain their existing deferred diagnostic policy and nominal attempted-fetch cost.
|
||||
Device clocks still advance once after a successful machine step.
|
||||
This is ordered cost accounting, not a cycle-by-cycle bus scheduler.
|
||||
|
||||
Untimed execution, host inspection, cold-fill sampling, and DMA do not join a CPU timing transaction.
|
||||
They retain their existing behavior and do not create extra code/data charges.
|
||||
Untimed CPU execution still updates instruction retention and the next fetch kind, but does not compute a timing transaction.
|
||||
A future active prefetch model must define timing-state progression for this API explicitly.
|
||||
|
||||
## Original regression coverage
|
||||
|
||||
Test builds retain events from the last successful CPU timing transaction.
|
||||
Production builds retain only totals, the code WAITCNT snapshot, and data-sequence state; they allocate no event log.
|
||||
The test log covers the maximum supported block load, including PC, without truncation.
|
||||
Tests inspect event order and metadata independently of total cycle assertions.
|
||||
|
||||
Coverage includes:
|
||||
|
||||
- Word PC loads and the full register-list LDM sequence.
|
||||
- Thumb POP with word data and halfword target fetches.
|
||||
- ARM-to-Thumb BX, taken branches to fallthrough, and skipped conditions.
|
||||
- Swaps, register-shift internal cycles, and absence of duplicate source/refill events.
|
||||
- WAITCNT stores with old source settings and new settings on the next fetch.
|
||||
- IRQ entry after a Thumb load, including the retained non-sequential source kind.
|
||||
- Failed data accesses, late block-load failure, missing current/lookahead slots, and retry isolation.
|
||||
- Host reads, untimed CPU execution, and DMA isolation from the CPU trace.
|
||||
|
||||
## Validation
|
||||
|
||||
Workspace and core/demo tests pass in debug and release on Darwin arm64.
|
||||
Formatting, clippy, rustdoc, Python preparation tests, native ROM windows, and all graphics smoke modes pass.
|
||||
The release executable is native Mach-O arm64.
|
||||
Public ARM, Thumb, memory, and BIOS reports match the preceding sequencing change exactly, including cycles and step counts.
|
||||
Debug and release reports also match. Original CPU and timer demo traces are unchanged.
|
||||
|
||||
## Next implementation work
|
||||
|
||||
Implement and test queue progress against these ordered timing events before enabling WAITCNT acceleration.
|
||||
Keep the cartridge queue separate from CPU instruction retention, BIOS protected-read history, and IWRAM local lanes.
|
||||
Resolve startup, capacity, page boundaries, partial ARM fetches, cancellation, and WAITCNT changes with independent expectations.
|
||||
DMA/idle progression and diagnostic rollback need separate tests before claiming those interactions are supported.
|
||||
|
|
@ -45,6 +45,7 @@ Update this file when a feature lands or a limit is removed.
|
|||
- STOP freezes CPU/DMA/device clocks, retains device phases, and reports a stopped frame runner without spinning.
|
||||
- Machine execution to the next VBlank event, with a configurable step limit.
|
||||
- CPU/device stepping with nominal ARM7 instruction costs and memory wait states.
|
||||
- Ordered CPU timing transactions record source, data, internal, and refill costs, with whole-step diagnostic rollback.
|
||||
- Code costs use actual ARM PC+8/Thumb PC+4 source fetches and branch/exception target pairs, including region and ROM boundaries.
|
||||
- IRQ entry samples its discarded incoming-state fetch before the ARM vector pair, with local IWRAM history updates.
|
||||
- Persistent fetch access kinds follow CPU data/internal work, compose with DMA resume, and reset after target refills.
|
||||
|
|
@ -166,7 +167,9 @@ Writes to cartridge addresses return errors instead of modeling cartridge hardwa
|
|||
Keep unknown history diagnostic until fetch ordering and latch ownership have independent coverage.
|
||||
Validate BIOS snapshots with independent hardware tests before claiming exact refill or data-access history.
|
||||
The desktop runner still uses only the original BIOS. Keep protected reads image-derived for all supplied images.
|
||||
2. Add Game Pak prefetch with verified startup and invalidation rules.
|
||||
2. Add Game Pak prefetch using the ordered CPU timing path; bit 14 still does not accelerate execution.
|
||||
Verify queue startup, full-buffer restart, page boundaries, partial ARM fetches, and invalidation before enabling it.
|
||||
See [prefetch research and prerequisites](research/gamepak-prefetch.md).
|
||||
Validate cold-start costs, then extend per-access device updates, bus arbitration, and 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.
|
||||
Validate STOP entry/wake edges and add external wake sources and remaining DMA device modes.
|
||||
|
|
|
|||
|
|
@ -265,6 +265,11 @@ They use independent N/S tables across every ROM window and wait setting, includ
|
|||
They check timed/untimed equivalence, clones, IRQ/DMA composition, repeated transfers, PC-load refills, failed steps, and cold-start policy.
|
||||
Page/wait-window crossings, masked IRQs, host/HALT isolation, and pre-write WAITCNT settings retain separate checks.
|
||||
See [persistent fetch access kinds](research/fetch-access-sequencing.md) for evidence and public-report changes.
|
||||
Timing-event tests inspect source/data/internal/refill order and metadata independently of aggregate cycle costs.
|
||||
They cover the full LDM register list, PC loads, Thumb POP, state changes, skipped branches, swaps, shifts, and IRQ entry.
|
||||
WAITCNT snapshots, late failure rollback, deferred fetch errors, and host/untimed/DMA isolation have separate checks.
|
||||
Test-only event logs do not add a production allocation or a public trace API.
|
||||
See [prefetch prerequisites](research/gamepak-prefetch.md); these tests do not establish an active Game Pak prefetch implementation.
|
||||
Instruction timing tests cover arithmetic, shifts, branches, transfers, block operations, multiply, and exception returns.
|
||||
Timed and untimed execution are compared across all 65,536 Thumb encodings with fixed initial registers.
|
||||
Timer/IRQ tests verify that changing WAITCNT changes when an interrupt is sampled.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue