Skip to content

agnus: evaluate sprite DMA lines at both hardware slots#114

Merged
LinuxJedi merged 1 commit into
mainfrom
fix/sprite-two-slot-fetch
Jul 4, 2026
Merged

agnus: evaluate sprite DMA lines at both hardware slots#114
LinuxJedi merged 1 commit into
mainfrom
fix/sprite-two-slot-fetch

Conversation

@LinuxJedi

Copy link
Copy Markdown
Owner

Summary

Sprite DMA lines are now evaluated at both of their hardware bus slots
instead of once per pair: sprite N's first slot ($15+4N) runs the line
entry logic (vstop comparator, descriptor chain, arming) and samples the
DATA word(s) at that slot's beam time; the second slot ($17+4N) samples
DATB at its own beam time and assembles/emits the display line. SPREN is
still sampled per slot (from #110), so a mid-line DMACON edge between the
two slots fetches exactly one word of the pair, and chip RAM rewritten
between the slots is seen by DATB but not DATA -- matching the real bus
timing.

  • SpriteSlotPhase (Pair/Slot1/Slot2) threads through the former
    captured_sprite_line_with_slots: Slot1 stashes pending DATA words +
    line markers on DisplaySpriteDmaState, Slot2 completes the line from
    pending state. The single-shot Pair path remains for the pre-display
    replay wrapper and as the second-slot fallback when the first slot did
    not run (SPREN low there, or the stream re-seeded between the slots).
  • A skipped slot leaves SPRxPT one fetch behind the line-derived stream
    position (data_word_skew), so later fetches and the next descriptor
    fetch read from the hardware pointer's actual position; the display
    line assembles from the stale latch on the skipped side, and a missed
    DATA slot never arms the sprite.
  • The per-line markers default to "unset" (manual Default -- a derived
    zero default would false-match line 0), and stream re-seeds (descriptor
    reload, SPRxPT retarget) clear the pending state.
  • STATE_VERSION 17 (DisplaySpriteDmaState gained fields).

Scores

This is timing-correctness groundwork: the vAmigaTS
Agnus/Registers/DMACON sprena*/sprdis* family (29-43%) does not
move. Investigating that family against the real-A500 photos (which match
vAmiga exactly) showed its root cause is Copperline's descriptor-precompute
sprite model itself: hardware fetches POS/CTL on the vstop line through
these same two slots and runs the vertical comparators off Agnus register
copies, with the per-sprite DMA flip-flop cleared on the vstop line even
when SPREN is off. That register-level state machine is a follow-up
rework; this PR puts the per-slot evaluation points in place for it.

Testing

  • cargo test clean (~750 unit tests), cargo clippy / cargo fmt clean.
  • Per-slot beam-time sampling pinned by
    sprite_dma_capture_samples_line_words_at_beam_time (RAM rewritten
    between the two slots: DATA sees the pre-rewrite word, DATB the
    post-rewrite word).
  • Byte-identity gate vs current main (raw screenshots): kick13boot 15s,
    Gen-X 110s + 620s, Inside the Machine 25s, Hamazing 25s, A1200 Kickstart
    25s, Zool 25s, Second Nature 40s -- all byte-identical.

Sprite N's line was captured in one shot at its second DMA slot; now the
first slot ($15+4N) runs the line entry logic (vstop comparator,
descriptor chain, arming) and samples the DATA word(s) at that slot's
beam time, and the second slot ($17+4N) samples DATB at its own beam
time and assembles the display line. Chip RAM rewritten between the two
slots is therefore seen by DATB but not DATA, and a mid-line DMACON
SPREN edge fetches exactly one word of the pair, matching the real bus
timing. A skipped slot leaves SPRxPT one fetch behind the line-derived
stream position; the display line reuses the stale latch on that side
and a missed DATA slot never arms the sprite.

The single-shot path remains for the pre-display replay wrapper and as
the second-slot fallback when the first slot did not run. Stream
re-seeds (descriptor reload, SPRxPT retarget) clear the pending state,
and the per-line markers default to unset so a fresh state cannot
false-match line 0. STATE_VERSION 17 (DisplaySpriteDmaState gained
fields).

Byte-identical on the demo regression set (Gen-X 110s/620s, ITM,
Hamazing, Zool, Second Nature, Kickstart 1.3 and A1200 boots) vs main.
@LinuxJedi LinuxJedi merged commit c6ad4d0 into main Jul 4, 2026
7 checks passed
@LinuxJedi LinuxJedi deleted the fix/sprite-two-slot-fetch branch July 4, 2026 18:46
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