TT-Zork & More — Documentation

Zork I on Tenstorrent

Running a 1977 stack-based virtual machine on 2026 AI accelerator hardware — three hardware stages, an LLM remix layer, and a full terminal UI.

Demos

All demos use the --stage sim Python interpreter. The LLM remix layer and AI auto-play connect to Llama-3.3-70B running on Tensix cores via tt-inference-server.

Hybrid demo — human plays, LLM rewrites every response

Hybrid — human plays, Llama-3.3-70B rewrites every Z-machine response

Stage 2 — game binary on Blackhole DRAM

Stage 2 — game binary on Blackhole DRAM

AI auto-play — LLM plays Zork, full TUI

AI auto-play — experimental persona, 30 turns, full TUI (first 60s)

Colossal Cave Adventure — Z-machine V5

Colossal Cave Adventure — Z5, the original text adventure (1976)

The Hitchhiker's Guide to the Galaxy — Blackhole DRAM

Hitchhiker's Guide to the Galaxy — V3 Release 60, Blackhole DRAM (1984)

Planetfall — Blackhole DRAM

Planetfall — V3 Release 39, Blackhole DRAM (1983)

Leather Goddesses of Phobos — Blackhole DRAM

Leather Goddesses of Phobos — V3 Release 59, Blackhole DRAM (1986)

→ Full interactive demo page with embedded asciinema players for all eleven recordings including Zork II, Colossal Cave Adventure, and three more classic Infocom titles on Blackhole DRAM.

Background

Zork was written in 1977–1979 by Marc Blank, Dave Lebling, Bruce Daniels, and Tim Anderson at MIT, originally in MDL on a PDP-10. Infocom commercialised it in 1980. To ship the game across the fragmented microcomputer market of the era, Infocom designed the Z-machine: a simple stack-based virtual machine whose bytecode could be compiled once and interpreted on any platform they supported — CP/M, Apple II, TRS-80, Commodore 64, and dozens more. The interpreter was small enough to write in a few kilobytes of assembly for each target. The Z-machine specification, released publicly after Infocom was acquired by Activision, later inspired Graham Nelson's Inform language and remains the format for a large archive of interactive fiction.

Tenstorrent builds AI accelerators whose chips contain two distinct kinds of processing elements. The Tensix cores handle tensor operations — matrix multiplications, the inner loop of transformer inference. Each Tensix block is managed by a cluster of small embedded RISC-V cores that handle data movement, instruction dispatch, and coordination. These management cores are fully programmable; TT-Metal and TT-Lang expose them as general-purpose compute targets through the ttnn API.

This project runs the Z-machine on those three levels of the Tenstorrent stack:

StageWhere the game runs
1 — simPython Z-machine interpreter on the host CPU
2 — deviceSame interpreter; game binary resides on Blackhole DRAM
3 — risc-vZ-machine interpreter kernel running on Blackhole RISC-V cores
+remixLLM response layer served by tt-inference-server on Tensix

Quick Start

# Activate the TT-Lang pyenv (required for stages 2 and 3)
source ~/code/tt-lang/build/env/activate

# Interactive startup menu (game + stage + remix selection)
python play.py

# Stage 1 — pure Python, no hardware needed
python play.py --stage sim

# Stage 2 — game binary on Blackhole DRAM
python play.py --stage device

# Stage 3 — interpreter on RISC-V cores
python play.py --stage risc-v

# Any stage with the LLM remix layer
python play.py --stage sim --remix

# LLM persona auto-play (the LLM plays; you watch)
python play.py --stage sim --persona expert --turns 40

# Full terminal UI (hardware monitor, streaming tokens, ASCII art)
python play.py --stage device --remix --tui

Run with no arguments to get an interactive startup menu that lets you choose the game file, stage, and remix mode. Pass --stage and --game together to skip the menu. Use --menu to force the menu even when other flags are present.

Available game files in game/: zork1.z3, zork2.z3, zork3.z3, advent.z5. Zork I–III are Z-machine V3; Colossal Cave Adventure (advent.z5) is Graham Nelson's V5 port. Three additional Infocom titles — hhgg.z3, planetfall.z3, lgop.z3 — are not redistributed; run bash game/fetch-infocom.sh to download them from historicalsource. Use --game to point at any Z-machine story file.

How the Stages Work

Stage 1 — Pure Python (--stage sim)

engines/sim.py wraps ttlang/zmachine_v3.py, a complete Python implementation of the Z-machine V3 specification. No hardware is required. The interpreter runs the game's bytecode locally, handling all opcodes, the object tree, the dictionary, Z-string abbreviation decoding, and the READ/PRINT I/O loop.

Stage 2 — Blackhole DRAM (--stage device)

engines/device.py opens a Tenstorrent Blackhole device via ttnn, uploads the 87 KB game binary to on-chip DRAM as a ttnn.Tensor, verifies the round-trip (first 8 header bytes), and records the physical DRAM address. The Python Z-machine interpreter then runs against those DRAM-resident bytes on the host. The game data lives on silicon; the interpreter logic runs on the host CPU. This validates the data path that Stage 3 reuses.

Requires: /dev/tenstorrent present, TT-Lang pyenv active.

Stage 3 — RISC-V cores (--stage risc-v)

engines/riscv.py dispatches kernels/zork_interpreter_l1.cpp to Blackhole RISC-V cores via ttnn.generic_op. The kernel implements the Z-machine interpreter in C++: it reads game bytecode from DRAM via the on-chip NoC, executes instructions, decodes Z-strings, and writes output back to DRAM. The Python host reads the result after each batch.

Current constraints: The Blackhole chip firmware limits each kernel invocation to approximately 10 Z-machine instructions before the execution watchdog fires. A third generic_op call within a single device session hangs reliably (diagnosed in ttlang/diag_batch3.py); the workaround is opening and closing the device for each batch. State does not persist across step() calls — each command restarts the interpreter from the initial PC. These are firmware execution budget constraints, not architecture limitations.

Requires: Blackhole hardware (p300c card or equivalent), TT-Lang pyenv active, kernels/zork_interpreter_l1.cpp built.

Remix layer (--remix)

An LLM layer that intercepts each game response and rewrites it in a more expansive voice, generates ASCII art for room entries, and collects postcard-style narrative snapshots at notable moments. It does not alter game state — the Z-machine response is the source of truth; the LLM changes the prose, not the facts.

The layer connects to an OpenAI-compatible endpoint (default: http://localhost:8000/v1/chat/completions, typically a tt-inference-server instance running LLaMA on Tensix). Override with ZORK_LLM_URL. Override the model with --model or ZORK_LLM_MODEL.

TaskDefault model
Input mapping (freeform → Zork command)Llama-3.2-1B
Persona command selection (auto-play)Llama-3.2-1B
Output remix, ASCII art, postcardsLlama-3.1-8B

The remix layer degrades gracefully — if the LLM server is unreachable, raw Z-machine output is shown unchanged.

Terminal UI (--tui)

python play.py --stage device --remix --tui

A Textual-based full-terminal interface with:

Slash commands available in the TUI:

CommandEffect
/remixEnable LLM remix layer
/classicDisable LLM remix layer
/auto [persona]Start LLM auto-play with named persona
/stopStop auto-play, return to manual
/helpShow command list
/quitExit

Persona Auto-play (--persona)

python play.py --stage sim --persona expert --turns 50
python play.py --stage sim --persona naive --remix

The LLM plays the game. On each turn, the current game output is sent to a small model with a persona-specific system prompt; the model returns the next command.

The remix layer, if active, still rewrites each response. Use --turns to cap the session (default: 50). In the TUI, /auto expert triggers the same loop mid-session; /stop hands control back.

Requirements

Stage 1 (sim)

Stages 2 and 3 (device, risc-v)

Remix layer (--remix)

Hardware telemetry (TUI right pane)

Repository Layout

play.py                  # Entry point — all stages and modes
engines/
  sim.py                 # Stage 1: pure Python
  device.py              # Stage 2: Blackhole DRAM-backed
  riscv.py               # Stage 3: RISC-V kernel dispatch
ttlang/
  zmachine_v3.py         # Python Z-machine V3 interpreter (~700 lines)
  zork_device.py         # Blackhole DRAM upload / verify helper
  zork_risc.py           # RISC-V batch loop (open→run→close per batch)
kernels/
  zork_interpreter_l1.cpp  # RISC-V Z-machine interpreter kernel
  zork_interpreter_opt.cpp # Earlier kernel variant (read opcode support)
remix/
  llm.py                 # call_llm / call_llm_stream (OpenAI-compatible SSE)
  router.py              # Task → model routing
  mode.py                # RemixLayer orchestration
  personas.py            # Auto-play persona definitions
  input_mapper.py        # Freeform English → Zork command
  output_remixer.py      # Z-machine text → LLM-rewritten response
  ascii_artist.py        # Room ASCII art generation and caching
  narrative_enhancer.py  # Postcard generation at notable moments
tui/
  app.py                 # ZMachineTuiApp (Textual)
  game_pane.py           # Scrolling output + input widget
  context_pane.py        # THINKING / ART / HARDWARE panel + token colorizer
  hw_poller.py           # tt-smi -s JSON parser
  vocabulary.py          # Z-machine dictionary extractor for token colorizer
prompts/                 # LLM system prompts (editable plain text)
game/
  zork1.z3               # Zork I V3 bytecode (86 838 bytes, MIT-licensed)
  zork2.z3               # Zork II V3 bytecode (MIT-licensed)
  zork3.z3               # Zork III V3 bytecode (MIT-licensed)
  advent.z5              # Colossal Cave Adventure Z5 (Graham Nelson port)
  LICENSES.md            # Per-file license details
tests/                   # pytest test suite (Python components)
src/                     # Earlier C/Frotz implementation (historical)

The src/ directory contains an earlier C implementation based on the Frotz interpreter with TT-Metal kernel experiments. It is not connected to play.py and is preserved for reference.

Tests

source ~/code/tt-lang/build/env/activate
pytest tests/ -q

The test suite covers the Python Z-machine interpreter, the LLM layer (mocked), the TUI token colorizer, and the hardware poller.

Credits

Zork I — Marc Blank, Dave Lebling, Bruce Daniels, Tim Anderson (Infocom, 1980).

Z-machine specification — Graham Nelson and contributors. The canonical reference is The Z-Machine Standards Document.

Frotz — David Griffith and contributors. The C implementation in src/ is built on Frotz 2.56pre (GPL-2.0). play.py and ttlang/ do not use Frotz.

TT-Metal / TT-Lang — Tenstorrent Inc. (Apache-2.0). The RISC-V kernel and device layer use the ttnn API.

Zork I, II, and III were open-sourced under the MIT License in November 2025 by Microsoft, Team Xbox, and Activision. See game/LICENSES.md for full details.