Hubbry Logo
Z-machineZ-machineMain
Open search
Z-machine
Community hub
Z-machine
logo
7 pages, 0 posts
0 subscribers
Be the first to start a discussion here.
Be the first to start a discussion here.
Z-machine
Z-machine
from Wikipedia
Z-machine
DesignerInfocom
Bits16
Introduced1979
Version1.1 (2014)
DesignCISC
EndiannessBig
OpenYes

The Z-machine is a virtual machine that was developed by Joel Berez and Marc Blank in 1979 and used by Infocom for its text adventure games. Infocom compiled game code to files containing Z-machine instructions (called story files or Z-code files) and could therefore port its text adventures to a new platform simply by writing a Z-machine implementation for that platform. With the large number of incompatible home computer systems in use at the time, this was an important advantage over using native code or developing a compiler for each system.

History and design

[edit]

Nomenclature and conventions

[edit]

The "Z" of Z-machine stands for Zork, Infocom's first adventure game. Infocom used file extensions of .dat (Data) and .zip (ZIP = Z-machine Interpreter Program), but the latter clashed with the widespread use of .zip for PKZIP-compatible archive files starting in the 1990s, after Activision had closed Infocom.

Infocom produced six versions of the Z-machine. Files using versions 1 and 2 are very rare. Only two version 1 files are known to have been released by Infocom and only two of version 2. Version 3 covers the majority of Infocom's released games. Later versions had more capabilities, culminating in some graphic support in version 6.

The modern convention for Z-code files usually have names ending in .z1, .z2, .z3, .z4, .z5, .z6, .z7, or .z8, where the number is the version number of the Z-machine on which the file is intended to be run, as given by the first byte of the story file.[1] As previously noted, the Infocom games used the equivalent of .z1 through .z6; .z7 and .z8 were proposed and adopted after Infocom had shut down.

Before Z-machine

[edit]

The MDL programming language was derived from Lisp at the Massachusetts Institute of Technology by the Dynamic Modeling group of the Laboratory for Computer Science (LCS) in the 1970s; inspired by Colossal Cave Adventure (1977), members of that group went on to write Zork in MDL, completing the initial version two weeks later.[2][3]: 5–6  Like Adventure, Zork was programmed for the DEC PDP-10; the finished version occupies 1 MB of MDL code and requires 512 KB of RAM to run. Because contemporary home computers did not have these resources, considerable effort was needed to port the game.[3]: 11  Eventually, the developers split Zork into two games for personal computers.[4]

The compression required to run Zork from floppy disks with approximately 80 KB of storage seemed like an insurmountable barrier to Blank. Berez realized that UCSD Pascal used a virtual machine (VM) model to generate executable files that could be readily ported across platforms, and together with Blank, they devised requirements for a lightweight VM optimized for text adventure games, which would retrieve data and execute instructions as needed from storage to compensate for the relatively small RAM sizes in typical microcomputers.[3]: 11  The resulting Z-machine used an object tree structure for in-game items, locations, characters, and weapons.[3]: 11  For comparison, the Z-machine parser occupies 3 kB of storage, while the original PDP-10 parser occupies 10 Kwords (36-bit).[5]

ZIL and ZIP, ZILCH and ZAP

[edit]

To complement the Z-machine, Infocom developed the high-level computer language Zork Implementation Language (ZIL) by streamlining MDL,[5] and the Z-language Interpreter Program (ZIP), which compiles ZIL into Z-machine instructions in a two-stage process; this made text adventure development platform-independent and enabled porting to different systems simply by writing an appropriate Z-machine interpreter.[3]: 12–13  ZIP consists of a compiler (ZILCH, short for ZIL Compiler Hack) and an assembler (ZAP, the Z-machine Assembler Program).[6]

ZILCH has never been released, although documentation of ZIL still exists, and an open-source replacement "ZILF"[7] has been written. After Mediagenic moved Infocom to California in 1989, Computer Gaming World stated that "ZIL ... is functionally dead", and reported rumors of a "completely new parser that may never be used".[8]

Graham Nelson and Inform

[edit]

In May 1993, Graham Nelson released the first version of his Inform compiler, which also generates Z-machine story files as its output, even though the Inform source language is quite different from ZIL.

Inform has become popular in the interactive fiction community. A large proportion of interactive fiction is in the form of Z-machine story files. Demand for the ability to create larger game files led Nelson to specify versions 7 and 8 of the Z-machine, though version 7 is rarely used. Because of the way addresses are handled, a version 3 story file can be up to 128K in length, a version 5 story can be up to 256K in length, and a version 8 story can be up to 512k in length. Though these sizes may seem small by today's computing standards, for text-only adventures, these are large enough for elaborate games.

During the 1990s, Graham Nelson drew up a Z-Machine Standard based on detailed studies of the existing Infocom files. The standard also includes extensions used by his newer versions, as well as links to the "Blorb" resource format and the "Quetzal" savefile format.[9] In 2006, Nelson expanded Z-machine to the 32-bit Glulx format for Inform 7. The Interactive Fiction Technology Foundation, founded 2016, manages all these standards.[10]

ZIL (Zork Implementation Language)

[edit]

The ZIL is based on MDL from MIT. Here is the definition of Zork I's brass lantern in ZIL, with added comments to illustrate the meaning of each line:[11]

<OBJECT LANTERN                 #_Defines the LANTERN object
  (LOC LIVING-ROOM)             #_Defines the initial object location
  (SYNONYM LAMP LANTERN LIGHT)  #_Defines synonyms that can be used instead of LANTERN
  (ADJECTIVE BRASS)             #_Optional adjective to distinguish this lantern from other lanterns
  (DESC "brass lantern")        #_Short description in inventory list
  (FLAGS TAKEBIT LIGHTBIT)      #_What is this object capable of? It can be TAKEN. It provides LIGHT.
  (ACTION LANTERN-F)            #_Subroutine which defines special actions with this object
  (FDESC "A battery-powered lantern is on the trophy case.")  #_Description during first encounter
  (LDESC "There is a brass lantern (battery-powered) here.")  #_Later description in other locations
  (SIZE 15)>                    #_Defines weight to limit inventory capacity

The equivalent object in MDL is defined as:

<OBJECT ["LAMP" "LANTE" "LIGHT"]
        ["BRASS"]
        "lamp"
        <+ ,OVISON ,TAKEBIT ,LIGHTBIT>
        LANTERN
        ()
        (ODESC0 "A battery-powered brass lantern is on the trophy case."
         ODESC1 "There is a brass lantern (battery-powered) here."
         OSIZE 15
         OLINT [0 >])>

A more complex example involving combat, along with its MDL Zork equivalent, is presented in a 2019 blog post by Andrew Plotkin. Notably, the Z-machine has no support for garbage collection and ZIL has no concept of Lisp's list system.[12]

Interpreters

[edit]
An implementation of Frotz running on an iPhone, playing the MIT version of Zork.

Interpreters for Z-code files are available on a wide variety of platforms. The Inform website lists links to freely available interpreters for 15 desktop operating systems (including 8-bit microcomputers from the 1980s such as the Apple II, TRS-80, and ZX Spectrum, and grouping "Unix" and "Windows" as one each), 10 mobile operating systems (including Palm OS and the Game Boy), and four interpreter platforms (Emacs, Java, JavaScript, and Scratch). According to Nelson, it is "possibly the most portable virtual machine ever created".[13]

Popular interpreters include Nitfol and Frotz. Nitfol makes use of the Glk API, and supports versions 1 through 8 of the Z-machine, including the version 6 graphical Z-machine. Save files are stored in the standard Quetzal save format. Binary files are available for several different operating systems, including classic Mac OS, Unix-like systems, Windows.[14]

Frotz was written in C by Stefan Jokisch in 1995 for DOS. Over time it was ported to other platforms, such as Unix-like systems,[15] RISC OS,[16] and iOS.[17] Sound effects and graphics were supported to varying degrees. By 2002, development stalled and the program was picked up by David Griffith. The code base was split between virtual machine and user interface portions in such a way that the virtual machine became independent from any user interface. This allowed more variety in porting Frotz. One of the stranger ports is also one of the simplest: an instant messaging bot is wrapped around a version of Frotz with the minimum I/O functionality creating a bot with which one can play most Z-machine games using an instant messaging client.[18]

Another popular client for macOS and other Unix-like systems is Zoom.[19] It supports the same Quetzal save-format, but the packaging of the file-structure is different.

See also

[edit]
  • Glulx – Similar to the Z-machine, but relieves several limitations
  • Inform – A programming language that can produce Z-machine programs
  • SCUMM – by LucasArts, a graphical system similar to Z-machine
  • TADS – Made to address some of the Z-machine's limitations

References

[edit]
[edit]
Revisions and contributorsEdit on WikipediaRead on Wikipedia
from Grokipedia
The Z-machine is a developed by Joel Berez and in autumn 1979 for , Inc., designed to interpret (known as Z-code) compiled from the Zork Implementation Language (ZIL) and enable portable execution of games across diverse computer platforms without requiring recompilation. Its core purpose was to adapt the mainframe-based Zork for early personal computers, such as the and , by abstracting hardware differences into a unified interpretive environment. Over its active development period from 1979 to 1989, the Z-machine evolved through six primary versions, each enhancing capabilities like memory management, text compression, object handling, and input/output operations to support increasingly complex games. Versions 1 through 3 focused on basic text adventures with features such as a stack-based instruction set, a dictionary for parsing commands, and an object tree for game world modeling, while later iterations (4 through 6) introduced support for graphics, sound effects, mouse input, and larger file sizes to accommodate titles like Zork Zero. This progression allowed Infocom to release over 30 commercial games, including classics such as The Hitchhiker's Guide to the Galaxy and Trinity, all encoded in Z-code files that could be run via platform-specific interpreters like ZIP for early versions or YZIP for graphical ones. Following Infocom's closure in 1989, the Z-machine's legacy was preserved and expanded through community efforts, notably the reverse-engineering and formal standardization led by Graham Nelson and Mark Howell between 1994 and 1995. Nelson's Z-machine Standards Document (first released in 1995 and updated through version 1.1 in 2006) meticulously defined the machine's opcodes, memory layout, and behaviors across all eight versions (including non-Infocom extensions 7 and 8 for larger programs), ensuring full interpreter compatibility and portability. This built upon Nelson's earlier creation of the authoring system in 1993, which had initiated reverse-engineering of the Z-machine and compiles modern to Z-code, resulting in thousands of additional games and sustaining the format's use in interpreters today.

Overview

Definition and purpose

The Z-machine is a stack-based developed by Joel Berez and for in 1979 to execute games, particularly text-based adventures like . It interprets compiled from game , allowing programs to operate as if on a dedicated hardware platform regardless of the host system. The primary purpose of the Z-machine was to enable portability of Infocom's games across diverse hardware environments without requiring recompilation for each platform, such as the , , and systems. By abstracting hardware differences through interpretation, it addressed the challenges of limited memory (often 32K or less) and incompatible architectures prevalent in the late personal computing landscape, ensuring games could reach a broad audience efficiently. In the context of interactive fiction, the Z-machine supports parser-driven narrative experiences where players input natural language commands to interact with a simulated world, managing operations, story logic, object interactions, and within constrained environments. This design facilitated immersive, text-only adventures that emphasized exploration and puzzle-solving, with the machine handling the underlying to maintain consistency across play sessions. The Z-machine's initial development was tied to the porting of , originally created as a mainframe between 1977 and 1979, with formalizing the system for commercial release by 1980 and stabilizing its core design around 1981.

Key features

The Z-machine employs a stack-based to manage state, object manipulation, and routine calls, enabling efficient handling of recursive operations and local variables within constrained environments. This design includes packed addressing schemes, such as 2-byte packing in early versions, which optimize usage by compressing routine and string addresses into fewer bytes. Text output in the Z-machine is facilitated through ZSCII encoding, a 10-bit character system that supports ASCII-like values alongside extensions for international characters and control codes, allowing for compact storage of game narratives. Dynamic vocabulary tables enable flexible of player input by storing word dictionaries in memory, while built-in save and restore mechanisms in all versions, with added from version 5, preserve the execution state—including the stack, , and dynamic memory—for seamless game resumption. Portability is a core strength of the Z-machine, achieved through its format (Z-code), which remains independent of the host operating system, with interpreters responsible for platform-specific operations like screen display and keyboard handling. This abstraction layer allowed games to run across diverse hardware without recompilation. The system incorporates multimedia features starting from Version 3, including sound effects via dedicated opcodes that support volume control and repetition; Version 6 adds capabilities for displaying images and menu systems for user navigation. Early versions impose a 64KB limit on low memory (dynamic and static), supporting story files up to 128KB overall, though later iterations expand this up to 512KB. Error handling is integrated into the Z-machine's design, with mechanisms to detect and halt on invalid operations like or illegal opcodes, alongside debugging hooks such as verification routines for integrity checks during execution. These features ensure robust performance in , a design later adopted and extended by tools like for broader development.

Development history

Origins at Infocom

Infocom was founded on June 22, 1979, by a group of MIT graduates including Tim Anderson, Joel Berez, , Mike Broos, Scott Cutler, Stu Galley, and , primarily to commercialize interactive adventure games stemming from their work on at MIT's Dynamic Modeling Group. The company emerged from the need to adapt mainframe-based software for emerging personal computers, with serving as the foundational project. In the pre-Z-machine era, Zork I, II, and III were developed between 1977 and 1979 in the MDL (MUDDLE) programming language for the DEC PDP-10 mainframe, resulting in a sprawling game exceeding 1 MB that was distributed via ARPANET. Porting this code to microcomputers like the Apple II and TRS-80 proved challenging, as the games far exceeded the typical 16-32 KB memory limits of these systems, necessitating extensive manual rewriting and truncation that consumed months of effort per platform and introduced inconsistencies across versions. These portability issues highlighted the limitations of direct code translation from a mainframe environment to diverse, resource-constrained hardware. To address these challenges, decided around 1979-1981 to develop the , a architecture designed to generate a single, platform-agnostic story file that could be interpreted by lightweight, machine-specific executables, thereby automating and streamlining the . The debuted with the 1980 release of Zork I for personal computers, but its full implementation appeared in 1982 titles such as Deadline, a adventure by , and Starcross, a game by , marking the first productions fully leveraging the system for efficient cross-platform deployment. Infocom's business model centered on releasing high-quality text adventures simultaneously across dozens of platforms—over 30 by the mid-1980s—including the , 8-bit, Commodore 64, and IBM PC, which drove strong sales, with Zork I exceeding 400,000 copies. The Z-machine drastically reduced times from months of manual labor to mere days, as developers compiled once into a universal format while interpreters handled hardware variations, enabling rapid market expansion and cost efficiencies that sustained Infocom's growth through the early 1980s. A key milestone was the maturation of Z-machine Version 3 by the mid-1980s, which became the standard for most of Infocom's classic titles, supporting up to 255 rooms and 255 objects to accommodate more complex narratives and interactions within memory constraints. This version powered iconic games like The Hitchhiker's Guide to the Galaxy and , solidifying the Z-machine's role in enabling sophisticated without platform-specific rework.

ZIL and compilation tools

The (ZIL) was a developed by for authoring games targeted at the virtual machine. Derived from MDL, a of used in early development on the mainframe, ZIL adopted a prefix notation and parenthetical syntax to define game elements such as rooms, objects, actions, and parser behaviors. It supported routines for procedural logic, properties for object attributes, and global variables for state management, enabling developers to model complex worlds with interconnected elements like inventories, locations, and verb-object interactions. Prior to ZIL, prototyped games in MDL, but ZIL streamlined the process by stripping unnecessary features for more efficient code generation. ZIL's syntax emphasized declarative structures; for instance, objects were defined using the <OBJECT> form with properties like LOC for location, DESC for descriptions, FLAGS for attributes (e.g., TAKEBIT for portable items), and ACTION for custom routines triggered by player input. Routines followed the form <ROUTINE NAME (ARG1 ARG2) <body>>, where the body could include conditionals via COND, output with TELL, and returns with RTRUE or RFALSE. Global states were managed through variables prefixed with commas (e.g., ,HERE for the current room), and the parser tokenized input into semantic units like PRSA (action verb), PRSO (direct object), and PRSI (indirect object) for processing commands. Technical conventions in ZIL included Easter eggs like "zorkmid" as a unit of currency in object properties, reflecting Infocom's playful nomenclature while maintaining consistent property numbering across objects within a game. A representative example of ZIL code for handling a basic movement command like "go north" involves room properties and a generic walk routine. A room might be defined as <ROOM LIVING-ROOM (DESC "You are in the living room.") (NORTH TO [KITCHEN](/page/Kitchen)) (FLAGS LIGHTBIT)>, where the parser sets PRSA to V?WALK and PRSO to P?NORTH. The movement routine then checks: <ROUTINE GO? (DIRECTION) <COND (<GETP ,HERE ,DIRECTION> <GOTO .?>) (T <TELL "You can't go that way." CR> <RFALSE>)>>, executing the transition if the directional property (e.g., NORTH) exists. This structure allowed for conditional exits, such as (NORTH TO [KITCHEN](/page/Kitchen) IF UNLOCKED ELSE "The door is locked."). The compilation pipeline for ZIL began with source files written in the language, which were processed by ZILCH, the primary , to generate Z Assembly Language (often in .ZAP files). ZILCH handled macro expansion, optimization, and , producing assembly that could be manually edited for fine-tuning. The Z Assembly Language was then assembled by ZAP (Zork Assembler Program) into the final Z-code story file, a compact, machine-independent binary for the Z-machine. ZILCH also included utilities for generating headers and managing build configurations, though it was tightly integrated with the environment initially. This formed a closed at , requiring developers to optimize memory usage manually due to ZIL's verbose syntax and the constraints of early Z-machine versions, such as limited object counts and string storage. ZIL and its tools remained proprietary to throughout the company's operation, used exclusively by in-house authors for all 32 major releases from to 1989. The language's reliance on Lisp-like evaluation and manual interventions for packing objects into memory slots made it powerful for narrative depth but demanding for efficiency, often necessitating iterative compilation to fit within Z-machine limits like 64 KB for version 3 games. 's shutdown in 1989 marked the end of active ZIL development, leaving the tools inaccessible until leaks and reverse-engineering efforts in the .

Expansion via Inform

Following Infocom's acquisition by in 1986 and the subsequent closure of its operations in 1989, the Z-machine entered a period of dormancy, with no new official developments or tools emerging from the company. This changed in 1993 when Graham Nelson created as a modern authoring system specifically targeting the Z-machine, enabling hobbyists and independent developers to produce in the established format. Inform 6, released in 1996, further standardized Z-machine Versions 1 through 8 by incorporating extensions for larger story files in Versions 7 and 8 while maintaining compatibility with earlier versions. Key features of Inform included a simplified, higher-level syntax that was more intuitive and accessible than Infocom's proprietary , reducing the need for low-level programming through an extensive of predefined objects, actions, and rules; support for modular extensions to customize ; and the Z-machine as the primary output format. The Z-machine remained Inform's default target until 2006, when support for the —designated informally as Version 10—was added in Inform 7 to accommodate larger games and modern features beyond Z-machine limits. Nelson's standardization efforts culminated in the Z-machine Standards Document (version 1.0 released in 1996 and updated to version 1.1 in 2006), which formally documented opcodes, memory organization, the ZSCII , and other technical details, providing a comprehensive reference that facilitated community-driven implementations and ensured long-term portability. This specification, building on earlier drafts from 1995, helped establish de facto standards within the emerging community, enabling consistent interpreter development and game creation without proprietary restrictions. The adoption of revitalized the Z-machine in the 1990s and 2000s, leading to the creation of thousands of free games, such as Curses! (1993) by Nelson himself and later works like Anchorhead (1998) by Michael Gentry, which leveraged the format's portability and the tools' ease of use to foster a vibrant, non-commercial scene. As of 2025, remains actively maintained, with the latest Inform 7 release (version 10.1.2) in September 2024 supporting Z-machine output alongside Glulx.

Technical architecture

Versions and standards

The Z-machine evolved through eight versions developed primarily by between 1979 and 1988, with versions 7 and 8 added later by Graham Nelson to support larger games created using the system. , introduced in autumn 1979 by Joel Berez and , provided basic text handling capabilities, including a header, divided layout, variables and stack, object , , and instruction format, along with "shift lock" characters for text compression. Version 2 followed as a minor update, introducing a 32-word abbreviation bank and a six-digit in the header. Version 3, established by March 1982 and used until November 1987, became the most common format for games such as Deadline and Zork I, dropping shift lock compression in favor of 96 abbreviation entries, adding the "verify" for checksums, and supporting status line reprinting; it limited story files to 128 KB total, with approximately 64 KB allocated to dynamic . Version 4, released in August 1985 with , enhanced handling to address size restrictions of prior versions, while expanding the maximum story file size to 256 KB. Version 5, introduced in September 1987 for titles like Beyond Zork and Border Zone, incorporated calculated addresses, character graphics, real-time keyboard input, additional opcodes, and support for 9-letter words in the , maintaining the 256 KB file limit. Version 6, deployed in 1988 for games including Zork Zero and , added graphics support via opcodes such as @picture, mouse input, menus, sound, and a computationally advanced parser, doubling the story file size to 512 KB. Versions 7 and 8, devised by Nelson in 1995, extended the 512 KB limit of version 6 but were otherwise similar to version 5, with version 7 rarely used and version 8 applied nichely to large Inform-generated games requiring packed address scaling (e.g., byte address B = 8P for version 8). These versions introduced compatibility levels where interpreters must handle earlier formats, with dynamic and static memory combined not exceeding 64 KB across all versions, though total file sizes varied. Infocom maintained informal specifications for the Z-machine internally, without public documentation, until Nelson formalized them in The Z-Machine Standards Document, first released in draft form (version 0.2) in November 1995 and updated to version 1.0 around 1996, and version 1.1 in May 2006 (revised February 2014). This document standardized elements across versions 1 through 8, including header formats (e.g., release number and serial code in YYMMDD format like 970619), behaviors, organization, and expansion provisions for features like . Community extensions, such as the save-file format (version 1.4, November 1997), further standardized portable save states across interpreters by defining (IFF) chunks for and stack data, addressing Infocom's proprietary save incompatibilities.

Memory organization

The Z-machine employs a contiguous block of memory divided into distinct regions to support the execution of interactive fiction games, with the entire story file typically loaded into memory at startup. The layout begins with a fixed 64-byte header at address 0, which contains essential metadata including the machine version, memory configuration pointers, and a checksum for integrity verification. Following the header is dynamic memory, a writable region starting immediately after byte 63 and extending to the address specified in header word $0E (multiplied by 2 for byte addressing), used for mutable game state such as the object table and global variables. Static memory, which is read-only, occupies the subsequent region up to the start of high memory (indicated by header word $04 multiplied by 2), housing permanent data structures like the vocabulary dictionary and grammar tables. High memory, accessed indirectly, holds read-only code and resources including routines, Z-strings, and the call stack, extending to the end of the allocated memory block. Addressing in the Z-machine distinguishes between direct byte or word addresses in the lower memory regions and packed addresses for high memory to optimize space in the compact story files. Byte addresses are straightforward unsigned values for accessing dynamic and static , while word addresses represent even byte locations (multiplied by 2). Packed addresses, encoded in 1 to 4 bytes depending on the version, are unpacked via version-specific multipliers—such as multiplying by 2 for versions 1–3 or by 4 for versions 4–5—to compute locations in high memory, with versions 6–7 adding header-based offsets and version 8 using multiplication by 8. This scheme enables efficient referencing of routines and strings while limiting total memory; for example, version 3 supports up to 128 KB overall, with dynamic memory configurable but often around half that size in practice. Key data structures are allocated within these regions to manage game elements efficiently. The object table resides in dynamic memory (starting at the address in header word $0A), forming a hierarchical tree where each object entry includes attributes (bit flags for state, up to 48 in later versions), links to parent, sibling, and child objects, and pointers to property lists containing numerical or textual data; versions 1–3 limit objects to 255 with 9-byte entries, while versions 4+ expand to 65,535 objects using 14-byte entries. The dictionary, located in static memory (at header word $08), stores hashed vocabulary words as Z-character encoded strings for input parsing, typically supporting hundreds of entries sorted alphabetically, with entry sizes of 4 bytes in early versions increasing to 6 in later ones. Routine frames are pushed onto the call stack in high memory during execution, each comprising the return program counter, 0–15 local variables, and an evaluation stack for temporary values; the evaluation stack supports up to 256 entries across frames, though the overall call stack depth is limited only by available memory. Resource management in the Z-machine relies on manual allocation by game authors, as no automatic garbage collection is provided, requiring careful packing of to minimize fragmentation and fit within constraints. Dynamic serves as a heap for runtime modifications, such as updating object attributes or allocating temporary storage, but authors must pre-arrange layouts to avoid exhaustion during play. File I/O is handled by loading the complete story file into upon initialization, with save states preserving the dynamic region; interpreters manage high access transparently, but fragmentation from stack growth or property additions can necessitate compression techniques in . Version-specific sizes influence these limits, such as 128 KB total for version 3 compared to 256 KB for version 5. To illustrate the conceptual memory map:
  • Header (0–63 bytes): Configuration and pointers.
  • Dynamic Memory (~64 bytes to ~32–64 KB): Writable heap (objects, globals); grows/shrinks via game logic.
  • Static Memory (~32–64 KB to ~64–128 KB): Read-only data (dictionary, grammar); fixed at compile time.
  • High Memory (~64–128 KB to end): Code and stack (routines, strings); indirect access via packing.
This organization ensures portability across hardware while constraining resource use for the era's computing limitations.

Instruction set and execution

The Z-machine employs an opcode-based instruction set where each instruction is encoded as a variable-length sequence ranging from 1 to 9 bytes, with opcodes numbered from 0 to 255. These opcodes are divided into forms based on the number and types of operands: zero-operand (0OP), one-operand (1OP), two-operand (2OP), variable number of operands (VAR), and extended opcodes (EXT, introduced via a special prefix in Version 5 and later). Common categories include stack operations such as @add (adds two values and stores the result) and @sub (subtracts one value from another), branching instructions like @je (jumps if the first operand equals any subsequent operand) and @jl (jumps if the first operand is less than the second), object manipulation opcodes including (retrieves a property value from an object), and input/output commands such as @print (outputs a literal ) and @call (invokes a routine with arguments). The execution model follows a classic fetch-decode-execute cycle within an interpreter loop, where the (PC) points to the current instruction in the high memory region containing the game's code. The interpreter fetches the and operands from at the PC location, decodes them to determine the operation and data types (such as small constants of 0-255, large constants of 0-65535, or variables), executes the instruction, and then advances the PC to the next byte position unless occurs. Branching uses a 1- or 2-byte offset after the operands; the high bit of the first byte (bit 7) is 0 to branch if the condition is false or 1 to branch if true. If the branch is taken, for a 1-byte offset O (0 to 63): if O=0, execute rfalse; if O=1, execute rtrue; otherwise, set PC to the position immediately after the branch data plus (O - 2). For 2-byte offsets, the offset is a signed 14-bit value with analogous special cases and adjustment by -2. Stack operations form a core part of the instruction set, supporting zero-operand instructions that implicitly use the evaluation stack (a last-in, first-out structure for temporary values), one-operand forms that take a single and often push or pop from the stack, two-operand instructions that operate on two explicit values, and variable forms that specify the number of operands in a following byte. For instance, @store (opcode 13 in 2OP form) takes a variable and a value, storing the latter into the former to update game state such as player location or flags, while implicitly managing stack pushes for intermediate results in expressions. Operand types are encoded efficiently: variables are referenced by a 1-byte index (0 for the stack top, 1-255 for or global variables), allowing compact representation without . Flow control is managed through dedicated opcodes for subroutine calls, unconditional jumps, and . Routine calls like @call (VAR form, opcode 224) push the return and up to three arguments (or more in extended versions) onto the stack before transferring control to the routine's , with results optionally stored upon return. Loops and unconditional branches use @jump (1OP, opcode 140), which sets the PC to the current position plus a signed offset for arbitrary . In Versions 5 and later, error handling is supported by @catch (0OP, opcode 185 in V5/6), which pushes the current stack frame pointer for later use, and @throw (2OP, opcode 28), which unwinds the stack to a specified frame and returns a value. Unique to the Z-machine is its lack of interrupts, ensuring uninterrupted execution except for explicit operations like sound completion callbacks in later versions, which promotes predictable behavior. This deterministic model facilitates save and restore functionality: saves capture the full state and stack, while restores resume from the saved PC with an empty stack, guaranteeing identical execution paths across interpreters. The following table summarizes the standard opcodes by form and category, with numbers, equivalents, store/branch capabilities (St for result storage, Br for conditional branching), and representative assembly syntax for clarity. Illegal opcodes in a given version cause interpreter errors. The extended opcodes (EXT, prefixed by 190) are listed separately for versions 5+, including only defined standard ones.
FormDecimal RangeHex RangeSt/BrCategory Examples (Opcode: Name - Syntax)
2OP (Long form, small/variable operands)0-31 (small const, small const)
32-63 (small const, variable)
64-95 (variable, small const)
96-127 (variable, variable)
0x00-0x1F
0x20-0x3F
0x40-0x5F
0x60-0x7F
VariesBranch: 1: je a b ?L; 2: jl a b ?L; 3: jg a b ?L; 6: jin obj1 obj2 ?L; 7: test bitmap flags ?L; 10: test_attr obj attr ?L
Object: 11: set_attr obj attr; 12: clear_attr obj attr; 14: insert_obj obj dest; 17: get_prop obj prop -> r; 18: get_prop_addr obj prop -> r; 19: get_next_prop obj prop -> r
Stack/Math: 8: or a b -> r; 9: and a b -> r; 13: store var val; 15: loadw arr idx -> r; 16: loadb arr idx -> r; 20: add a b -> r; 21: sub a b -> r; 22: mul a b -> r; 23: div a b -> r; 24: mod a b -> r
Flow: 25: call_2s rout arg -> r; 26: call_2n rout arg; 27: set_colour fg bg (V5+); 28: throw val frame (V5+)
Check: 4: dec_chk var val ?L; 5: inc_chk var val ?L
1OP (Short form, large/small/variable operands)128-143 (large const)
144-159 (small const)
160-175 (variable)
0x80-0x8F
0x90-0x9F
0xA0-0xAF
VariesBranch/Object: 128: jz a ?L; 129: get_sibling obj -> r ?L; 130: get_child obj -> r ?L
Object: 131: get_parent obj -> r; 132: get_prop_len addr -> r
Stack: 133: inc var; 134: dec var; 142: load var -> r; 143: not val -> r (V3/4; VAR in V5+)
I/O: 135: print_addr addr; 141: print_paddr paddr
Flow/Object: 136: call_1s rout -> r; 137: remove_obj obj; 138: print_obj obj; 139: ret val; 140: jump ?L
0OP (No operands)176-191 (except 190=EXT)0xB0-0xBFNone (except Br on some)Flow/I/O: 176: rtrue; 177: rfalse; 178: print "str"; 179: print_ret "str"; 180: nop; 183: restart; 184: ret_popped; 186: quit; 187: new_line; 188: show_status (V3+); 191: piracy ?L (V5+)
Stack: 185: pop (V1-4; catch in V5/6)
Save: 181: save ?L (V1-4); 182: restore ?L (V1-4); 189: verify ?L (V5; unused in V1-4)
VAR (Variable operands, types in next 1-2 bytes)192-223 (2OP)
224-255 (VAR/EXT prefix)
0xC0-0xDF (2OP)
0xE0-0xFF (VAR)
VariesBranch: 193: call_1n rout ?L (V4+; illegal V1-3); 194: remove_obj obj ?L (V4+); 195: print_obj obj ?L (V4+); 196: ret val ?L (V4+); 197: jump ?L (V4+); 198: print_paddr paddr ?L (V4+)
Store: 199: load var -> r ?L (V4+); 200: not val -> r ?L (V5/6)
I/O: 201: call rout -> r ?L (V4+); 202: store var val ?L (V4+); 203: insert_obj obj dest ?L (V4+); 204: loadw arr idx -> r ?L (V4+); 205: loadb arr idx -> r ?L (V4+); 206: get_prop obj prop -> r ?L (V4+); 207: get_prop_addr obj prop -> r ?L (V4+); 208: get_next_prop obj prop -> r ?L (V4+); 209: add a b -> r ?L (V4+); 210: sub a b -> r ?L (V4+); 211: mul a b -> r ?L (V4+); 212: div a b -> r ?L (V4+); 213: mod a b -> r ?L (V4+)
Flow: 214: call_vs rout -> r (V4+); 215: store var val (V5+); 216: insert_obj obj dest (V5+); 217: loadw arr idx -> r (V5+); 218: loadb arr idx -> r (V5+); 219: get_prop obj prop -> r (V5+); 220: get_prop_addr obj prop -> r (V5+); 221: get_next_prop obj prop -> r (V5+); 222: set_attr obj attr ?L (V5+); 223: clear_attr obj attr ?L (V5+); 224: call_vs rout -> r (V5+); 225: store var val (V6+); 226: insert_obj obj dest (V6+); 227: loadw arr idx -> r (V6+); 228: read table parse (V5+; aread in Inform); 229: print_char ch (V5+); 230: print_num val (V5+); 231: random num -> r (V5+); 232: split_window lines (V4+); 233: set_window win (V4+); 234: output_stream num table (V5+; - in V4); 235: input_stream num (V5+); 236: call_vs2 rout -> r (V6+); 237: erase_window win (V6+); 238: erase_line value (V6+); 239: set_cursor_line row (V6+); 240: set_cursor_column col (V6+); 241: set_cursor_position row col (V6+); 242: buffer_mode on/off (V6+); 243: output_stream num table (V6+); 244: input_stream num (V6+); 245: set_font font -> r (V5+); 246: draw_picture pic y x (V6+); 247: picture_data table pic (V6+); 248: not val -> r (V6+); 249: call_vn rout (V6+); 250: call_vn2 rout (V7/8); 251: tokenise dict text parse (V5+); 252: encode_text dest src len (V5+); 253: copy_table dest src size (V5+); 254: print_table addr size table (V7+); 255: check_arg_count num ?L (V7+)
EXT (Byte 190 prefix + 0-255 number; V5+)N/A (second byte 0-255)N/AVaries0: save table bytes name prompt -> (result) (V5); 1: restore table bytes name prompt -> (result) (V5); 2: log_shift number places -> (result) (V5); 3: art_shift number places -> (result) (V5+); 4: set_font font -> (result) (V5+); 5: draw_picture picture-number y x (V6); 6: picture_data picture-number array ?(label) (V6); 7: erase_picture picture-number y x (V6); 8: set_margins left right window (V6); 9: save_undo -> (result) (V5); 10: restore_undo -> (result) (V5); 11: print_unicode char-number (V5+); 12: check_unicode char-number -> (result) (V5+); 13: set_true_colour foreground background (V5+); 16: move_window window y x (V6); 17: window_size window y x (V6); 18: window_style window flags operation (V6); 19: get_wind_prop window property-number -> (result) (V6); 20: scroll_window window pixels (V6); 21: pop_stack items stack (V6); 22: read_mouse array (V6); 23: mouse_window window (V6); 24: push_stack value stack ?(label) (V6); 25: put_wind_prop window property-number value (V6); 26: print_form formatted-table (V6); 27: make_menu number table ?(label) (V6); 28: picture_table table (V6); 29: buffer_screen mode -> (result) (V6+). Opcodes 14-15, 30-255 are reserved or undefined in the standard (50-127 reserved, 128-255 user-defined).

Implementations and interpreters

Original hardware and software interpreters

The original Z-machine interpreters developed by were primarily software implementations designed to run on specific hardware platforms of the , enabling the execution of Z-code files across diverse personal computers and systems. These interpreters emulated the Z-machine virtual architecture directly in , prioritizing performance on resource-constrained environments. The first such interpreters emerged for early microcomputers, with the inaugural versions created for the Model I by Scott Cutler and for the by Bruce K. Daniels around 1980-1981, written in platform-specific assembly languages (Z80 for the Model I and 6502 for the ) to handle the initial ports of . These early efforts focused on text-based , mapping Z-machine opcodes to native assembly instructions for efficient execution. Subsequent software interpreters expanded to other platforms, each optimized for the target system's processor and I/O capabilities. For instance, the interpreter, released in 1982, was coded in Z80 assembly to support systems like the and Osborne 1. By 1983, an 8086 assembly version arrived for on PCs, followed in 1984 by a 68000 assembly for the Macintosh, which integrated with the system's Pascal-based tools and handled hierarchical file systems. The ST received its interpreter in 1985, also in 68000 assembly, emphasizing non-PC ports that extended reach to European and hobbyist markets. Development typically involved writing core emulation logic in assembly for speed, with managed through platform-specific system calls, such as serial transfers from DEC-20 mainframes during testing. This approach ensured low overhead but tied interpreters tightly to hardware, limiting portability without recompilation. While predominantly software-based, some later implementations incorporated hardware-specific optimizations, such as the Amiga interpreter from around 1986-1987, which used 68000 assembly and C for audio handling to leverage the system's custom chips for sound effects. Similarly, ports to the Japanese PC-98 in 1987 adapted the Z-machine for its 8086-compatible architecture, though still as software emulation. Early interpreters supported only versions 1-5 of the Z-machine, restricting features to text adventures with no graphics; graphics and sound capabilities were not added until version 6 interpreters in 1987, as seen in games like The Lurking Horror. Distribution of these interpreters occurred alongside Infocom's games, bundled on floppy disks within physical game packages or included in collections like the Masterpieces of Infocom series starting in 1986. Standalone interpreters were occasionally sold separately for users to play multiple titles. By 1989, Infocom had developed interpreters for over 30 distinct platforms, including Commodore 64, , and TI-99/4A, demonstrating the Z-machine's role in achieving broad compatibility without altering game code. In November 2023, the source code for many of these original interpreters was publicly released, enabling further analysis and ports to modern systems.

Modern and portable interpreters

Modern interpreters for the Z-machine emphasize portability across contemporary platforms, leveraging open-source development to support a wide array of devices from desktops to mobile and web browsers. These tools emulate the original specifications while incorporating enhancements for modern hardware, such as text rendering and integration, ensuring compatibility with legacy titles. One of the foundational modern interpreters is Frotz, originally developed by Stefan Jokisch in 1995 for Unix and DOS systems. Written , Frotz complies with the Z-machine Standard 1.1 and provides full support for versions 1 through 8, with extensions for and sound through the Blorb resource format. Blorb, standardized in 1996, packages Z-machine stories with images and OGG audio files, allowing interpreters like Frotz variants (e.g., sfrotz) to display pictures and play sounds without proprietary tools. Bocfel, introduced in the early by Chris Spiegel, extends portability further as a multi-platform C-based interpreter supporting Z-machine versions 1-5, 7, and 8 fully, with partial version 6 compatibility. It features optimizations for low-end devices and integrates output for international text handling. Bocfel's lightweight design facilitates cross-compilation to various operating systems, including embedded systems like the Pico. Web-based options like , launched in 2008 by Paul Thomas, enable browser play using JavaScript engines such as Quixe. supports Z-machine games directly in HTML5 environments, promoting accessibility without downloads, and integrates with the Interactive Fiction Database (IFDB) for seamless online playback. Its JavaScript foundation allows deployment on any device with a modern browser, including mobile. Save file compatibility across interpreters relies on the standard, formalized in 1997 by as an IFF-based format for portable game states. This ensures saves from one interpreter, such as Frotz, load in another like Bocfel, preserving progress in multi-platform play. Sound support in these tools often includes OGG via Blorb, with some legacy MIDI handling for older resources. Community-driven mobile adaptations include the port of Frotz, released in 2008, which adds touch-friendly interfaces while maintaining core Z-machine emulation. Performance tweaks in interpreters like Bocfel target resource-constrained devices, reducing memory usage for smoother execution on smartphones and tablets. Recent advancements include Lectrote, developed by Andrew Plotkin starting in 2016 and updated through 2021, which wraps Z-machine emulation (via the ZVM engine) in an app for desktop cross-platform use. Lectrote supports versions 3, 4, 5, and 8, with features like automatic transcripting for preservation. Preservation efforts benefit from archives like the Archive on archive.org, hosting Z-machine files for emulator access. A key challenge for modern interpreters remains full support for version 6 games, which rely on proprietary graphics formats not natively emulated on current hardware. While Blorb extensions address some V6 picture handling, complete fidelity requires specialized mappings, limiting seamless playback compared to text-only versions. As of 2025, interpreters like Bocfel remain actively integrated into web and mobile projects, with no major new developments reported since 2021.

Legacy and influence

Impact on interactive fiction

The Z-machine played a pivotal role in the commercial golden age of during the , enabling to release over 30 titles that standardized the parser-based text adventure genre. These games, such as and Deadline, leveraged the Z-machine's portability to reach diverse platforms, achieving peak annual sales of $10 million in 1984 through 725,000 units sold. This success established sophisticated natural-language parsing as a core mechanic, influencing competitors like Sierra On-Line to incorporate similar parser systems in their graphical adventures using the AGI engine. The Z-machine's legacy extended into the 1990s revival of , where Graham Nelson's compiler—targeting the Z-machine—democratized game creation and sparked an explosion of free titles. This led to the inaugural XYZZY Awards in 1996, celebrating community-driven works, with over 1,000 Z-code games available by 2000 through archives and competitions like IFComp. Notable examples include Michael Gentry's (1998), a adventure that won Best Setting at the XYZZY Awards and exemplified the format's narrative depth. In terms of design, the Z-machine's strict memory constraints—typically 128 KB or less—fostered concise, evocative storytelling that prioritized implication over exposition, shaping the genre's emphasis on player imagination. enhanced this with "feelies," physical artifacts like maps and props included in game packages to extend the narrative beyond the screen, often integrating with save mechanics for immersive clues. The Z-machine's influence permeated academia, inspiring studies on procedural narrative where games like demonstrated dynamic, branching stories generated through code. In , has been used to teach logic and , as in classroom exercises where students map commands to simulate programming problem-solving. As of 2025, the Interactive Fiction Database lists over 600 games created with Inform for the Z-machine or compatible formats, underscoring its enduring role in indie .

Preservation and extensions

Efforts to preserve the Z-machine have centered on archiving story files and emulating the original hardware platforms that ran its interpreters. The Interactive Fiction Archive, established in 1993, serves as a primary repository for interactive fiction works, hosting thousands of Z-machine-compatible files in its /games/zcode directory, including both Infocom originals and community-created games. Emulation projects like MAME preserve the experience of running Z-machine interpreters on period hardware, such as the Apple II or Commodore 64, by replicating the underlying systems that Infocom targeted in the 1980s. The Z-machine specification was detailed in a document released by Graham Nelson in 1993, which is freely available under an open license, enabling open development and widespread preservation without legal barriers to the technical standard. The Interactive Fiction Technology Foundation (IFTF) has maintained and updated the standards document, with version 1.2 released in 2014, supporting continued development and interpreter compatibility as of 2025. Extensions to the Z-machine have enhanced its capabilities while maintaining , often through -driven standards. The Blorb format, introduced by Andrew Plotkin in 1998, bundles Z-code story files with multimedia resources like images and sounds into a single archive, simplifying distribution for interpreters supporting Versions 5 and 6. Standardized features such as and quicksave, defined in the Z-machine standards document, allow interpreters to store and revert game states efficiently, with undo implemented via the for rapid access during play. efforts have also expanded support for Version 6's native color capabilities, with interpreters like Frotz providing robust implementation of the 16-color palette for enhanced visual storytelling in compatible games. Modern adaptations integrate the Z-machine into contemporary environments, bridging text-based with graphical and immersive technologies. Tools like Andrew Plotkin's Ztools suite enable validation, disassembly, and analysis of Z-code files, aiding developers in maintaining and extending legacy works. Experimental projects in the 2020s have embedded Z-machine interpreters within Unity, allowing hybrid that combines classic text adventures with 3D visuals or VR elements for more dynamic player experiences. Preservation faces challenges from restrictions and inherent design limitations. While the Z-machine specification is open, copyrights to Infocom's original games remain with , limiting legal distribution of those titles despite free access to the emulator ecosystem. The architecture lacks native networking support, confining it to single-player, offline scenarios and requiring external extensions for any multiplayer or online features. Looking ahead as of 2025, the Z-machine's modular design positions it for potential revival in AI-driven , where its lightweight could serve as a backend for procedurally generated narratives, though such applications remain exploratory.

References

  1. https://apps.apple.com/[us](/page/United_States)/app/frotz/id287653015
Add your contribution
Related Hubs
User Avatar
No comments yet.