feat(timing): implement nominal Game Pak opcode prefetch
This commit is contained in:
parent
7f3ebd3a5d
commit
8f22092e06
25 changed files with 1062 additions and 124 deletions
|
|
@ -52,6 +52,9 @@ The repository is a Cargo workspace with three crates:
|
|||
| `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, ordered CPU timing transactions, and timing breakdowns |
|
||||
| `crates/gba-core/src/timing/prefetch.rs` | Nominal eight-halfword opcode queue, partial transfers, capacity stops, and cancellation |
|
||||
| `crates/gba-core/src/timing/prefetch/tests.rs` | Wait-state matrices, partial words, cancellation phases, boundaries, configuration, and progress consistency |
|
||||
| `crates/gba-core/src/memory/prefetch_tests.rs` | CPU/DMA/idle queue ownership, WAITCNT writes, branch/IRQ timing, API isolation, and rollback |
|
||||
| `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 |
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ Other commands:
|
|||
direnv exec . cargo run --locked -- --cpu-demo
|
||||
|
||||
# Run a timer-generated interrupt through an original test handler.
|
||||
# Uses nominal instruction/bus costs; prefetch and sub-instruction timing are not modeled.
|
||||
# Uses nominal instruction/bus costs and opcode prefetch; sub-instruction device scheduling is not modeled.
|
||||
direnv exec . cargo run --locked -- --timer-demo
|
||||
|
||||
# Verify 60 CPU-driven frames with scripted movement and color changes.
|
||||
|
|
|
|||
|
|
@ -360,13 +360,39 @@ Timed CPU execution uses an ordered `CpuTiming` transaction: source fetch, actua
|
|||
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.
|
||||
The transaction also stages the nominal Game Pak prefetch queue described below.
|
||||
|
||||
### Game Pak opcode prefetch
|
||||
|
||||
WAITCNT bit 14 enables an eight-halfword timing queue, separate from retained CPU instructions and bus-history values.
|
||||
ROM opcode misses start a stream. Internal work and non-cartridge accesses advance an active stream.
|
||||
Matching queued ARM words or Thumb halfwords cost one cycle; partial words wait for the remaining halfword work.
|
||||
The CPU-side delivery cycle also advances active background work. A CPU N request can still hit the queue.
|
||||
ROM data accesses and nonmatching ROM code requests cancel the stream.
|
||||
Cancellation adds one cycle when an active halfword has one cycle remaining.
|
||||
Full-buffer production stops until the entries drain; the next empty demand restarts with N timing.
|
||||
Background production pauses before 128 KiB boundaries, where demand uses forced-N timing.
|
||||
|
||||
The queue stores no instruction bytes and performs no background memory reads.
|
||||
Missing lookahead and branch targets therefore keep their existing deferred diagnostic behavior.
|
||||
Successful CPU transactions commit queue progress; failures discard it.
|
||||
`Cpu::step` maintains the same queue as `Cpu::step_timed` when prefetch is enabled, without advancing device clocks.
|
||||
Cold or invalidated CPU pipelines clear staged queue metadata and retain nominal S startup timing.
|
||||
|
||||
Changes to ROM wait fields or prefetch enable clear queue metadata after the WAITCNT write.
|
||||
PHI/SRAM-only changes preserve it. Exact hardware live-reconfiguration behavior remains unverified.
|
||||
RAM DMA and HALT supply idle cartridge time; cartridge DMA cancels the stream. STOP freezes queue progress.
|
||||
Host reads and `Memory::advance_cycles` do not advance the queue; machine steps account for progress separately.
|
||||
|
||||
These are source-backed nominal rules, not a hardware conformance claim.
|
||||
See [queue evidence, regression coverage, and limits](../research/gamepak-prefetch.md).
|
||||
|
||||
### Nominal CPU resume after DMA
|
||||
|
||||
A successful DMA unit marks the next CPU instruction's nominal code access non-sequential.
|
||||
This applies even when DMA only accesses RAM. Consecutive units retain one pending resume, not multiple penalties.
|
||||
The source fetch uses its actual lookahead address, incoming width, and current WAITCNT with N instead of S.
|
||||
The source request uses its actual lookahead address, incoming width, and current WAITCNT with N instead of S.
|
||||
A matching enabled prefetch stream can satisfy that request without paying the raw N cost.
|
||||
This includes branches and accepted IRQ entry; target pairs still use N then S.
|
||||
ARM word accesses retain an S cost for their second halfword.
|
||||
CPU history and ROM boundaries that already require N do not receive an additional access.
|
||||
|
|
@ -390,7 +416,7 @@ Important timing limits:
|
|||
Cold entry, debugger invalidation, and PC/state mismatches use nominal S, not hardware-validated startup timing.
|
||||
- Refill cost calculation does not read target bytes. ARM/Thumb instruction-buffer and local IWRAM bus-history samples add no extra cycles.
|
||||
- Target-pair sampling cannot fail the branch early. An invalid branch target still fails on the following instruction fetch.
|
||||
- Game Pak prefetch is not implemented. WAITCNT bit 14 is stored but does not accelerate execution.
|
||||
- Game Pak prefetch is nominal. Full-buffer restart, page boundaries, cancellation, and live WAITCNT changes need independent hardware validation.
|
||||
- PHI and SRAM wait fields are stored; PHI output and SRAM mapping are not implemented.
|
||||
- External work RAM timing is fixed. The undocumented memory-control register is not implemented.
|
||||
- Exact DMA startup/resumption delays, display-bus contention, shared timer prescaler phase, and timer startup delays remain unmodeled.
|
||||
|
|
|
|||
|
|
@ -48,7 +48,11 @@ Timing uses independent source and destination bus costs, including WAITCNT and
|
|||
The first unit uses non-sequential accesses plus two internal cycles. Later units use sequential accesses.
|
||||
Each step reports zero code cycles. Overlapping transfers read each unit after the preceding write; they are not bulk host copies.
|
||||
A successful unit breaks the next nominal CPU code-access sequence, even if DMA accessed only RAM.
|
||||
The resumed non-refill instruction uses N code timing once; later instructions return to their normal summaries.
|
||||
The resumed instruction requests N once; enabled opcode prefetch can still satisfy a matching request.
|
||||
RAM accesses and the nominal startup cycles advance an active prefetch stream; cartridge accesses cancel it.
|
||||
Cancellation can add one data cycle at the final halfword phase. DMA never consumes queued opcodes.
|
||||
Only successful units commit queue progress; WAITCNT destinations apply configuration changes after the transfer.
|
||||
Exact startup/completion placement remains nominal, not independently verified prefetch arbitration.
|
||||
See [CPU resume timing](cpu.md#nominal-cpu-resume-after-dma) for failure, idle, and refill rules.
|
||||
Startup scheduling delays, channel-resumption costs, a full CPU fetch pipeline, and display-bus contention remain unmodeled.
|
||||
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ Display edges include every HBlank entry and scanline start. Cascaded timers rec
|
|||
These bounds prevent idle advances from skipping DMA triggers or wake-up events.
|
||||
They also keep frame execution bounded when no interrupt can wake the CPU.
|
||||
Idle steps neither fetch instructions nor change CPU registers; code, data, and internal cycle counts remain zero.
|
||||
HALT idle cycles advance an already active Game Pak opcode prefetch stream, without starting one.
|
||||
Exact hardware entry/exit delays and pipeline effects are not modeled.
|
||||
|
||||
CPU writes to POSTFLG and HALTCNT take effect only when the executing instruction address is within the 16 KiB BIOS region.
|
||||
|
|
@ -171,6 +172,7 @@ CPU-only stepping can record HALT/STOP but does not enforce either pause. Use `M
|
|||
Writing HALTCNT with bit 7 set requests STOP. Bits 0–6 are ignored.
|
||||
The instruction that writes STOP finishes and pays its full nominal cycle cost.
|
||||
Later machine steps perform no CPU fetch, DMA transfer, timer tick, or display update.
|
||||
The nominal Game Pak prefetch queue also remains frozen.
|
||||
`StepKind::StopIdle` reports zero timing; it does not represent elapsed host wall time.
|
||||
`Memory::stopped()` and `Machine::stopped()` report this state. The corresponding `halted()` methods return false in STOP.
|
||||
|
||||
|
|
|
|||
|
|
@ -206,8 +206,13 @@ Game Pak prefetch research:
|
|||
- 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.
|
||||
- [Jgenesis prefetch at fab6e2cc](https://github.com/jsgroth/jgenesis/blob/fab6e2ccc60e492dd68b7f1e927b0829a6d80195/backend/gba-core/src/prefetch.rs) and its [bus integration](https://github.com/jsgroth/jgenesis/blob/fab6e2ccc60e492dd68b7f1e927b0829a6d80195/backend/gba-core/src/bus.rs), for independent halfword capacity, full-buffer pause/restart, CPU delivery, and cancellation rules.
|
||||
- [NanoBoyAdvance boundary test at cc3f4a28](https://codeberg.org/nba-emu/hw-test/src/commit/cc3f4a286cdef823980d9b353bd70befc9927d28/bus/128kb-boundary/source/main.c), reviewed for data LDM/DMA boundaries, not active opcode-queue conformance.
|
||||
- [PrefetchAbuse](https://github.com/zaydlang/PrefetchAbuse), a search-excerpt-only cancellation-test lead. Its source and ROM were not used.
|
||||
|
||||
See [prefetch behavior and evidence](research/gamepak-prefetch.md).
|
||||
The nominal queue is implemented. Source differences and live WAITCNT transitions remain validation questions.
|
||||
No hardware conformance result is claimed.
|
||||
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ No extra access is appended. A resumed ROM branch can therefore cost more than i
|
|||
The later [sequencing extension](fetch-access-sequencing.md) applies each instruction's data/internal effects to the following source fetch.
|
||||
CPU history, DMA resume, and ROM page boundaries can all require N without duplicating an access.
|
||||
A completed transfer after DMA can establish a new N requirement for the following fetch.
|
||||
Game Pak prefetch remains unimplemented; WAITCNT bit 14 does not alter this nominal timing path.
|
||||
This baseline preceded active prefetch. The later [nominal queue](gamepak-prefetch.md) can satisfy an N resume request from queued code.
|
||||
|
||||
This change does not select a DMA value for CPU open-bus reads.
|
||||
DMA channel data, persistent local IWRAM lanes, and protected BIOS history remain separate.
|
||||
|
|
|
|||
|
|
@ -123,8 +123,10 @@ The timer therefore runs two additional cycles before the handler stops it.
|
|||
- Cold-start costs and state-changing test/compare quirks are not hardware-validated.
|
||||
- Data timing still uses an instruction-local access trace. This is not a complete bus-event scheduler.
|
||||
- Device clocks still update once per instruction, IRQ entry, or DMA unit.
|
||||
- Game Pak prefetch, configurable EWRAM timing, display contention, and DMA during internal cycles remain unimplemented.
|
||||
- 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 later [prefetch prerequisite](gamepak-prefetch.md) records source, data, internal, and refill costs in order without changing totals.
|
||||
The later ordered timing transaction preserved these baseline totals.
|
||||
The subsequent [nominal prefetch queue](gamepak-prefetch.md) uses those events and can accelerate code despite a CPU N request.
|
||||
CPU access-kind rules remain separate from the queue's cartridge-bus timing.
|
||||
The next timing work remains an active Game Pak queue, with verified startup and invalidation rules and independent tests.
|
||||
|
|
|
|||
|
|
@ -72,10 +72,11 @@ The later [refill timing extension](refill-fetch-timing.md) also charges source
|
|||
- Thumb BL prefixes use their lookahead address; suffixes add the target pair.
|
||||
- Cold fills have no separate startup charge, even though their samples update supported bus history.
|
||||
- Devices advance once after the whole successful instruction. No per-access timer/IRQ update is introduced.
|
||||
- Game Pak prefetch, display contention, configurable EWRAM timing, and sub-instruction DMA arbitration remain unimplemented.
|
||||
- Display contention, configurable EWRAM timing, and sub-instruction DMA arbitration remain unimplemented.
|
||||
- The later [nominal prefetch queue](gamepak-prefetch.md) changes code costs when bit 14 is enabled.
|
||||
|
||||
This is a fetch-address correction within the existing timing model, not cycle-accurate emulation.
|
||||
The next timing step is Game Pak prefetch with verified startup and invalidation rules.
|
||||
Game Pak prefetch followed this baseline; independent startup and invalidation timing validation remains necessary.
|
||||
|
||||
## Original regression coverage
|
||||
|
||||
|
|
|
|||
|
|
@ -1,115 +1,139 @@
|
|||
# Game Pak prefetch: evidence and timing prerequisites
|
||||
# Game Pak prefetch: nominal queue and evidence
|
||||
|
||||
## 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.
|
||||
WAITCNT bit 14 enables a nominal Game Pak opcode prefetch queue.
|
||||
The queue tracks eight halfwords, partial transfers, full-buffer stops, and cancellation stalls.
|
||||
It follows ordered CPU timing events and the existing instruction-boundary DMA scheduler.
|
||||
This is source-backed timing behavior, not hardware-verified accuracy.
|
||||
|
||||
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.
|
||||
The queue stores addresses and timing metadata, not ROM bytes.
|
||||
CPU instruction retention, BIOS protected-read history, and IWRAM local lanes remain separate.
|
||||
Background progress cannot cause an early ROM-file lookup or change instruction values.
|
||||
|
||||
## 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.
|
||||
- [GBATEK GamePak Prefetch](https://www.problemkaputt.de/gbatek-gba-gamepak-prefetch.htm) describes eight 16-bit entries, opcode-only service, and idle-bus progress.
|
||||
- [mGBA's cycle-counting article](https://mgba.io/2015/06/27/cycle-counting-prefetch/) explains independent cartridge progress and partially completed fetches.
|
||||
Its examples and linked timing suite provide validation leads, 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 hits, partial fetches, misses, and cancellation stalls.
|
||||
- [ares prefetch at 6f6786e0](https://github.com/ares-emulator/ares/blob/6f6786e04f0822a3475463df284f313ab8518d51/ares/gba/cpu/prefetch.cpp) uses halfword entries and stops at capacity or page boundaries.
|
||||
Its [bus dispatcher](https://github.com/ares-emulator/ares/blob/6f6786e04f0822a3475463df284f313ab8518d51/ares/gba/cpu/bus.cpp) separates opcode requests, data requests, and other-memory progress.
|
||||
- [Jgenesis prefetch at fab6e2cc](https://github.com/jsgroth/jgenesis/blob/fab6e2ccc60e492dd68b7f1e927b0829a6d80195/backend/gba-core/src/prefetch.rs) independently supports halfword entries, full-buffer stopping, and last-cycle cancellation stalls.
|
||||
Its [bus integration](https://github.com/jsgroth/jgenesis/blob/fab6e2ccc60e492dd68b7f1e927b0829a6d80195/backend/gba-core/src/bus.rs) separates CPU delivery cycles from background transfers and DMA ownership.
|
||||
- [NanoBoyAdvance 128 KiB boundary test at cc3f4a28](https://codeberg.org/nba-emu/hw-test/src/commit/cc3f4a286cdef823980d9b353bd70befc9927d28/bus/128kb-boundary/source/main.c) tests data LDM and DMA boundaries.
|
||||
Reading this test does not validate active opcode-queue crossings. It was not run here.
|
||||
- [PrefetchAbuse](https://github.com/zaydlang/PrefetchAbuse) appeared in search results as a cartridge-access cancellation test lead.
|
||||
Only its search excerpt was reviewed. No expectations or implementation code were taken from it.
|
||||
|
||||
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.
|
||||
## Implemented queue rules
|
||||
|
||||
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.
|
||||
Raw ROM costs include one clock plus the configured wait states for each halfword.
|
||||
The public `bus_cycles` helper remains stateless and does not apply prefetch.
|
||||
|
||||
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.
|
||||
1. A ROM code miss pays the requested raw cost, plus any cancellation stall.
|
||||
It starts background fetching at the following halfword address.
|
||||
2. Internal cycles and non-cartridge memory accesses advance an already active stream.
|
||||
They cannot start a stream by themselves.
|
||||
3. A code request must match the queue head. CPU N requests can still match queued code.
|
||||
A queued Thumb halfword or complete ARM word costs one CPU-side cycle.
|
||||
4. That CPU-side cycle also advances background work when production is active.
|
||||
A partial ARM word waits separately for its missing halfwords.
|
||||
5. Background production stops when an advance observes all eight entries occupied.
|
||||
It remains stopped while the queue drains. The next empty demand restarts with N timing.
|
||||
6. ROM data accesses cancel the stream instead of consuming opcode entries.
|
||||
A nonmatching ROM code request also cancels it before starting a new stream.
|
||||
7. Cancellation costs one additional cycle when an active halfword has one cycle remaining.
|
||||
A paused or fully occupied queue does not add that stall.
|
||||
8. Background production pauses before a 128 KiB ROM boundary.
|
||||
Demand at that boundary uses raw forced-N timing and starts the next stream.
|
||||
No background transfer crosses beyond the final ROM window.
|
||||
|
||||
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.
|
||||
The full-buffer policy follows ares and Jgenesis.
|
||||
The page-boundary policy follows ares conservatively; the reviewed sources differ in this area.
|
||||
The cancellation cycle is included in the requesting code or data field of `StepTiming`.
|
||||
These rules have original regression tests, not a hardware conformance result.
|
||||
|
||||
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.
|
||||
## Timing transactions and ownership
|
||||
|
||||
`Memory` owns the committed queue because CPU, DMA, and HALT share cartridge-bus time.
|
||||
Each `CpuTiming` transaction stages a copy and applies events in order:
|
||||
|
||||
1. Source instruction fetch at ARM P+8 or Thumb P+4.
|
||||
2. Actual data accesses, using aligned bus addresses and widths.
|
||||
3. Internal cycles from the incoming instruction classification.
|
||||
4. Refill target N and target+width S accesses, using the resulting instruction state.
|
||||
|
||||
IRQ entry records the discarded incoming-state source, then the ARM vector pair.
|
||||
Non-ROM code fetches advance the existing ROM stream without consuming it.
|
||||
A branch can therefore preserve the stream while executing a BIOS handler.
|
||||
A later ROM fetch still needs an exact head match to use queued timing.
|
||||
|
||||
Success commits queue progress. A diagnostic discards all staged progress, including earlier successful data accesses.
|
||||
Missing lookahead or target bytes retain deferred diagnostics and nominal attempted-fetch costs.
|
||||
Device clocks still advance once after a successful machine step, not after each timing event.
|
||||
|
||||
`Cpu::step_timed` updates the queue and returns costs without advancing devices.
|
||||
`Cpu::step` uses the same path when prefetch is enabled, but discards returned costs.
|
||||
With prefetch disabled, the CPU-only path retains its previous untimed behavior.
|
||||
Host reads, setup writes, and `Memory::advance_cycles` do not supply queue progress.
|
||||
Host WAITCNT writes do apply queue configuration.
|
||||
|
||||
Cold entry, debugger invalidation, and PC/state mismatches clear staged queue metadata.
|
||||
They preserve the existing nominal S startup policy and add no current/decode fill charge.
|
||||
Accepted IRQ entry uses the interrupted pipeline's cold/retained state before replacing that pipeline.
|
||||
Failed CPU steps preserve the previously committed queue.
|
||||
|
||||
### WAITCNT changes
|
||||
|
||||
A store pays source and data costs using the previous settings.
|
||||
After the write, changing ROM wait fields or bit 14 clears timing metadata immediately.
|
||||
Changing only SRAM or PHI fields preserves the stream.
|
||||
CPU, host byte/halfword/word, and DMA writes use this configuration policy.
|
||||
|
||||
This reset policy is deliberate, not a verified model of live hardware reconfiguration.
|
||||
Jgenesis models retained entries after disable; that behavior is not implemented here.
|
||||
Exact enable/disable transitions and changes during a partial transfer need independent tests.
|
||||
|
||||
### DMA and idle
|
||||
|
||||
A DMA unit stages queue progress independently of the CPU transaction.
|
||||
Its existing two startup cycles precede source and destination accesses in the nominal model.
|
||||
RAM-only DMA supplies idle cartridge time. Cartridge DMA cancels the stream and can incur the completion-edge stall.
|
||||
A failed unit preserves queue state and clocks. A successful WAITCNT destination applies the new configuration.
|
||||
DMA's CPU-resume N request remains separate; a matching queue entry can still satisfy that request.
|
||||
|
||||
`HaltIdle` advances an active queue with its idle cycles. `StopIdle` freezes it.
|
||||
Machine device updates do not advance the queue a second time.
|
||||
Exact DMA startup/completion placement, bus arbitration, and hardware HALT/STOP edges remain unverified.
|
||||
|
||||
## 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.
|
||||
Queue tests cover all ROM windows, all N/S settings, ARM/Thumb widths, partial words, capacity, and restart.
|
||||
They check every cancellation phase around a fill, exact-head matching, data cancellation, and page/window boundaries.
|
||||
Configuration tests distinguish relevant fields from PHI/SRAM fields.
|
||||
A seeded batched-versus-single-clock comparison checks progression consistency, not independent hardware correctness.
|
||||
|
||||
Coverage includes:
|
||||
Integration tests cover RAM loads, register shifts, ROM data stalls, branch hits/misses, and PC-load refills.
|
||||
They check timed/CPU-only equivalence, debugger invalidation, IRQ entry, WAITCNT writes, DMA, HALT, and STOP.
|
||||
Failure tests cover late block loads, missing ROM bytes, failed DMA, retries, and host isolation.
|
||||
Instruction-pair matrices separately assert CPU N/S kinds and prefetch-adjusted costs.
|
||||
Existing ordered-event tests retain source/data/internal/refill ordering checks, including a full-register LDM with PC.
|
||||
Test builds retain an event log; production builds allocate no event log or queue storage on the heap.
|
||||
|
||||
- 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
|
||||
## Validation and remaining limits
|
||||
|
||||
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.
|
||||
Public ARM, Thumb, memory, and BIOS reports match the preceding ordered-timing change exactly, including cycles and step counts.
|
||||
Debug and release reports also match. Original CPU and timer demo traces are unchanged.
|
||||
These public checkpoints do not independently validate active prefetch timing.
|
||||
|
||||
## 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.
|
||||
Next, validate this queue against independent timing tests, especially full-buffer restart, cancellation, and page boundaries.
|
||||
Cold-start timing, live WAITCNT reconfiguration, per-access device scheduling, and sub-instruction DMA arbitration remain incomplete.
|
||||
Exact bus history, display contention, configurable EWRAM timing, and timer/IRQ delays remain separate work.
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ The stopped counter therefore increases by five even though the final machine-cy
|
|||
- Cold current/decode fills have no separate startup timing charge.
|
||||
- BIOS retained history is not a complete refill/data-access bus latch.
|
||||
- Missing instruction bytes remain diagnostics, not hardware prefetch aborts.
|
||||
- Game Pak prefetch, per-access device updates, display contention, configurable EWRAM timing, and sub-instruction DMA arbitration remain unimplemented.
|
||||
- Per-access device updates, display contention, configurable EWRAM timing, and sub-instruction DMA arbitration remain unimplemented.
|
||||
- The later [nominal prefetch queue](gamepak-prefetch.md) can change source and target costs when bit 14 is enabled.
|
||||
|
||||
The next timing work is Game Pak prefetch with verified startup and invalidation rules.
|
||||
Game Pak prefetch followed this baseline; independent startup and invalidation timing validation remains necessary.
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ Update this file when a feature lands or a limit is removed.
|
|||
- 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.
|
||||
- Game Pak wait-state control (`WAITCNT`) for all three ROM windows.
|
||||
- Bit 14 enables a nominal eight-halfword opcode prefetch queue, with partial fetches, cancellation, and DMA/idle integration.
|
||||
- Sequential/non-sequential data accesses, branch refill costs, and variable multiply timing.
|
||||
- Optional caller-supplied 16 KiB BIOS mapping, with CPU read protection based on retained ARM PC+8 or aligned Thumb PC+4 words.
|
||||
- Optional original BIOS replacement: minimal boot, SoftReset, selective RegisterRamReset, IRQ dispatch, interrupt waits, memory copy/fill, integer/fixed-point arithmetic, affine matrices, bit unpacking, LZ77/run-length/Huffman decompression, and differential filters.
|
||||
|
|
@ -117,6 +118,8 @@ This diagnostic policy does not reproduce partial transfers during hardware data
|
|||
CPU instructions, including swaps, finish before a newly requested DMA unit runs. Sub-instruction bus arbitration is not modeled.
|
||||
CPU/bus costs are nominal estimates, not a cycle-accurate implementation.
|
||||
The instruction buffer retains the next fetch kind; cold startup costs and per-access device scheduling remain unmodeled.
|
||||
Game Pak prefetch uses source-backed queue rules, not hardware-verified timing.
|
||||
Live WAITCNT transitions, page-boundary behavior, and exact DMA/idle ordering still need independent timing validation.
|
||||
Graphics support includes Mode 0–5 debug snapshots and HBlank row capture with sprites, mosaic, windows, and color effects.
|
||||
Internal affine origins, vertical window flags, and vertical mosaic counters track line boundaries.
|
||||
Horizontal window comparators retain four-cycle event history.
|
||||
|
|
@ -167,9 +170,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 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).
|
||||
2. Validate the active nominal Game Pak prefetch queue against independent timing tests.
|
||||
Prioritize full-buffer restart, cancellation, page boundaries, and live WAITCNT transitions.
|
||||
See [prefetch behavior and evidence](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.
|
||||
|
|
|
|||
|
|
@ -267,9 +267,14 @@ Page/wait-window crossings, masked IRQs, host/HALT isolation, and pre-write WAIT
|
|||
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.
|
||||
WAITCNT snapshots, late failure rollback, deferred fetch errors, and host/DMA isolation have separate checks.
|
||||
CPU-only execution joins the timing path when prefetch is enabled.
|
||||
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.
|
||||
Prefetch queue tests cover every ROM wait setting and width, partial ARM words, full-buffer stops, restart, and cancellation phases.
|
||||
They also check page/window boundaries, configuration changes, and batched-versus-single-clock consistency.
|
||||
Integration tests check RAM/internal progress, ROM data stalls, branch and IRQ fetches, CPU-only equivalence, and debugger invalidation.
|
||||
WAITCNT CPU/host/DMA writes, RAM/cart DMA, HALT/STOP, failed steps, and missing ROM bytes have separate checks.
|
||||
See [prefetch evidence and limits](research/gamepak-prefetch.md). These tests validate the nominal model, not physical-hardware accuracy.
|
||||
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