Skip to content

Read the sprite enable bit at the display decision, time the sprite events per model, take the VIC bank from CIA 2's port pins - #332

Merged
highbyte merged 1 commit into
feature/cpu-cycle-enginefrom
feature/c64-vic2-sprite-enable-timing
Sep 16, 2026
Merged

highbyte merged 1 commit into
feature/cpu-cycle-enginefrom
feature/c64-vic2-sprite-enable-timing

Conversation

@highbyte

@highbyte highbyte commented Sep 16, 2026

Copy link
Copy Markdown
Owner

Summary

  • The display decision needs the enable bit. The chip's cycle 58 check asks for the sprite's enable bit as it stands in that cycle, which the VIC-II article's rule 4 omits. A sprite switched on for the two DMA compares and off again before cycle 58 is fetched but not shown (VICE's spriteenable 1, 2 and 4 test programs, which write the enable register with a read-modify-write whose two writes land on the two compare cycles).
  • The sprite event cycles per model. On the 6567R8's 65-cycle line the compares are in cycles 56 and 57 and the decision in 59, one later than PAL. The offsets were PAL constants; they now follow sprite 0's pointer cycle per model, as the bus stall model already did.
  • A late DMA start leaves sprite 0's first byte to the CPU. Started by the second compare, its fetch is two cycles on, one short of what BA needs, so that byte reads $FF.
  • The display is cleared at the cycle-58 decision when the DMA is off, not in cycle 16 when the DMA ends, so a sprite whose Y is rewritten to its last line restarts there and shows its first row again (VICE's spriterestart premise).
  • A sprite 3-7 shown on the line its DMA starts carries what its fetch slot read while the DMA was off: $FF, the idle byte, $FF (VICE's sb_sprite_fetch readme).
  • The VIC bank follows CIA 2 port A's pins. A bit the direction register makes an input floats high through its pull-up, so programs that select the bank through $DD02 got bank 3 from us instead of bank 0. The snapshot restore derives the bank the same way.
  • SpriteEnable sample in the Avalonia and browser menus: three timed cases on the SpriteX sample's line clock, showing the $FF byte on a sprite enabled between the compares, an enabled-then-cleared sprite that never shows, and the restart on the last line, on PAL and NTSC.
  • Docs updated; seven new tests cover the rules, two DMA tests moved their display assertion from cycle 16 to 58, and the snapshot round-trip test sets the direction register as the KERNAL does.

Verification

  • VICE harness, 274 tests on both models: banking and spriteenable 1 and 2 on PAL and NTSC go from DIFF to MATCH, spriteenable 4 and the three spritebug tests improve, nothing gets worse. 194 tests match.

  • Games A/B against the integration branch: identical for Commando (two snapshots, D64 PAL and NTSC) and Giana Sisters (D64 PAL and NTSC).

  • Demo A/B: eleven demos identical; Chars Sucks, which selects its bank through $DD02, now shows its sprite logo and scroller (its ghost-byte shading remains a follow-up).

  • The sample's write cycles were verified with a register trace on both models (line 212 index 54/55, line 208 index 55-56/56-57, line 233 index 55-56/56-57) and the run dumps (sprite 0's first byte $FF, sprite 1 clean, sprite 2 never displayed, sprite 1 restarted with row 0).

  • Whole solution builds; full test suite passes (the two wall-clock timing tests pass when rerun alone).

  • Timing (For Your Sprites Only, 600 frames, three repeats, two alternating rounds, MacBook Air M1): no measurable change against the integration branch in any renderer configuration. Sequencer with per-line sprites 1297-1322 vs 1310-1332 us/frame, the other four configurations likewise within the round-to-round noise.

…vents per model, take the VIC bank from CIA 2's port pins, add the SpriteEnable sample

The display decision in cycle 58 asks for the sprite's enable bit as it
stands in that cycle, not only for DMA and Y (the VIC-II article's rule 4
omits it): a sprite switched on for the two compares and off again before
cycle 58 is fetched but not shown. The compares and the decision are one
cycle later on the 6567R8's 65-cycle line (56, 57 and 59), so the sprite
event cycles now follow sprite 0's pointer cycle per model. A DMA the second
compare starts leaves sprite 0's first data byte to the CPU (its fetch is
two cycles on, one short of what BA needs), so that byte reads $FF. The
display is cleared when the cycle-58 decision finds the DMA off, not in
cycle 16 when the DMA ends, so a sprite whose Y is rewritten to its last
line restarts there. A sprite 3-7 shown on the line its DMA starts carries
what its fetch slot read while the DMA was off: $FF, the idle byte, $FF.

The VIC bank follows the levels on CIA 2 port A's pins: a bit the direction
register makes an input floats high through its pull-up, so a program that
selects the bank through $DD02 gets the bank the pins carry, not the bytes
written. The snapshot restore derives the bank the same way.

The SpriteEnable sample shows the enable timing, the $FF byte and the
restart on both models.
@sonarqubecloud

Copy link
Copy Markdown

@highbyte
highbyte merged commit 3c145a3 into feature/cpu-cycle-engine Sep 16, 2026
9 checks passed
@highbyte
highbyte deleted the feature/c64-vic2-sprite-enable-timing branch September 16, 2026 13:27
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