feat(cpu): retain Thumb instruction pipeline halfwords
This commit is contained in:
parent
47df9d05a7
commit
ea055270f4
21 changed files with 535 additions and 97 deletions
|
|
@ -24,7 +24,8 @@ No external source code or test ROM was imported. No physical-hardware or extern
|
|||
|
||||
## Implementation
|
||||
|
||||
`cpu/pipeline.rs` owns a private two-slot ARM continuation with its expected execution PC.
|
||||
`cpu/pipeline.rs` owns a private two-slot continuation with its expected execution PC and instruction state.
|
||||
The later [Thumb extension](thumb-instruction-buffer.md) uses this same structure for halfwords.
|
||||
Each slot retains either a mapped word or its strict fetch error.
|
||||
`Cpu` owns and clones this state; full CPU equality includes it.
|
||||
|
||||
|
|
@ -37,13 +38,13 @@ Successful non-refill ARM execution commits the next pair.
|
|||
A successful refill into ARM instead samples T and T+4 after data transfers and status restoration.
|
||||
This includes ARM/Thumb BX, ARM PC writes and loads, taken branches, exception returns, and SWI vectors.
|
||||
A refill to the sequential address still discards the previous sequential pair.
|
||||
Untaken branches retain the pair. Leaving ARM clears it; Thumb continues to use direct instruction reads.
|
||||
Untaken branches retain the pair. A transition to Thumb now replaces it with a Thumb target pair.
|
||||
|
||||
Machine IRQ entry captures its vector pair immediately after exception entry.
|
||||
The standalone exception APIs have no Memory argument, so they invalidate the old pair and leave the vector cold.
|
||||
This distinction is explicit rather than retaining unrelated words at a coincident PC.
|
||||
|
||||
`Memory::fetch_arm_word` reads aligned mapped words without CPU data context, timing traces, or bus-history changes.
|
||||
`Memory::fetch_instruction` reads aligned mapped instructions without CPU data context, timing traces, or bus-history changes.
|
||||
Normal memory mirrors apply. Unmapped, truncated, and misaligned fetches retain their existing errors.
|
||||
No BIOS-protected data value or general open-bus value can become a synthetic instruction through this path.
|
||||
|
||||
|
|
@ -74,7 +75,7 @@ The current instruction address still selects nominal code cost rather than a se
|
|||
ARM PC+8 open bus and protected BIOS readback remain separate snapshots.
|
||||
The instruction-buffer sample and those snapshots see mapped memory before instruction effects, but no unified per-access bus model exists yet.
|
||||
The target samples do not establish complete ARM IWRAM or BIOS bus history.
|
||||
Thumb buffering, instruction-state-changing compare quirks, Game Pak prefetch, and DMA arbitration remain incomplete.
|
||||
Instruction-state-changing compare quirks, Game Pak prefetch, and DMA arbitration remain incomplete.
|
||||
DMA still runs between whole instructions, not during their data accesses or internal cycles.
|
||||
|
||||
## Original regression coverage
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ A completed DMA WAITCNT store changes the settings before CPU resume.
|
|||
## Limits
|
||||
|
||||
The timing model has no per-access fetch scheduling or DMA arbitration.
|
||||
The later [ARM instruction buffer](arm-instruction-buffer.md) retains instruction words but does not change these nominal costs.
|
||||
The later [ARM](arm-instruction-buffer.md) and [Thumb](thumb-instruction-buffer.md) instruction buffers retain instructions without changing these nominal costs.
|
||||
It charges the current instruction address, not a separately scheduled PC+4/PC+8 pipeline fetch.
|
||||
DMA still executes only between instructions, not between data accesses or during CPU internal cycles.
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ An accepted machine IRQ invalidates history. Failed DMA units preserve it.
|
|||
The DMA extension below updates existing continuation lanes from successful IWRAM accesses.
|
||||
|
||||
This is not a full IWRAM bus model across all CPU states. ARM-target history and DMA-to-CPU ordering remain incomplete.
|
||||
It is not a persistent instruction pipeline. Self-modifying instruction execution and exact per-access device timing remain unverified.
|
||||
It is not a persistent instruction pipeline. Exact per-access device timing remains unverified.
|
||||
|
||||
## Thumb IWRAM refill extension
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ Unmapped instruction targets still fail on the following fetch.
|
|||
Cold direct startup and arbitrary PC changes do not manufacture a refill.
|
||||
|
||||
These are bus-history samples, not instruction-buffer contents or extra emulated cycles.
|
||||
The interpreter still reads Thumb instructions when it executes them; ARM now has separate instruction buffering.
|
||||
ARM and Thumb execution now use a separate instruction buffer. Cold buffer filling does not seed this bus history.
|
||||
Changing T+2 after the branch does not replace its captured bus value; changing T+4 before arrival affects the later sample.
|
||||
Those original tests verify sample ordering, not hardware-accurate self-modifying instruction execution.
|
||||
|
||||
|
|
@ -111,8 +111,8 @@ Only complete successful units commit history, preserving the project's atomic d
|
|||
Cold direct entry still has no expected continuation PC. DMA does not manufacture one, even after a word access.
|
||||
An existing partially known continuation can gain lanes. IRQ entry and CPU discontinuities retain their invalidation rules.
|
||||
General DMA open-bus reads, cross-state history, sub-instruction arbitration, and DMA during CPU internal cycles remain outside this subset.
|
||||
This extension does not fix self-modifying Thumb instruction-buffer behavior.
|
||||
The later [ARM instruction buffer](arm-instruction-buffer.md) separately retains ARM words across DMA.
|
||||
This extension models bus lanes, not self-modifying instruction execution.
|
||||
The later [ARM](arm-instruction-buffer.md) and [Thumb](thumb-instruction-buffer.md) instruction buffers separately retain instructions across DMA.
|
||||
|
||||
No physical-hardware measurements or external emulator differential runs were performed.
|
||||
All regression programs are original, with a separate byte-array lane reference in the DMA matrix tests.
|
||||
|
|
|
|||
85
docs/research/thumb-instruction-buffer.md
Normal file
85
docs/research/thumb-instruction-buffer.md
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
# Persistent Thumb instruction buffering
|
||||
|
||||
## Evidence and scope
|
||||
|
||||
The [ARM7TDMI pipeline description](https://developer.arm.com/documentation/dvi0027/b/arm7tdmi/instruction-pipeline) identifies fetch, decode, and execute stages.
|
||||
The [technical reference manual](https://documentation-service.arm.com/static/5e8e1323fd977155116a3129) describes Thumb's two-byte instruction width and visible PC offset of four bytes.
|
||||
The [Thumb BL cycle sequence](https://support.arm.com/documentation/ddi0210/c/Instruction-Cycle-Timings/Thumb-branch-with-link) distinguishes the sequential prefix from the branching suffix.
|
||||
|
||||
[NanoBoyAdvance at 55b5cf0a](https://github.com/nba-emu/NanoBoyAdvance/blob/55b5cf0ae3d929582ac5bfd486558173502b8354/src/nba/src/arm/arm7tdmi.hh) provides an implementation cross-check:
|
||||
|
||||
- `Run` takes the retained current instruction and shifts the next instruction forward.
|
||||
- In Thumb state, it reads the next halfword before executing the current instruction.
|
||||
- `ReloadPipeline16` reads target T, then T+2. The target instruction later fetches T+4.
|
||||
- `ReloadPipeline32` uses ARM's four-byte width instead.
|
||||
|
||||
Thus, execution at P retains the halfwords at P+2 and P+4 before instruction effects.
|
||||
A store cannot replace these retained instructions. It can affect P+6, which is fetched later.
|
||||
A taken PC write discards the sequential pair, even when its destination equals fallthrough.
|
||||
The BL prefix retains its suffix; only the suffix refills the target pair.
|
||||
|
||||
This extends the [ARM instruction buffer](arm-instruction-buffer.md), not the bus scheduler.
|
||||
No external source code or test ROM was imported. No physical-hardware or external-emulator differential run was performed.
|
||||
|
||||
## Implementation
|
||||
|
||||
`cpu/pipeline.rs` shares one two-slot buffer between ARM and Thumb.
|
||||
Each buffer records its expected execution PC and instruction state.
|
||||
Both must match before retained instructions can be reused.
|
||||
Thumb halfwords are zero-extended in the slots; upper bits do not hold another instruction.
|
||||
|
||||
Cold execution reads the current instruction and samples the next two instructions.
|
||||
Sequential execution uses retained results and samples only P+4 in Thumb state.
|
||||
The prospective continuation commits only after successful execution.
|
||||
Refills sample the target pair after data transfers and status restoration, using the resulting instruction state.
|
||||
ARM-to-Thumb BX and saved-state exception returns therefore capture T and T+2, not T and T+4.
|
||||
Thumb-to-ARM transitions and SWI/IRQ vectors capture ARM pairs.
|
||||
|
||||
`Memory::fetch_instruction` uses strict mapped reads with the selected instruction width.
|
||||
A Thumb fetch reads exactly two bytes, even in a region whose separate bus snapshot uses a full word.
|
||||
Memory mirrors apply. Unmapped and misaligned instruction reads retain diagnostics rather than using data open bus.
|
||||
Lookahead errors remain deferred until their slot executes; a branch can discard them.
|
||||
|
||||
Failed execution preserves the previous buffer exactly. Newly sampled lookahead does not commit.
|
||||
CPU stores, DMA transfers, and host writes never replace retained instructions automatically.
|
||||
`Cpu::invalidate_pipeline()` explicitly discards retained instructions for debugger repair or attachment to different memory.
|
||||
It does not clear separate BIOS or IWRAM bus history.
|
||||
CPU clones own independent buffers; full CPU equality includes them.
|
||||
|
||||
## Separation from bus history and timing
|
||||
|
||||
Instruction retention and data-bus snapshots remain separate models.
|
||||
Cold instruction-buffer filling does not make unknown IWRAM bus lanes known.
|
||||
Successful DMA can update existing IWRAM bus lanes without changing retained CPU instructions.
|
||||
Refill bus-history sampling and instruction sampling currently perform separate strict mapped reads.
|
||||
|
||||
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.
|
||||
Unified fetch-driven bus history, exact region crossings, per-access timing, Game Pak prefetch, and sub-instruction DMA arbitration remain incomplete.
|
||||
Instruction-state-changing compare quirks also remain hardware-unverified.
|
||||
|
||||
## Original regression coverage
|
||||
|
||||
Original programs cover:
|
||||
|
||||
- CPU byte/halfword stores to P+2, P+4, and the later P+6 instruction.
|
||||
- Host writes, RAM/video mirrors, and halfword/word DMA writes.
|
||||
- Taken and untaken branches, PC writes to fallthrough, and standalone BL suffixes.
|
||||
- BL prefix retention and suffix refill, with unchanged nominal costs.
|
||||
- ARM-to-Thumb target pairs at both halfword alignments and SWI/IRQ saved-state returns.
|
||||
- Failed data loads, discarded speculative advances, deferred short-ROM errors, and strict target diagnostics.
|
||||
- Debugger invalidation, independent clones, PC/state mismatches, and alignment errors.
|
||||
- Equal timed/untimed buffers without additional nominal cycles.
|
||||
|
||||
The retention regressions failed with the previous direct-fetch Thumb interpreter before implementation.
|
||||
Existing bus-history tests now invalidate deliberately repaired code or repair a data address without changing the retained instruction.
|
||||
Successful instruction-semantic tests compare architectural state separately; failed-step tests still compare complete CPU state.
|
||||
|
||||
## 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 previous ARM-buffer reports exactly, including nominal cycle counts.
|
||||
Debug and release reports also match for the same fixture paths.
|
||||
These checks do not establish full hardware pipeline or timing conformance.
|
||||
Loading…
Add table
Add a link
Reference in a new issue