Importing zdevtools release 20110529 from https://zdevtools.codeplex.com/ minus the...
[zdevtools.git] / za / README
1 It is assumed that the user has a good working knowledge of the Z-machine; this
2 document is not meant as a tutorial, nor is this assembler meant to be useful
3 for anything beyond the testing of interpreters.
4
5 All Z-machine instructions for all Z-machine versions are implemented.  However,
6 there are some major features of the Z-machine that are not currently
7 implemented.  These include (but surely are not limited to) objects, the
8 dictionary, and abbreviations.  There is no direct access to the Unicode table,
9 but if you use UTF-8 characters in a string, they will automatically be added to
10 the Unicode table.
11
12 Diagnostics are generally useful, but might sometimes be cryptic.  If all else
13 fails, look at the source code.  This assembler is quite rough around the edges.
14
15 Source files must be encoded in UTF-8.  If you're only using ASCII, that will be
16 fine.
17
18 In this file, the term "C-style constant" refers to a number as written in C: a
19 leading 0x means the number is hexadecimal, a leading 0 means octal, otherwise,
20 decimal.
21
22 Instruction names are identical to those given in ยง15 of the Z-machine standard.
23 Unlike Inform, instructions are not prefixed with @.
24
25 Comments are introduced with the # character and extend to the end of the line.
26
27 A label is introduced with the "label" directive:
28 label LabelName
29
30 An aligned label (which is the same as calling "align" then "label") has the
31 same syntax:
32 alabel ALabelName
33
34 A routine is introduced with the "routine" directive, and includes the number of
35 locals the routune has (this cannot be omitted even if there are no locals):
36 routune RoutineName 5
37
38 If a version 1-4 story file is being created, initial values can be given to
39 each local variable by listing their values after the number of locals.  The
40 following gives the value 1 to L00, 2 to L01, 3 to L02 and, because values were
41 omitted, L03 and L04 are set to zero:
42 routune RoutineName 5 1 2 3
43
44 An arbitrary byte sequence is introduced with the "byte" directive, each byte
45 specified in hex, separated by space:
46 bytes fa ff fa
47
48 The "align" directive, when given no arguments, forces routine alignment,
49 ensuring that the next instruction is on a 2-, 4-, or 8-byte boundardy,
50 depending on the Z-Machine version (1-3, 4-7, and 8, respectively).  When given
51 a C-style constant as an argument, align to that value instead:
52 align
53 align 0x10
54
55 The "include" directive causes the contents of another file to be included for
56 assemby, analogous to #include in C (recursion is not detected):
57 include anotherfile
58
59 The "seek" directive inserts the specified number of zeroes into the output
60 file; the argument is a C-style constant:
61 seek 0x100
62
63 The "seeknop" directive is identical to "seek", except instead of zeroes, nop
64 instructions are inserted.
65
66 The "status" directive, available only in V3 stories, indicates whether this is
67 a "score game" or a "time game".  The syntax is:
68 status score # or
69 status time
70
71 The "status" directive may be specified at any point in the source file any
72 number of times.  The last takes precedence.  The default game type is a score
73 game.  Although objects are not supported by this assembler, object 1 is created
74 so that interpreters can properly display the status bar.  This object has the
75 name "Default object" and no properties.
76
77 The instructions "print" and "print_ret" take a string as their argument; this
78 should not be enclosed in quotes unless you want to print out quotes.  However,
79 a ^ character does indicate newline as in Inform:
80 print "Try" our hot dog's^Try "our" hot dog's^
81
82 In order to allow strings to start with space, the two printing instructions are
83 tokenized slightly different from other instructions.  Rather than skipping all
84 whicespace after the instruction name, a single space is skipped; and this must
85 be a space character, not a tab.  So these could be thought of as the "print "
86 and "print_ret " instructions, in a sense:
87 print  Foo
88
89 This will print " Foo" because there are two spaces; one to separate the
90 arguments from the instruction name, and then one before the 'F' of "Foo".
91
92 The directive "string " is treated in the same manner.  This directive will
93 directly insert an encoded string, suitable for use with print_paddr.
94
95 The instruction "print_char" cannot be used with literal characters, but instead
96 must be supplied with a ZSCII value:
97 print_char 65
98
99 The "aread" and "sread" opcodes are just called "read" in this assembler.
100
101 If you are in a routine, local variables can be accessed as L00, L01, ... L15.
102 The numbers are decimal.
103
104 Global variables are available in G00, G01, ... Gef.  The numbers are hex.
105
106 The stack pointer is called sp or SP.
107
108 For instructions that require a store, use -> to indicate that:
109 call_1s Routine -> sp
110
111 Literal numbers are stored appropriately, meaning as a small constant for values
112 that fit into 8 bits, a large constant otherwise.  Only values that will fit
113 into a 16-bit integer (signed or unsigned) are allowed, meaning -32768 to 65535.
114 Numbers are parsed as C-style constants.
115
116 The "start" directive must be used once, before any opcodes are used.  Until
117 "start" is seen, the assembler writes to dynamic memory.  Once "start" is
118 encountered, static memory begins, and the starting program counter is set to
119 that address.  The reason for this is chiefly to allow arrays to be placed in
120 dynamic memory:
121 # Combine label and seek to produce arrays.
122 label Array
123 seek 100
124 # Execution will begin here.
125 start
126 storew &Array 0 0x1234
127
128 In V6, the starting point of the story must be a routine, not an instruction.
129 To accomplish this, "start" has a special syntax for V6, which looks identical
130 to the syntax for "routine":
131 start main 0
132
133 This causes a routine called "main" with zero locals to be created, and uses
134 this as the entry point.  These arguments are allowed in non-V6 games, but are
135 ignored.
136
137
138 Labels in the Z-Machine are slightly convoluted.  One might think that a label
139 could be both branched to and called, but this is not exactly the case.  When
140 using a call instruction, the address of the routine is packed, meaning (in V8)
141 that it is divided by 8 and stored in a 16-bit word.  When branching, the
142 address is stored either as a 14-bit signed offset or a 6-bit unsigned offset.
143 And, finally, the @jump instruction takes a 16-bit signed offset.
144
145 Above it was noted that routune labels are produced differently than "normal"
146 labels; this is because routunes start with a byte that specifies the number of
147 local variables, and this byte needs to be jumped past when calling the routine.
148 Branching to a routine label would make no sense, just as calling a normal label
149 would make no sense.
150
151 How to encode a label depends entirely on how it's going to be used: routine
152 call (or print_paddr), branch, or jump.
153
154 The type of a label name could be inferred from how it was defined, but due to a
155 design choice in this assembler, when branching to a label, a prefix is
156 required.  So as not to deviate from Inform's syntax too much, this prefix is a
157 question mark:
158 label Label
159 je 0 0 ?Label
160
161 This will branch to the label Label if 0 is equal to 0.  As with Inform a prefix
162 of ?~ will invert the test.  This stores a 14-bit offset.  By using % instead of
163 ?, an unsigned 6-bit offset can be chosen, which means one fewer byte used in
164 the output.  Of course, this also means that you can only jump about 63 bytes
165 forward.  The assembler will tell you if you're trying to jump too far.
166
167 Branching instructions can, instead of branching when the test passes, return
168 true or false from the current routine.  This can be accomplished with ?1 and
169 ?0, respectively.
170
171 When a packed address is desired (e.g. when you are trying to call a routine),
172 an exclamation point should be used:
173 routine Routine 0
174 quit
175
176 call_1n !Routine
177
178 This syntax should also be used when a packed string is required for use with
179 the print_paddr opcode:
180 print_paddr !String
181 quit
182
183 alabel String
184 string This is a string.
185
186 Note that routine and string offsets (for V6 and V7 games) are not supported, so
187 the packing of strings and routines at the top of memory (beyond 256K) will
188 fail.  This should not be an issue unless you deliberately seek this far before
189 creating a string or routine.
190
191 The actual address of a label can be retrieved with the ampersand prefix.  This
192 means either an unpacked routine, or when used with a label, the absolute
193 address of the label, not an offset.  So to print the address of an instruction:
194 label Label
195 print_num &Label
196
197 Or to use an array (as seen in the "start" directive above):
198 label Array
199 seek 100
200 start
201 storew &Array 0 0x1234
202
203 Note that it is up to you to use the proper prefix with labels.  The assembler
204 will cheerfully let you call a label, or jump to a routine, neither of which
205 makes sense.  So the following assembles, but is nonsensical:
206 label Label
207 call_1n !Label
208 routine Routine 0
209 je 0 0 ?Routine
210
211
212 How should the jump instruction be used, since it is neither a branch nor a
213 routine call?  This instruction is special-cased by pretending that it is a
214 branch instruction.  Before this nefarious lie can cause problems, however, the
215 assembler steps and and writes a proper jump offset.  So:
216 label Label
217 jump ?Label
218
219
220 Here is a full working sample:
221
222 start
223
224 call_1n !main
225 quit
226
227 routine main 0
228 je 0 0 ?Equal
229 print This will not be seen.^
230 label Equal
231
232 jump ?Past
233 print This will not be seen either.^
234 label Past
235
236 print The main routine is: 
237 print_num &main
238 new_line
239 print Packed, the main routine is: 
240 print_num !main
241 new_line
242 print The Equal label is: 
243 print_num &Equal
244 new_line
245
246 quit