ZSAVE is a save file format for Z-machine interpreters. No interpreter is required to support it, although it is recommended if you think Quetzal is too complicated and not very good. This is what the author thought, and why it was invented.
The first byte of the save file is the number of routines on the call stack.
Each call stack entry is then a big-endian 32-bit number, as follows:
cccccccc csaaaaaa aaaaaaaa aaaaaaaa
- c = The count of data stack entries of this routine.
- s = Set if the return value is discarded.
- a = Address of next instruction.
The last entry on the call stack will correspond to the currently executing subroutine, and will therefore correspond to the current instruction pointer. The result of the SAVE instruction (which will be 2) should be written into the save file by the interpreter, so that when it is restored, it can easily continue from there.
After the call stack is the data stack, which consists of 16-bit big-endian numbers. The locals are considered the first entries on the stack, and top of stack is at the end.
A catch token is the zero-based index of the routine which will return from if it is thrown.
(Note: If the return value is not discarded, where to store the result is determined by subtracting 1 from the instruction address and using that as the store code.)
After all data stacks is RAM, starting at address
$38. (Note: Address
is a part of the header, and the intention of this is that the interpreter
may write a username here.)
If the next byte in the file is nonzero, the next byte in the RAM will be the initial contents XORed by the byte in the file.
If the next byte in the file is zero, then the next byte is called X. If bit7 of X is set, then the next byte after that is called Y.
If X has bit7 cleared, then the next
(X+1) bytes of RAM copy the initial
contents of RAM.
If X has bit7 set, then the next
(X+(Y<<7)+1) bytes of RAM copy the
initial contents of RAM.
Once the end of the save file is reached, the rest of the RAM copies the initial contents of the RAM.