I’ve been playing around with a pedagogical Z-Machine emulator and interpreter, which will be heavily commented. As part of this I’m trying to include bits of disassembly from txd to drive a few points home. (I’m posting this in the “Interpreters” category for this reason; maybe that’s wrong.)
A question reared its head as I got started. Here’s an example of the first opcode to be executed in Zork 1:
The specifications category is probably a little better, so I moved it there.
From section 4.1, an instruction can have
Opcode 1 or 2 bytes
(Types of operands) 1 or 2 bytes: 4 or 8 2-bit fields
Operands Between 0 and 8 of these: each 1 or 2 bytes
(Store variable) 1 byte
(Branch offset) 1 or 2 bytes
(Text to print) An encoded string (of unlimited length)
@call (e0) is a VAR form instruction, so the next byte specifies the operands, as in 4.2. 03 is 00 00 00 11: three long (2 byte) operands, with no fourth operand.
For @call, the first operand is a padded address to the routine. 2a39 must be multiplied by 2 to get 5472 or 21618 in decimal.
The next two operands are the arguments to the routine. They could be anything. I’d guess that 8010 is another packed address, maybe to a string, and ffff is probably -1. You’d have to look up the routine to be sure. Considering that the first opcode is conventionally a call to a real routine so that it can have local variables, both of these operands are a bit odd.
The final byte is the storer. The return value of the routine is stored in the stack pointer once it’s completed.
A quick source-dive implies that routine $5472 is called QUEUE in the source. This has to do with daemons. The code starts by setting up daemons for combat, the sword glow, the thief, light source expiration, and so on.
I’m going to be incorporating your comments into the learning documentation for this interpreter. This is exactly the kind of stuff I want to provide as part of helping people understand how everything works and how the interpreter is constructed.
One other thing: any address, variable, etc after a -> in Inform-style assembly indicates the store destination for the instruction. In other words, the instruction produces a result of some sort, and the bit after -> indicates where that result goes.
In this case, the result of the call—that is, its return value—is stored to sp, which means it’s pushed onto the stack. But that doesn’t happen until the call is over and has returned a value.