1. The memory map
1.1 Regions of memory
The memory map of the Z-machine is an array of bytes with “byte addresses” running from 0 upwards. This is divided into three regions: “dynamic”, “static” and “high”. Dynamic memory begins from byte address $00000
and runs up to the byte before the byte address stored in the word at $0e
in the header. (Dynamic memory must contain at least 64 bytes.) Static memory follows immediately on. Its extent is not defined in the header (or anywhere else), though it must end by the last byte of the story file or by byte address $0ffff
(whichever is lower). High memory begins at the “high memory mark” (the byte address stored in the word at $04
in the header) and continues to the end of the story file. The bottom of high memory may overlap with the top of static memory (but not with dynamic memory).
1.1.1
Dynamic memory can be read or written to (either directly, using loadb
, loadw
, storeb
and storew
, or indirectly with opcodes such as insert_obj
and remove_obj
).
1.1.3
Except for its (possible) overlap with static memory, high memory cannot be directly accessed at all by a game program. It contains routines, which can be called, and strings, which can be printed using print_paddr
.
1.2 Addresses
There are three kinds of address in the Z-machine, all of which can be stored in a 2-byte number: byte addresses, word addresses and packed addresses.
1.2.1
A byte address specifies a byte in memory in the range 0 up to the last byte of static memory.
1.2.2
A word address specifies an even address in the bottom 128K of memory (by giving the address divided by 2). (Word addresses are used only in the abbreviations table.)
1.2.3
[1.0] A packed address specifies where a routine or string begins in high memory. Given a packed address P, the formula to obtain the corresponding byte address B is:
2P |
Versions 1, 2 and 3 |
4P |
Versions 4 and 5 |
4P + 8R_O |
Versions 6 and 7, for routine calls |
4P + 8S_O |
Versions 6 and 7, for print_paddr |
8P |
Version 8 |
R_O
and S_O
are the routine and strings offsets (specified in the header as words at $28
and $2a
, respectively).
Dynamic |
|
header |
|
abbreviation strings |
|
|
abbreviation table |
|
|
property defaults |
|
|
objects |
|
|
object descriptions and properties |
|
|
global variables |
|
|
arrays |
|
Static |
|
grammar table |
|
actions table |
|
|
preactions table |
|
|
adjectives table |
|
|
dictionary |
|
High |
|
Z-code |
|
static strings |
|
|
end of file |
Remarks
Inform never compiles any overlap between static and high memory (it places all data tables in dynamic memory). However, many Infocom games group tables of static data just above the high memory mark, before routines begin; some, such as Nord ‘n’ Bert…, interleave static data between routines, so that static memory actually overlaps code; and a few, such as Seastalker release 15, even contain routines placed below the high memory mark. (The original idea behind the high memory mark was that everything below it should be stored in the interpreter’s RAM, while what was above could reasonably be kept in “virtual memory”, i.e., loaded off disc as needed.)
Note that the total of dynamic plus static memory must not exceed 64K. (In fact, 64K minus 2 bytes.) This is the most serious limitation on the Z-machine.