agnus: model sprite DMA at the register level#116
Merged
Conversation
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.
Replace the descriptor-precompute sprite model with the register-level state machine the chip implements (vAmiga executeFirst/SecondSpriteCycle and updateSpriteDMA semantics, ground-truthed against the real-A500 sprenacpu2 photos, which match vAmiga's render exactly): - Each channel keeps Agnus-side SPRxPOS/SPRxCTL register copies and the vertical comparator values derived from them, updated identically by DMA control-word fetches and CPU/Copper pokes (POS supplies vstart's low bits, CTL the high bit plus the whole vstop, and disarms the display latches). Line-start comparators set/clear the per-channel DMA flip-flop; vstop clears it even when SPREN is off, which leaves a sprite dead until the next field when software disables DMA across its vstop line - the vAmigaTS sprena/sprdis mechanism. - The vstop line's two slots fetch the next POS/CTL control words, and the vertical-blank reset (PAL $19 / NTSC $14) forces every channel's vstop to that line, which is how each field's first control-word fetch happens. Terminators, inverted vstop pairs, deferred starts and equal start/stop descriptors all fall out of the comparators naturally. - SPRxPT advances only on words actually fetched: the word-skew model is gone and the frame-start frontier is simply the live pointer. An armed channel with DMA off keeps redisplaying its latches until a CTL fetch/poke disarms it, which renders the sprena/sprdis vertical-bar staircase the old model structurally could not produce. - Deleted with the descriptor model: register-stream seeding, SPRxPT retarget math, the same-slot descriptor-restart discard, and the save-state reconstruction hack - the register state is chip state and is now serialized and restored directly. - Sprite bus-slot arbitration uses the same rules (enabled channel or vstop-line control fetch claims the slots, vblank-gated), and VideoPipelineStats (host perf telemetry) is no longer serialized: call chunking legitimately differs across a save-state load. The sprena/sprdis vAmigaTS percentages stay ~30-45%: those sweeps step CPU DMACON writes at two-colour-clock resolution over a CPU-timed flickering background, so the residual is the known CPU-write-timing class, not sprite modelling. Structurally the renders now match the photos' bar staircase. Byte-identical on kick13boot, Gen-X, Hamazing, ITM, A1200 Kickstart, Zool and Roots II AGA; Second Nature and Roots II ECS show the known benign animation-phase drift class. STATE_VERSION 17.
Owner
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Sprite DMA is now modelled at the register level the way Agnus works,
replacing the descriptor-precompute model (vAmiga
executeFirstSpriteCycle/executeSecondSpriteCycle/updateSpriteDMA
semantics, ground-truthed against the real-A500 sprenacpu2 photos, which
match vAmiga exactly):
vertical comparator values, updated identically by DMA fetches and
CPU/Copper pokes (POS = vstart low bits; CTL = vstart high bit + whole
vstop + disarm). Line-start comparators set/clear the per-channel DMA
flip-flop -- vstop clears it even when SPREN is off, which is what
leaves a sprite dead until the next field when software disables DMA
across its vstop line (the sprena/sprdis mechanism).
vertical-blank reset (PAL $19 / NTSC $14) forces every vstop to that
line, which is how each field's first control-word fetch happens. No
descriptor chain, no precomputed stream end: terminators, inverted
vstop pairs, deferred starts and equal start/stop descriptors all fall
out of the comparators naturally.
gone; the frame-start frontier is just the live pointer), and an armed
channel with DMA off keeps redisplaying its latches until a CTL
fetch/poke disarms it -- this renders the vAmigaTS sprena/sprdis
vertical-bar staircase that the old model structurally could not
produce.
retarget math, same-slot descriptor-restart discard, the save-state
reconstruction hack (the register state is chip state and is now
serialized/restored directly), ~250 net lines removed.
vstop-line control fetch claims the slots, vblank-gated).
VideoPipelineStats(host perf telemetry) is no longer serialized:call chunking legitimately differs across a save-state load.
STATE_VERSION 17.
vAmigaTS
Structural: sprenacpu2 now renders the yellow armed-persistence bar
staircase that the A500 photo and vAmiga show (the old model painted a
drifting streak instead). The family's mismatch percentages stay
~30-45%: those sweeps step CPU DMACON writes at 2-colour-clock
resolution over a CPU-timed flickering background, so the residual is
dominated by the known CPU-write-timing class (the #102/#104 residual),
not sprite modelling. interfere1/1b improved (7.2/5.3 -> 6.1/7.2 mixed),
manual1/2 and the collision buckets are unchanged.
Testing
vertical-blank reset line (shared helper), pointer reloads land before
it, inverted vstop now pins the control-word refetch on the vstop line
(vAmiga semantics) instead of the old run-to-bottom clamp.
Gen-X 110s, Hamazing, ITM, A1200 Kickstart, Zool -- identical.
Second Nature 40s is the known benign animation-phase drift (the FSM
build reaches the byte-identical frame 0.04s earlier).
wolf/SPREN-clear scene class) byte-identical; Roots II AGA 60s
byte-identical; Roots II ECS byte-identical at 20/35/50s with a
timeline knife-edge crossing between 50s and 60s (same benign drift
class as Second Nature).