Hardware-in-the-loop development platform for the Commodore 64.
ultimate-tool docs PORTABILITY.md
7.1 kB
Markdown
at main

Project portability #

Ultimate Tool has two explicit onboarding tiers. Both use the same build, target, run, evidence, CLI, service, dashboard, and MCP operations.

Tier 1: screen observation #

Manifest schema 5 can run an existing PRG without source instrumentation. Schema 6 additionally identifies one supporting artifact for hardware REU deployment. Schema 7 can attach optional map/ELF analysis, and schema 8 can enforce or observe build budgets, without changing the observation tier:

schema_version = 8

[project]
name = "existing-game"

[build]
command = ["make", "build"]
working_directory = "."
artifact = "build/game.prg"
supporting_artifacts = ["build/game.reu"]
symbol_sources = [
  { id = "resident-map", path = "build/game.map", format = "llvm_lld_map", context = "resident" },
  { id = "resident-elf", path = "build/game.elf", format = "elf_mos", context = "resident" },
]
source_remaps = [{ from = "/container/project", to = "." }]
toolchain = "pinned-toolchain-identity"

[[build.budgets]]
id = "resident-stack-room"
measure = "symbol_gap"
context = "resident"
start_symbol = "__heap_start"
end_symbol = "__stack"
minimum_bytes = 768
severity = "warning"

[[build.budgets]]
id = "resident-text"
measure = "section_size"
context = "resident"
section = ".text"
maximum_bytes = 32768
severity = "error"

[diagnostics]
address = 49152
length = 256
screen_address = 1024
color_address = 55296

[vice]
executable = "x64sc"
working_directory = "."
arguments = ["-reu", "-reusize", "1024", "-reuimage", "build/game.reu"]
poll_interval_ms = 100

[ultimate]
poll_interval_ms = 250
request_timeout_ms = 8000
reu_image = "build/game.reu"

[[tests]]
name = "boot-screen"
timeout_ms = 60000
observation = "screen"
expected_screen = "READY"

Build working directories and artifact paths are project-relative. The primary artifact must be a PRG. Supporting artifacts are copied byte-for-byte into every run bundle with size and SHA-256 metadata. VICE runs from its declared project-relative working directory so media arguments can use stable paths. Declared symbol sources are likewise project-relative build outputs. They are snapshotted and parsed before target mutation; they do not instrument or alter the PRG. Declared budgets evaluate only that normalized snapshot. Warning misses are retained as evidence; error misses stop before target mutation.

ultimate.reu_image must exactly match one build.supporting_artifacts entry. For an Ultimate run, the freshly built bytes are snapshotted before deployment, written at REU offset zero through the password-authenticated Ultimate DMA Service, and bounded by the freshly probed REU capacity and the protocol's 16 MiB address space. Each chunk is sent once; an ambiguous write is not retried. A final identity command on the same connection is the completion barrier before the PRG reset/load/run begins. REU writes and C64 resets require separate explicit authorization.

Ultimate Tool polls only screen/color memory in VICE and captures the display PNG once after the marker is stable. A passing record contains:

  • final_state.terminal = "screen_match"
  • The final screen, color RAM, decoded text, and VICE PNG
  • An unsupported heartbeat summary
  • Empty event and mailbox-observation collections
  • The PRG and every declared supporting artifact

This tier proves bounded build, launch, and visible behavior. It does not provide readiness events, assertions, startup commands, crash/hang classification, or cooperative liveness. Accordingly, screen tests reject expected_terminal, startup_command, and heartbeat_timeout_ms.

The [diagnostics] mailbox address and length remain required by schema 5 for backward-compatible manifest shape, but screen observation does not read them.

Tier 2: instrumented mailbox #

Mailbox observation is the existing full diagnostic mode and remains the default when observation is omitted. It requires expected_terminal and can use the Rust-MOS SDK for:

  • Ordered ready, log, assertion, pass, fail, and crash events
  • One acknowledged startup command
  • Opt-in heartbeat hang detection
  • Cooperative panic/crash classification
  • Bounded crash-state evidence

Projects should adopt this tier only where its memory and toolchain cost has been measured. A screen test is not silently promoted to mailbox support.

Verified projects #

The first VICE 3.8 portability proof used unchanged application binaries:

  • roguelike-c64: Rust-MOS, 51,092-byte PRG, marker R O G U E L I K E
  • Polyself from nethack-6510: llvm-mos C with overlays, 40,943-byte PRG plus a 1,048,576-byte REU image, marker DLVL:1

Both immutable records checksum successfully and contain no diagnostic events or mailbox observations. The same Polyself PRG and REU hashes subsequently passed on identity-pinned C64 Ultimate 25A60A: the host wrote the 1 MiB image in 17 chunks, received the firmware identity completion barrier, invoked one run_prg reset, and captured DLVL:1 from physical screen memory. The device's REU and Ultimate DMA Service settings were enabled only for the authorized run and verified restored to Disabled afterward.

The same Roguelike analysis artifact (5b4501c0...72567294) subsequently passed on identity-pinned C64 Ultimate 25A60A with one authorized run_prg reset. Immutable run 7ee1c352-5e13-463d-9a6e-77af024b42ce captured R O G U E L I K E, the visible title menu, checksummed map/ELF analysis, exact and containing-range symbol resolution, a resumed CPU, zero retries or recoveries, and a healthy post-run identity probe. This is automated screen-memory evidence, not manual HDMI, audio, keyboard, or raster-quality acceptance.

Polyself's authoritative build prints 283 bytes of stack room against its configured 768-byte floor while still exiting successfully. Manifest schema 8 now models that result as an explicit warning budget, alongside an enforced 7,856-byte limit for the selected OVL_POLYSELF section.

A later analysis spike retained the already accepted Polyself PRG hash d9cf7f2a...37c6604, selected-overlay binary hash 903ad657...546b34, and REU hash 53da5578...5286c while adding -gline-tables-only to both compiler passes. Its snapshotted resident lld map/ELF and OVL_POLYSELF ELF resolve resident and selected-overlay functions, including project-relative C lines, and correctly treat $B000 as ambiguous without an overlay context. That final analysis build passed DLVL:1 in VICE 3.8. The older immutable physical run remains unavailable to the resolver and was not modified; matching deployable hashes made another hardware reset unnecessary.

Schema-8 VICE run 6b01ee08-9902-45aa-bea3-3e43035047c0 preserved those same hashes and reached DLVL:1. Its normalized evidence records OVL_POLYSELF at 3,944 bytes with 3,912 bytes of headroom, and resident stack room at 283 bytes with -485 bytes relative to the warning floor. A comparison against the preceding identical build reported no artifact, section, object, or symbol changes. No physical hardware mutation was needed.