A complete Infocom Z-machine version 5 interpreter written in 6502 assembly (NMOS-only opcodes), targeting the Apple //e with 128K, conforming to the Z-Machine Standards Document 1.1. It boots from a ProDOS disk and plays real v5 games — including Beyond Zork, reassembled from the original two-sided Apple II release.
![]() |
![]() |
| 9:05 by Adam Cadre on the //e | Beyond Zork — “[UNDO completed.]” |
- czech.z5: 406/406 conformance tests passed — both under the PC-side harness and on the emulated //e itself.
- praxix.z5: all tests passed (multi-level undo excepted, an optional capability the suite itself notes is not required).
- Playable games: 9:05, Adventure (two-disk build), and Beyond Zork
(from an 800K hard-disk volume), all played interactively under MAME's
apple2e/apple2eedrivers and AppleWin.
- Full v5 opcode set: objects/properties, text with abbreviations and custom
alphabets, dictionary parsing (binary search on sorted dictionaries),
output stream 3 with 16-deep nesting,
catch/throw(frame-index cookies),scan/copy/print_table, terminating-characters tables, and the EXT set. - 80-column two-window screen driver writing the text pages directly:
split windows, inverse video, word-wrap buffering,
[MORE]paging, and a line editor with delete/arrow handling. - Demand paging: dynamic memory stays resident in main RAM; static/high memory is served from a 512-byte-page LRU cache in auxiliary RAM, faulted in from the story file through ProDOS MLI. 256K stories work on floppies or hard-disk volumes.
- UNDO: single-slot state snapshot kept in aux RAM (carved from the page cache), with the XZIP return conventions Beyond Zork actually probes for.
- Quetzal 1.4 saves (
IFhd+UMem+Stks), interoperable with Frotz in both directions — the reader also decodesCMemin place. - Font 3 character graphics rendered with MouseText on the enhanced //e / IIc (interpreter number 9, so Beyond Zork engages its on-screen map and bar-chart UI).
- The interpreter reports itself as Standard 1.0, interpreter 9 'A'.
src/ 6502 source (ca65). main.s includes everything; plat_harness.s
and plat_apple.s are the two platform back-ends.
cfg/ ld65 linker configs (harness @ $0800; Apple SYS + LC bank 2).
harness/ PC-side test harness: a C 6502 emulator (Klaus-validated) with
trap-based I/O — the fast development loop.
games/ Freely-available test suites and story files.
tools/ Build scripts, disk builders, story extractor, header dumper.
docs/ DESIGN.md, implementation-focused spec notes, screenshots.
ref/ Z-Machine Standard 1.1 (HTML) and InterL3 (Infocom Apple disk
format reference).
main $0800-$3Fxx interpreter + buffers + Z-stack aux $0200-$07FF (80-col text)
main $41xx-$BEFF dynamic memory (up to ~32.5K) aux $0800-$BFFF story page cache
LC bank 2 $D000 screen driver + object/table ops + undo snapshot (top)
LC bank 1 ProDOS 8 (entered only via mli_go)
Bank 2 of the language card — the 4K ProDOS leaves free — is the machine's resident state; every ProDOS call funnels through a single bank-switching choke point. That reclaimed enough main RAM for Beyond Zork's 32,085 bytes of dynamic memory.
Prereqs: cc65 (ca65/ld65), MSVC (for the
harness), Python 3, AppleCommander
(ac CLI in tools/), and a ProDOS 8 image to donate boot blocks + the
PRODOS file (see tools/mkdisk.sh).
sh tools/build_core.sh # harness build -> build/core.bin
harness/build.cmd # C harness -> build/harness.exe
build/harness.exe build/core.bin games/czech.z5 # run the suite
sh tools/build_apple.sh # Apple build -> build/interp.sys
sh tools/mkdisk.sh games/905.z5 build/zm905.po # 140K, one disk
sh tools/mkdisk2.sh games/Advent.z5 boot.po data.po # story on drive 2
sh tools/mkdisk800.sh games/beyondzork.z5 build/zmbz.po # 800K + .hdv- AppleWin:
AppleWin.exe -d1 build\zm905.po, or attachbuild\zmbz.hdvas the hard disk and boot from it. - MAME:
mame apple2e -flop1 zm905.po, or for hard-disk volumesmame apple2ee -sl6 cffa202 -hard1 zmbz.hdv(the unenhanced //e ROM only boots slot 6, andcffa202is the 6502-firmware CFFA — the 65C02 variant won't boot an unenhanced machine). MouseText (Beyond Zork's map borders and bar charts) needs the enhancedapple2ee.
The interpreter opens STORY on the boot volume, falling back to
/ZM2/STORY (a data disk in drive 2). Saves go to a SAVE file on the
boot volume in Quetzal format.
- Spec: Z-Machine Standards Document 1.1 (Graham Nelson et al.),
mirrored under
ref/spec/. ref/interl3.c— InterL 3.0 by S. V. Nickolas, the definitive reference for Infocom's Apple II disk formats (and the source of the side-B long-track decoding used bytools/extract_bz.py).- Test suites: CZECH (Amir Karger / Evin Robertson) and Praxix (Andrew Plotkin / Dannii Willis), from the IF Archive.
- Story files: 9:05 © Adam Cadre (freeware); Adventure (Crowther & Woods, Inform port); Beyond Zork © 1987 Infocom — included for historical preservation, as widely mirrored online.
- Written almost entirely by Claude (Anthropic's Claude Code), pair-flown by @hasseily, in one long session: spec digestion → C harness → core → platform layer → emulator verification, with an adversarial multi-agent review pass that caught 18 latent bugs the conformance suites couldn't see.

