Skip to content

Return the VIC-II's first-phase byte for reads nothing answers - #341

Merged
highbyte merged 1 commit into
feature/cpu-cycle-enginefrom
feature/c64-open-io-reads-vic2-bus
Sep 18, 2026
Merged

highbyte merged 1 commit into
feature/cpu-cycle-enginefrom
feature/c64-open-io-reads-vic2-bus

Conversation

@highbyte

Copy link
Copy Markdown
Owner

What

In the first phase of every cycle the VIC-II reads memory, and that byte stays on the data bus into the second phase unless something else drives it. Two kinds of CPU read now see it:

  • The I/O 1 and I/O 2 areas ($DE00-$DFFF) with no cartridge answering the address. They returned whatever had last been written there (I/O storage), which a real C64 does not have.
  • Colour RAM, whose chip drives only the data bus's low four bits: the high four now come from that byte instead of being 0.

Which byte depends on the cycle of the read:

Cycles (PAL, 1-based) First-phase access Byte
58, 60, 62, 1, 3, 5, 7, 9 pointer access of sprite 0-7 the pointer
the cycle after each sprite data slot middle byte of the row if the sprite's DMA is on, else $3FFF
11-15 refresh $3F00 + refresh counter (reset to $FF in line 0, counted down per access)
16-55 graphics idle state $3FFF ($39FF with ECM); display state the character or bitmap data
the rest idle $3FFF

On the 6567R8 (NTSC, 65 cycles) the sprite accesses start a cycle later (sprite 0 in cycle 59).

How

Vic2.FirstPhaseBusByte() brings the VIC-II to the cycle of the access in progress and derives the byte from the cycle, the sprite DMA state and the display state. The cartridge slot uses it as its fallback reader for $DE00-$DFFF (writes still go to I/O storage), and ColorRAMLoad takes its high four bits from it.

Five cartridge and SwiftLink unit tests expected an unanswered I/O read (a write-only register, a detached SwiftLink) to give back the stored value; they now expect the bus byte. As on hardware, a program probing for an REU by writing a register and reading it back no longer finds one that is not there.

Verification

  • VICE test programs (274 runs, PAL and NTSC): 254 → 256 match. Newly matching: phi1timing/phi1timing and phi1timing_ntsc, which read $DEAD on every cycle of a line and compare each byte with the expected access. colorram/test (reads colour RAM, masks to the low four bits) still passes. No other result changed.
  • New Vic2FirstPhaseBusByteTests (17 cases): pointer, slot, refresh, graphics and idle accesses by cycle, ECM for idle graphics accesses only, the refresh counter, a fetching sprite's middle byte, display-state character data, and colour RAM's high bits.
  • Games (Commando, Giana Sisters; PAL, NTSC, snapshots) and fourteen demos at three frame counts render byte-identically before and after.
  • Performance (MacBook Air M1): For Your Sprites Only unchanged (sequencer with per-line sprites 1357/1281 → 1349/1280 µs/frame). A worst-case loop doing nothing but colour RAM reads (~3,400 per frame) is 228 → 271 µs/frame without a renderer and 637 → 682 with the sequencer: about 13 ns per colour RAM read, half of it bringing the VIC-II to the read's cycle as register reads already do. A scroller copying all of colour RAM once per frame pays about 13 µs.

In the first phase of every cycle the VIC-II reads memory, and that byte stays
on the data bus into the second phase unless something else drives it. A CPU
read of the I/O 1 and I/O 2 areas ($DE00-$DFFF) with no cartridge answering
now returns it instead of whatever was last stored there, and colour RAM reads
take their high four bits from it, since the colour RAM drives only the low
four.

Which byte depends on the cycle: each sprite's pointer access, then the middle
byte of its row if its DMA is on or an idle access if not; refresh accesses in
cycles 11-15; graphics accesses in cycles 16-55 ($3FFF, or $39FF with ECM, in
idle state); idle accesses ($3FFF) elsewhere. VICE's phi1timing test programs
read $DEAD on every cycle of a line and now pass on PAL and NTSC.

Cartridge tests that expected an unanswered I/O read to give back the stored
value now expect the bus byte.
@sonarqubecloud

Copy link
Copy Markdown

@highbyte
highbyte merged commit 2414f6b into feature/cpu-cycle-engine Sep 18, 2026
9 checks passed
@highbyte
highbyte deleted the feature/c64-open-io-reads-vic2-bus branch September 18, 2026 11:59
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