Skip to content

Fix Ultimax cartridge rendering, with an e2e guard - #882

Merged
GideonZ merged 2 commits into
masterfrom
fix/ultimate-cartridge
Sep 10, 2026
Merged

Fix Ultimax cartridge rendering, with an e2e guard#882
GideonZ merged 2 commits into
masterfrom
fix/ultimate-cartridge

Conversation

@GideonZ

@GideonZ GideonZ commented Sep 10, 2026

Copy link
Copy Markdown
Owner

An 8K cartridge at $E000 with EXROM high and GAME low runs the machine in
Ultimax mode, where the VIC fetches characters and colour through the cartridge
rather than from the C64's own memory. Core 1.50 draws that correctly.

tests/e2e/io/c64/ultimax_cartridge_test.py is the regression guard. It starts
Jupiter Lander through runners:run_crt, taps F1, and compares the whole
384x272 VIC frame against a reference image, index for index, with no tolerance.

Measured on an Ultimate 64-II, one branch, two cores

Core Result
1.4F FAIL, 75887/104448 pixels matched (72.66%)
1.50, external/u64e2_100t.bit from this branch OK, exact match, four runs of four

Under 1.4F the shapes land in the right places and no character data reaches the
VIC at all: no text, no lander, no fuel bar, and the terrain colours inverted.
The suite reports the pixel count, the colour histogram of the closest frame,
and writes that frame beside the run's other files as <run>.frame.png.

The red core was loaded on the bench for the demonstration and the green core is
the bitstream in this branch, loaded over JTAG into SRAM, so both measurements
are of the same test against the two cores rather than against whatever happened
to be flashed.

Why an exact comparison rather than a tolerance

The game waits for the player before anything moves, so there is no frame timing
to absorb: over more than twenty starts the frame was identical to the reference
every time, arriving 2.1s to 2.9s after the cartridge started.

jupiter_lander.png is palette-indexed and its indices are what the video stream
carries, so the comparison converts no colour and assumes no palette. F1 repeats
until the frame arrives, because a tap that lands on an already-running game
leaves the picture unchanged, so retrying a lost keystroke costs nothing.

The suite skips on a machine streaming NTSC, since the reference is a PAL frame.

What is in the diff

No firmware source changes. The fix is the three bitstreams and the rest is the
test:

  • external/u64.sof, external/u64e2_100t.bit, external/u64e2_50t.bit.
  • 200 lines of new suite, with its .crt and reference frame beside it.
  • tests/e2e/lib/vic_video.py: VicStreamCapture takes a target, so it joins
    that target's own video group and ignores datagrams from any other sender. Two
    targets on one bench stream to the same group unless U64_VIDEO_* separates
    them, and an exact-match check cannot assemble a frame out of both machines.
  • run-tests: registers ultimax-cartridge in the standard profile. It runs in
    2.5s.
  • tests/README.md: the profile matrix, regenerated by
    tools/docs/update_test_docs.py. That also picks up three rows the checked-in
    matrix was already missing (iec-dos-commands, rel-copy, ident-leak).

🤖 Generated with Claude Code

https://claude.ai/code/session_01Dk5P8LzytLNNWSrtpqte2V

@chrisgleissner

Copy link
Copy Markdown
Collaborator

@GideonZ Looks amazing. I love the test and the golden image.

@GideonZ
GideonZ merged commit fd75647 into master Sep 10, 2026
2 checks passed
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.

2 participants