14.1

This table contains all 119 opcodes and, taken with the dictionary
in S 15, describes exactly what each should do.
In addition, it lists which opcodes are actually used in the known
Infocom story files, and documents the Inform assembly language syntax.

14.2

Formally, it is illegal for a game to contain an opcode
not specified for its version. An interpreter should normally halt with
a suitable message.

14.2.1

However, extended opcodes in the range EXT:29 to EXT:255
should be simply ignored (perhaps with a warning message somewhere
off-screen).

14.2.2

*** EXT:11 and EXT:12 are opcodes newly added to Standard 1.0
and which can be generated in code compiled by Inform 6.12 or later.
EXT:13 to EXT:15, and EXT:29 to EXT:127, are reserved for future versions
of this document to specify.

14.2.3

Designers who wish to create their own "new" opcodes, for one
specific game only, are asked to use opcode numbers in the range EXT:128 to
EXT:255. It is easy to modify Inform to name and assemble such opcodes.
(Of course the game will then have to be circulated with a suitably modified
interpreter to run it.)

14.2.4

Interpreter-writers should ideally make this easy by providing a
routine which is called if EXT:128 to EXT:255 are found, so that
the minimum possible modification to the interpreter is needed.

Reading the opcode tables

The two columns "St" and "Br" (store and branch) mark whether an
instruction stores a result in a variable, and whether it must provide a
label to jump to, respectively.

The "Opcode" is written TYPE:Decimal where the TYPE
is the operand count (2OP, 1OP, 0OP or VAR) or else EXT for two-byte
opcodes (where the first byte is (decimal) 190).
The decimal number is the lowest possible decimal opcode value.
The hex number is the opcode number within each TYPE.

The "V" column gives the Version information. If nothing is specified, the
opcode is as stated from Version 1 onwards. Otherwise, it exists only from
the version quoted onwards. Before this time, its use is illegal. Some
opcodes change their meanings as the Version increases, and these have more
than one line of specification. Others become illegal again, and these are
marked [illegal].

In a few cases, the Version is given as "3/4" or some such. The first
number is the Version number whose specification the opcode belongs to, and
the second is the earliest Version in which the opcode is known actually to
be used in an Infocom-produced story file. A dash means that it seems
never to have been used (in any of Versions 1 to 6).
The notation "5/*" means that the opcode was introduced in this
Standards document long after the Infocom era.

The table explicitly marks opcodes which do not exist in any version of the
Z-machine as ------: in addition, none of the extended set of codes
after EXT:28 were ever used.

Inform assembly language

This section documents Inform 6 assembly language, which is richer than
that of Inform 5. The Inform 6 assembler can generate every legal
opcode and automatically sets any consequent header bits (for instance,
a usage of set_colour will set the "colours needed" bit).

One way to get a picture of Inform assembly language is to compile
a short program with tracing switched on (using the -a or -t
switches).

1. An Inform statement beginning with an @ is sent directly to the
assembler. In the syntax below, (variable) and (result) must be
variables (or sp, a special variable name available only in assembly
language, and meaning the stack pointer); (label) a label
(not a routine name).

(literal-string) must be literal text in quotation marks "thus".

routine should be the name of a routine (this assembles to its packed
address). Otherwise any Inform constant term (such as '/' or
'beetle') can be given as an operand.

2. It is optional, but sensible, to place a -> sign before a
store-variable. For example, in

@mul a 56 -> sp;

("multiply variable a by 56, and put the result on the stack") the
-> can be omitted, but should be included for clarity.

3. A label to branch to should be prefaced with a question mark ?,
as in

@je a b ?Equal; ! Branch to Equal if a == b

(If the question mark is omitted, the branch is compiled in the short form,
which will only work for very nearby labels and is very seldom useful
in code written by hand.) Note that the effect of any branch
instruction can be negated using a tilde ~:

@je a b ?~Different; ! Branch to Different if a ~= b

4. Labels are assembled using full stops:

.MyLabel;

All branches must be to such a label within the same routine. (The
Inform assembler imposes the same-routine restriction.)

5. Most operands are assembled in the obvious way: numbers and constant
values (like characters) as numbers, variables as variables, sp as
the value on top of the stack. There are two exceptions. "Call"
opcodes expect as first operand the name of a routine to call:

@call_1n MyRoutine;

but one can also give an indirect address, as a constant or variable,
using square brackets:

@call_1n [x]; ! Call routine whose address is in x

Secondly, seven Z-machine opcodes access variables but by their
numbers: thus one should write, say, the constant 0 instead of the
variable sp. This is inconvenient, so the Inform assembler
accepts variable names instead. The operands affected are those
marked as (variable) in the syntax chart; Inform translates
the variable name as a "small constant" operand with that
variable's number as value. The affected opcodes are:

inc, dec, inc_chk, dec_chk, store, pull, load.

This is useful, but there is another possibility, of genuinely
giving a variable operand. The Inform notation for this involves
square brackets again:

6. The Inform assembler is also written with possible extensions
to the Z-machine instruction set in mind. (Of course these can only
work if a customised interpreter is used.) Simply give a specification
in double-quotes where you would normally give the opcode name.
For example,

@"1OP:4S" 34 -> i;
@get_prop_len 34 -> i;

are equivalent instructions, since get_prop_len is instruction 4
in the 1OP (one-operand) set, and is a Store opcode. The syntax is:

(EXT_LONG
is a logical possibility but has not been used in the Z-machine
so far: the assembler provides it in case it might be useful in future.)
The possible flags are:

S Store opcode
B Branch opcode
T Text in-line instead of operands
(as with "print" and "print_ret")
I "Indirect addressing": first operand is a (variable)
Fnn Set bit nn in Flags 2 (signalling to the interpreter that an
unusual feature has been called for): the number is in decimal

For example,

"EXT:128BSF14"

is an exotic new opcode, number 128 in the extended range, which is
both Branch and Store, and the assembly of which causes bit 14 to
be set in "Flags 2". See S 14.2 below for rules on how to number
newly created opcodes.

Remarks

The opcodes EXT:5 to EXT:8 were very likely in Infocom's own Version 5
specification (documentary records of which are lost): they seem to have
been partially implemented in existing Infocom interpreters, but do not
occur in any existing Version 5 story file. They are here left
unspecified.

The notation "5/3" for sound_effect is because this plainly
Version 5 feature was used also in one solitary Version 3 game,
'The Lurking Horror' (the sound version of which was the last Version 3
release, in September 1987).

The 2OP opcode 0 was possibly intended for setting break-points
in debugging (and may be used for this again). It was not nop.

read_mouse and make_menu are believed to have been used only in
'Journey' (based on a check of 11 Version 6 story files).

picture_table is used once by 'Shogun' and several times by
'Zork Zero'.