A look beneath the surface
The Z-machine is a 16-bit virtual machine using big endian addressing. A cpu, memory, and stack make up the bulk of the machine. The cpu has no registers, but instead relies on global variables in memory, routine specific local variables and temporary values on the stack to read and write data.
Memory is divided into dynamic, static, and high regions. Dynamic memory can be written to whereas static memory is read only. High memory is also read only, but can be swapped out of ram and loaded when needed. This allowed Infocom's games to be larger than the memory size of the computers they ran on (which in the mid-80's was typically around 64k or less). Modern interpreters needn't worry about the high memory distinction unless running on a memory constrained platform. By today's standards that would probably mean running on a wristwatch or toaster.
The stack is interesting and I think a source of confusion for people learning the Z-machine. Technically there are two stacks. The first maintains the state of each routine that has been called, such as local variables and the program counter. Calls to routines and returns from routines push/pop frames from this stack. The second stack holds temporary 16-bit values. Various opcodes can push/pop values from this stack. Because a routine is not allowed to pop values off the second stack that an earlier routine placed there, the second stack can be imagined as a bunch of independent stacks, each one belonging to a corresponding frame on the first stack. The basic structure of the stack can be implemented like this:
private Stack<Frame> frames;
private Stack<ushort> localStack;
I'll go over these components in more detail in future posts. Beyond these basic components of the Z-machine, there are smaller but still important pieces, such as the random number generator which I will talk about next time.