Skip to content

Unify the register-write effect pipeline: slot-referenced write-effect delays for CPU writes#149

Merged
LinuxJedi merged 2 commits into
mainfrom
fix/unified-write-effect-pipeline
Jul 7, 2026
Merged

Unify the register-write effect pipeline: slot-referenced write-effect delays for CPU writes#149
LinuxJedi merged 2 commits into
mainfrom
fix/unified-write-effect-pipeline

Conversation

@LinuxJedi

Copy link
Copy Markdown
Owner

What

CPU register writes now record their render/collision events at the chip-bus slot that carried the write plus the register class's write-to-effect delay - the same rule Copper writes have used since #146 - replacing the copper-only compensation twin and its TODO:

  • Denise-boundary registers (COLOR, BPLCONx, sprites, BPL1DAT, CLXCON, ...): slot + 4 cck (DENISE_WRITE_EFFECT_DELAY_CCK).
  • Agnus's two-cycle register class (DMACON, BPLxPT, BPLxMOD, SPRxPT; vAmiga recordRegisterChange(DMA_CYCLES(2))): slot + 2 cck (AGNUS_WRITE_EFFECT_DELAY_CCK).

Previously CPU events were recorded at the live beam position, which sits 2 cck past the granted slot on the classic bus once the write's bus cycle has been billed - so CPU Denise-class events carried a hidden -2 cck bias, and the offset silently depended on the CPU model (the 020+ short bus cycle leaves a different tail). The granted slot is remembered across the access (Bus::cpu_custom_access_slot, transient, #[serde(skip)] - STATE_VERSION stays 26).

Evidence (two-sided landing traces)

New probe pair: COPPERLINE_DIAG_CPU_WRITES=1 logs every CPU custom write's granted slot + effect position; an additive env-gated vAmiga patch (VAMIGA_CPU_PROBE=1, vamigats-reports/vamiga-cpu-probe.patch) logs every CPU-sourced pokeCustom16 with its beam position. Traces are aligned per IRQ episode on the copper INTREQ MOVE landings, which are bus-identical since #146.

  • DMACON/sprenacpu1 (dense CPU COLOR00 stream + IRQ pips): intra-handler write cadence (ack -> pip -> DMACON -> pip) matches vAmiga cycle-for-cycle on all ~50 episodes/frame. On the 14 scanlines whose COLOR00 landings match vAmiga line-for-line, CL rendered exactly 8 px (2 cck) LEFT of vAmiga at baseline; with this change all 14 render at shift 0. CIA/TOD latch2 (copper-driven bars) pins the copper side at 0.000% throughout.
  • DMACON/bploncpu1: landing-matched lines render at 0.000 residual after the change.
  • Agnus two-cycle class: pinned by the DMACON bplon bitplane-gating bars, which sit 8 px right of vAmiga if those events carry the Denise delay instead of DMA_CYCLES(2).

vAmigaTS family numbers (dual-setup sums, baseline = merged main @12fc0b1)

family baseline this PR delta
Paula/Interrupts (168) 1185.6 1127.8 -57.8
... inttim bucket (66) 524.3 504.4 -19.9
Agnus/Copper guard (223) 949.1 930.5 -18.6
... coptim bucket (24) 44.18 42.46 -1.72
Agnus/Registers/DMACON (63) 1041.8 1118.8 +77.0
... sprena/sprdis bucket (24) 899.8 884.8 -15.0
... bplon/bpoffbug bucket (17) 95.8 187.9 +92.1 (see below)
CIA (93) 610.5 628.1 +17.6 (see below)
Mainboard (88) 1075.4 1078.1 +2.7
... POT bucket (32) 750.7 750.7 0.0 (pure cadence class)
Denise guard (322) 1245.0 1245.0 byte-identical (one case -0.04pp)
Memory (11) 426.8 426.2 -0.6

What the fix exposes (characterized, not chased here)

The old -2 bias partially cancelled a REAL remaining divergence: the CPU write LANDING phase. The new probes measure it cleanly; each item is a separate follow-up model, none is a pipeline constant:

  • IRQ-handler entry (sprena class): per-episode landing deltas quantized by the interrupted busy-loop instruction boundaries; mode +2 cck late, scatter -7..+13.
  • E-clock-synced CIA loops (cnt/oldcnt, the CIA +17.6): bimodal 0 / +5 cck (oldcnt cnt1: 380 landings exact, 412 at +5). CL's E_SYNC_DELAY_CCK[5] is vAmiga's syncWithEClock even-phase projection at cck resolution; the odd phases (and the eClk7 15-clock case) are unreachable.
  • VHPOSR read value: CL reports slot+4 (post-grant beam + lookahead 2), vAmiga reports slot+5 (pos + 5 in peekVHPOSR) - 1 cck low, so poll-exit boundaries differ in ~1/13 loop phases. VHPOSR_LOOKAHEAD_CCK was calibrated (PR agnus: hardware VHPOSR/VHPOSW semantics (first vAmigaTS triage fix) #101) under the old bias; retune only with a two-sided poll-exit trace.
  • bplon/bpoffbug +92.1: the tests' full-screen background bands come from a free-running VHPOSR-quantized COLOR00 loop whose per-line phases decorrelate between emulators; the -2 bias netted more accidental pixel overlap. On landing-matched lines the new render is exact (0.000 residual).

Gates

  • cargo test --lib: 1329 green (13 collision/render tests re-staged to the slot-referenced semantics; every asserted hardware boundary unchanged).
  • cargo clippy --all-targets --all-features --locked -- -D warnings + fmt: clean.
  • 14-demo set vs merge-base 12fc0b1: ALL BYTE-IDENTICAL (eon, sota, itm, hamazing, genx, kick13boot, kicka1200, secondnature, roots-ecs, roots-aga, gods, rebirth, tomato, zool).
  • Denise family byte-identical; Agnus/Copper (incl. coptim) improved; CIA/TOD latch2 0.000% unchanged.
  • No serialized-state shape change; STATE_VERSION stays 26.

LinuxJedi added 2 commits July 7, 2026 09:09
…slot

A register write takes effect a fixed number of colour clocks after the
chip-bus slot that carried it, and the delay belongs to the register
pipeline, not to the bus master: Denise-boundary registers apply about
four colour clocks after the slot (DENISE_WRITE_EFFECT_DELAY_CCK), and
Agnus's two-cycle class (DMACON, BPLxPT, BPLxMOD, SPRxPT; vAmiga
recordRegisterChange DMA_CYCLES(2)) applies two colour clocks after the
slot (AGNUS_WRITE_EFFECT_DELAY_CCK).

Copper MOVEs execute at their bus slot, so their render events already
recorded slot + 4 since the write-landing fix. CPU writes, however, were
recorded at the live beam position - which sits past the granted slot by
the bus cycle's tail (two colour clocks on the classic bus, less on the
020+ short cycle), leaving CPU Denise-class events two colour clocks
early and making the offset CPU-model dependent. The granted slot is now
remembered across the access (Bus::cpu_custom_access_slot, transient) and
all CPU render events are referenced from it.

Two-sided evidence against vAmiga (VAMIGA_CPU_PROBE poke trace vs the
granted-slot positions): on vAmigaTS DMACON/sprenacpu1, all 14 scanlines
whose dense CPU COLOR00 landings match vAmiga line-for-line rendered
exactly two colour clocks left of vAmiga before this change and at zero
offset after it, while the copper-driven CIA/TOD latch2 bars hold 0.000%
throughout. The Agnus two-cycle class is pinned by the DMACON bplon
bitplane-gating bars, which sit two colour clocks right of vAmiga if
those events carry the Denise delay instead.

Copper-sourced events keep the Denise delay for the Agnus two-cycle
class: the copper-driven DMA-gating replay was calibrated with that
offset when the copper landings became bus-exact (documented TODO).

The staged collision/render unit tests move their write slots four
colour clocks ahead of the intended recorded positions, keeping every
asserted boundary identical. No serialized-state shape change.
…CPU_WRITES

Log every CPU custom-register write's granted chip-bus slot and the beam
position its effect applies at, in the same format as the copper landing
trace (COPPERLINE_DIAG_COP_WRITES), for cross-emulator landing comparison
against vAmiga's env-gated VAMIGA_CPU_PROBE pokeCustom16 probe
(vamigats-reports/vamiga-cpu-probe.patch in the reference checkout).

The two-sided histograms this pair produces separate the write-effect
pipeline (now modelled) from the remaining CPU write-landing phase
divergence: IRQ-handler entries land with a quantized scatter around a
+2 colour-clock mode (busy-loop instruction boundaries), and E-clock
synced CIA loops land bimodally at 0 / +5 colour clocks (the CIA E-sync
table is vAmiga's even-phase projection at colour-clock resolution).
@LinuxJedi LinuxJedi merged commit 063af0d into main Jul 7, 2026
8 checks passed
@LinuxJedi LinuxJedi deleted the fix/unified-write-effect-pipeline branch July 7, 2026 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant