Update to commit af5309356bfa197d7a7ea09101c317f94e9b856b
[inform.git] / src / asm.c
1 /* ------------------------------------------------------------------------- */
2 /*   "asm" : The Inform assembler                                            */
3 /*                                                                           */
4 /*   Part of Inform 6.35                                                     */
5 /*   copyright (c) Graham Nelson 1993 - 2021                                 */
6 /*                                                                           */
7 /* Inform is free software: you can redistribute it and/or modify            */
8 /* it under the terms of the GNU General Public License as published by      */
9 /* the Free Software Foundation, either version 3 of the License, or         */
10 /* (at your option) any later version.                                       */
11 /*                                                                           */
12 /* Inform is distributed in the hope that it will be useful,                 */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
15 /* GNU General Public License for more details.                              */
16 /*                                                                           */
17 /* You should have received a copy of the GNU General Public License         */
18 /* along with Inform. If not, see https://gnu.org/licenses/                  */
19 /*                                                                           */
20 /* ------------------------------------------------------------------------- */
21
22 #include "header.h"
23
24 uchar *zcode_holding_area;         /* Area holding code yet to be transferred
25                                       to either zcode_area or temp file no 1 */
26 uchar *zcode_markers;              /* Bytes holding marker values for this
27                                       code                                   */
28 static int zcode_ha_size;          /* Number of bytes in holding area        */
29
30 memory_block zcode_area;           /* Block to hold assembled code (if
31                                       temporary files are not being used)    */
32
33 int32 zmachine_pc;                 /* PC position of assembly (byte offset
34                                       from start of Z-code area)             */
35
36 int32 no_instructions;             /* Number of instructions assembled       */
37 int execution_never_reaches_here,  /* TRUE if the current PC value in the
38                                       code area cannot be reached: e.g. if
39                                       the previous instruction was a "quit"
40                                       opcode and no label is set to here     */
41     next_label,                    /* Used to count the labels created all
42                                       over Inform in current routine, from 0 */
43     next_sequence_point;           /* Likewise, for sequence points          */
44 int no_sequence_points;            /* Kept for statistics purposes only      */
45
46 static int label_moved_error_already_given;
47                                    /* When one label has moved, all subsequent
48                                       ones probably have too, and this flag
49                                       suppresses the runaway chain of error
50                                       messages which would otherwise result  */
51
52 int  sequence_point_follows;       /* Will the next instruction assembled    */
53                                    /* be at a sequence point in the routine? */
54
55 int uses_unicode_features;         /* Makes use of Glulx Unicode (3.0)
56                                       features?                              */
57 int uses_memheap_features;         /* Makes use of Glulx mem/heap (3.1)
58                                       features?                              */
59 int uses_acceleration_features;    /* Makes use of Glulx acceleration (3.1.1)
60                                       features?                              */
61 int uses_float_features;           /* Makes use of Glulx floating-point (3.1.2)
62                                       features?                              */
63
64 debug_location statement_debug_location;
65                                    /* Location of current statement          */
66
67
68 int32 *variable_tokens;            /* The allocated size is 
69                                       (MAX_LOCAL_VARIABLES +
70                                       MAX_GLOBAL_VARIABLES). The entries 
71                                       MAX_LOCAL_VARIABLES and up give the 
72                                       symbol table index for the names of 
73                                       the global variables                   */
74 int *variable_usage;               /* TRUE if referred to, FALSE otherwise   */
75
76 assembly_instruction AI;           /* A structure used to hold the full
77                                       specification of a single Z-code
78                                       instruction: effectively this is the
79                                       input to the routine
80                                       assemble_instruction()                 */
81
82 static char opcode_syntax_string[128];  /*  Text buffer holding the correct
83                                       syntax for an opcode: used to produce
84                                       helpful assembler error messages       */
85
86 static int routine_symbol;         /* The symbol index of the routine currently
87                                       being compiled */
88 static char *routine_name;         /* The name of the routine currently being
89                                       compiled                               */
90 static int routine_locals;         /* The number of local variables used by
91                                       the routine currently being compiled   */
92
93 static int32 routine_start_pc;
94
95 int32 *named_routine_symbols;
96
97 static void transfer_routine_z(void);
98 static void transfer_routine_g(void);
99
100 /* ------------------------------------------------------------------------- */
101 /*   Label data                                                              */
102 /* ------------------------------------------------------------------------- */
103
104 static int first_label, last_label;
105 static int32 *label_offsets;       /* Double-linked list of label offsets    */
106 static int   *label_next,          /* (i.e. zmachine_pc values) in PC order  */
107              *label_prev;
108 static int32 *label_symbols;       /* Symbol numbers if defined in source    */
109
110 static int   *sequence_point_labels;
111                                    /* Label numbers for each                 */
112 static debug_location *sequence_point_locations;
113                                    /* Source code references for each        */
114                                    /* (used for making debugging file)       */
115
116 static void set_label_offset(int label, int32 offset)
117 {
118     if (label >= MAX_LABELS) memoryerror("MAX_LABELS", MAX_LABELS);
119
120     label_offsets[label] = offset;
121     if (last_label == -1)
122     {   label_prev[label] = -1;
123         first_label = label;
124     }
125     else
126     {   label_prev[label] = last_label;
127         label_next[last_label] = label;
128     }
129     last_label = label;
130     label_next[label] = -1;
131     label_symbols[label] = -1;
132 }
133
134 /* ------------------------------------------------------------------------- */
135 /*   Useful tool for building operands                                       */
136 /* ------------------------------------------------------------------------- */
137
138 extern void set_constant_ot(assembly_operand *AO)
139 {
140   if (!glulx_mode) {
141     if (AO->value >= 0 && AO->value <= 255)
142       AO->type = SHORT_CONSTANT_OT;
143     else
144       AO->type = LONG_CONSTANT_OT;
145   }
146   else {
147     if (AO->value == 0)
148       AO->type = ZEROCONSTANT_OT;
149     else if (AO->value >= -0x80 && AO->value < 0x80)
150       AO->type = BYTECONSTANT_OT;
151     else if (AO->value >= -0x8000 && AO->value < 0x8000) 
152       AO->type = HALFCONSTANT_OT;
153     else
154       AO->type = CONSTANT_OT;
155   }
156 }
157
158 extern int is_constant_ot(int otval)
159 {
160   if (!glulx_mode) {
161     return ((otval == LONG_CONSTANT_OT) 
162       || (otval == SHORT_CONSTANT_OT));
163   }
164   else {
165     return ((otval == CONSTANT_OT)
166       || (otval == HALFCONSTANT_OT)
167       || (otval == BYTECONSTANT_OT)
168       || (otval == ZEROCONSTANT_OT));
169   }
170 }
171
172 extern int is_variable_ot(int otval)
173 {
174   if (!glulx_mode) {
175     return (otval == VARIABLE_OT);
176   }
177   else {
178     return ((otval == LOCALVAR_OT)
179       || (otval == GLOBALVAR_OT));
180   }
181 }
182
183 /* ------------------------------------------------------------------------- */
184 /*   Used in printing assembly traces                                        */
185 /* ------------------------------------------------------------------------- */
186
187 extern char *variable_name(int32 i)
188 {
189     if (i==0) return("sp");
190     if (i<MAX_LOCAL_VARIABLES) return local_variable_texts[i-1];
191
192     if (!glulx_mode) {
193       if (i==255) return("TEMP1");
194       if (i==254) return("TEMP2");
195       if (i==253) return("TEMP3");
196       if (i==252) return("TEMP4");
197       if (i==251) return("self");
198       if (i==250) return("sender");
199       if (i==249) return("sw__var");
200       if (i >= 256 && i < 286)
201       {   if (i - 256 < NUMBER_SYSTEM_FUNCTIONS) return system_functions.keywords[i - 256];
202           return "<unnamed system function>";
203       }
204     }
205     else {
206       switch (i - MAX_LOCAL_VARIABLES) {
207       case 0: return "temp_global";
208       case 1: return "temp__global2";
209       case 2: return "temp__global3";
210       case 3: return "temp__global4";
211       case 4: return "self";
212       case 5: return "sender";
213       case 6: return "sw__var";
214       case 7: return "sys__glob0";
215       case 8: return "sys__glob1";
216       case 9: return "sys__glob2";
217       case 10: return "sys_statusline_flag";
218       }
219     }
220
221     return ((char *) symbs[variable_tokens[i]]);
222 }
223
224 static void print_operand_z(assembly_operand o)
225 {   switch(o.type)
226     {   case EXPRESSION_OT: printf("expr_"); break;
227         case LONG_CONSTANT_OT: printf("long_"); break;
228         case SHORT_CONSTANT_OT: printf("short_"); break;
229         case VARIABLE_OT:
230              if (o.value==0) { printf("sp"); return; }
231              printf("%s", variable_name(o.value)); return;
232         case OMITTED_OT: printf("<no value>"); return;
233     }
234     printf("%d", o.value);
235 }
236
237 static void print_operand_g(assembly_operand o)
238 {
239   switch (o.type) {
240   case EXPRESSION_OT: printf("expr_"); break;
241   case CONSTANT_OT: printf("long_"); break;
242   case HALFCONSTANT_OT: printf("short_"); break;
243   case BYTECONSTANT_OT: printf("byte_"); break;
244   case ZEROCONSTANT_OT: printf("zero_"); return;
245   case DEREFERENCE_OT: printf("*"); break;
246   case GLOBALVAR_OT: 
247     printf("%s (global_%d)", variable_name(o.value), o.value); 
248     return;
249   case LOCALVAR_OT: 
250     if (o.value == 0)
251       printf("stackptr"); 
252     else
253       printf("%s (local_%d)", variable_name(o.value), o.value-1); 
254     return;
255   case SYSFUN_OT:
256     if (o.value >= 0 && o.value < NUMBER_SYSTEM_FUNCTIONS)
257       printf("%s", system_functions.keywords[o.value]);
258     else
259       printf("<unnamed system function>");
260     return;
261   case OMITTED_OT: printf("<no value>"); return;
262   default: printf("???_"); break; 
263   }
264   printf("%d", o.value);
265 }
266
267 extern void print_operand(assembly_operand o)
268 {
269   if (!glulx_mode)
270     print_operand_z(o);
271   else
272     print_operand_g(o);
273 }
274
275 /* ------------------------------------------------------------------------- */
276 /*   Writing bytes to the code area                                          */
277 /* ------------------------------------------------------------------------- */
278
279 static void byteout(int32 i, int mv)
280 {   if (zcode_ha_size >= MAX_ZCODE_SIZE)
281         memoryerror("MAX_ZCODE_SIZE",MAX_ZCODE_SIZE);
282     zcode_markers[zcode_ha_size] = (uchar) mv;
283     zcode_holding_area[zcode_ha_size++] = (uchar) i;
284     zmachine_pc++;
285 }
286
287 /* ------------------------------------------------------------------------- */
288 /*   A database of the 115 canonical Infocom opcodes in Versions 3 to 6      */
289 /*   And of the however-many-there-are Glulx opcode                          */
290 /* ------------------------------------------------------------------------- */
291
292 typedef struct opcodez
293 {   uchar *name;      /* Lower case standard name */
294     int version1;     /* Valid from this version number... */
295     int version2;     /* ...until this one (or forever if this is 0) */
296     int extension;    /* In later versions, see this line in extension table:
297                          if -1, the opcode is illegal in later versions */
298     int code;         /* Opcode number within its operand-number block */
299     int flags;        /* Flags (see below) */
300     int op_rules;     /* Any unusual operand rule applying (see below) */
301     int flags2_set;   /* If not zero, set this bit in Flags 2 in the header
302                          of any game using the opcode */
303     int no;           /* Number of operands (see below) */
304 } opcodez;
305
306 typedef struct opcodeg
307 {   uchar *name;      /* Lower case standard name */
308     int32 code;       /* Opcode number */
309     int flags;        /* Flags (see below) */
310     int op_rules;     /* Any unusual operand rule applying (see below) */
311     int no;           /* Number of operands */
312 } opcodeg;
313
314     /* Flags which can be set */
315
316 #define St      1     /* Store */
317 #define Br      2     /* Branch */
318 #define Rf      4     /* "Return flag": execution never continues after this
319                          opcode (e.g., is a return or unconditional jump) */
320 #define St2 8     /* Store2 (second-to-last operand is store (Glulx)) */
321
322     /* Codes for any unusual operand assembly rules */
323
324     /* Z-code: */
325
326 #define VARIAB   1    /* First operand expected to be a variable name and
327                          assembled to a short constant: the variable number */
328 #define TEXT     2    /* One text operand, to be Z-encoded into the program */
329 #define LABEL    3    /* One operand, a label, given as long constant offset */
330 #define CALL     4    /* First operand is name of a routine, to be assembled
331                          as long constant (the routine's packed address):
332                          as if the name were prefixed by #r$ */
333
334     /* Glulx: (bit flags for Glulx VM features) */
335
336 #define GOP_Unicode      1   /* uses_unicode_features */
337 #define GOP_MemHeap      2   /* uses_memheap_features */
338 #define GOP_Acceleration 4   /* uses_acceleration_features */
339 #define GOP_Float        8   /* uses_float_features */
340
341     /* Codes for the number of operands */
342
343 #define TWO      1    /* 2 (with certain types of operand, compiled as VAR) */
344 #define VAR      2    /* 0 to 4 */
345 #define VAR_LONG 3    /* 0 to 8 */
346 #define ONE      4    /* 1 */
347 #define ZERO     5    /* 0 */
348 #define EXT      6    /* Extended opcode set VAR: 0 to 4 */
349 #define EXT_LONG 7    /* Extended: 0 to 8 (not used by the canonical opcodes) */
350
351 static opcodez opcodes_table_z[] =
352 {
353     /* Opcodes introduced in Version 3 */
354
355 /* 0 */ { (uchar *) "je",              3, 0, -1, 0x01,     Br,      0, 0, TWO },
356 /* 1 */ { (uchar *) "jl",              3, 0, -1, 0x02,     Br,      0, 0, TWO },
357 /* 2 */ { (uchar *) "jg",              3, 0, -1, 0x03,     Br,      0, 0, TWO },
358 /* 3 */ { (uchar *) "dec_chk",         3, 0, -1, 0x04,     Br, VARIAB, 0, TWO },
359 /* 4 */ { (uchar *) "inc_chk",         3, 0, -1, 0x05,     Br, VARIAB, 0, TWO },
360 /* 5 */ { (uchar *) "jin",             3, 0, -1, 0x06,     Br,      0, 0, TWO },
361 /* 6 */ { (uchar *) "test",            3, 0, -1, 0x07,     Br,      0, 0, TWO },
362 /* 7 */ { (uchar *) "or",              3, 0, -1, 0x08,     St,      0, 0, TWO },
363 /* 8 */ { (uchar *) "and",             3, 0, -1, 0x09,     St,      0, 0, TWO },
364 /* 9 */ { (uchar *) "test_attr",       3, 0, -1, 0x0A,     Br,      0, 0, TWO },
365 /* 10 */ {(uchar *) "set_attr",        3, 0, -1, 0x0B,      0,      0, 0, TWO },
366 /* 11 */ {(uchar *) "clear_attr",      3, 0, -1, 0x0C,      0,      0, 0, TWO },
367 /* 12 */ {(uchar *) "store",           3, 0, -1, 0x0D,      0, VARIAB, 0, TWO },
368 /* 13 */ {(uchar *) "insert_obj",      3, 0, -1, 0x0E,      0,      0, 0, TWO },
369 /* 14 */ {(uchar *) "loadw",           3, 0, -1, 0x0F,     St,      0, 0, TWO },
370 /* 15 */ {(uchar *) "loadb",           3, 0, -1, 0x10,     St,      0, 0, TWO },
371 /* 16 */ {(uchar *) "get_prop",        3, 0, -1, 0x11,     St,      0, 0, TWO },
372 /* 17 */ {(uchar *) "get_prop_addr",   3, 0, -1, 0x12,     St,      0, 0, TWO },
373 /* 18 */ {(uchar *) "get_next_prop",   3, 0, -1, 0x13,     St,      0, 0, TWO },
374 /* 19 */ {(uchar *) "add",             3, 0, -1, 0x14,     St,      0, 0, TWO },
375 /* 20 */ {(uchar *) "sub",             3, 0, -1, 0x15,     St,      0, 0, TWO },
376 /* 21 */ {(uchar *) "mul",             3, 0, -1, 0x16,     St,      0, 0, TWO },
377 /* 22 */ {(uchar *) "div",             3, 0, -1, 0x17,     St,      0, 0, TWO },
378 /* 23 */ {(uchar *) "mod",             3, 0, -1, 0x18,     St,      0, 0, TWO },
379 /* 24 */ {(uchar *) "call",            3, 0, -1, 0x20,     St,   CALL, 0, VAR },
380 /* 25 */ {(uchar *) "storew",          3, 0, -1, 0x21,      0,      0, 0, VAR },
381 /* 26 */ {(uchar *) "storeb",          3, 0, -1, 0x22,      0,      0, 0, VAR },
382 /* 27 */ {(uchar *) "put_prop",        3, 0, -1, 0x23,      0,      0, 0, VAR },
383             /* This is the version of "read" called "sread" internally: */
384 /* 28 */ {(uchar *) "read",            3, 0, -1, 0x24,      0,      0, 0, VAR },
385 /* 29 */ {(uchar *) "print_char",      3, 0, -1, 0x25,      0,      0, 0, VAR },
386 /* 30 */ {(uchar *) "print_num",       3, 0, -1, 0x26,      0,      0, 0, VAR },
387 /* 31 */ {(uchar *) "random",          3, 0, -1, 0x27,     St,      0, 0, VAR },
388 /* 32 */ {(uchar *) "push",            3, 0, -1, 0x28,      0,      0, 0, VAR },
389 /* 33 */ {(uchar *) "pull",            3, 5,  6, 0x29,      0, VARIAB, 0, VAR },
390 /* 34 */ {(uchar *) "split_window",    3, 0, -1, 0x2A,      0,      0, 0, VAR },
391 /* 35 */ {(uchar *) "set_window",      3, 0, -1, 0x2B,      0,      0, 0, VAR },
392 /* 36 */ {(uchar *) "output_stream",   3, 0, -1, 0x33,      0,      0, 0, VAR },
393 /* 37 */ {(uchar *) "input_stream",    3, 0, -1, 0x34,      0,      0, 0, VAR },
394 /* 38 */ {(uchar *) "sound_effect",    3, 0, -1, 0x35,      0,      0, 7, VAR },
395 /* 39 */ {(uchar *) "jz",              3, 0, -1, 0x00,     Br,      0, 0, ONE },
396 /* 40 */ {(uchar *) "get_sibling",     3, 0, -1, 0x01,  St+Br,      0, 0, ONE },
397 /* 41 */ {(uchar *) "get_child",       3, 0, -1, 0x02,  St+Br,      0, 0, ONE },
398 /* 42 */ {(uchar *) "get_parent",      3, 0, -1, 0x03,     St,      0, 0, ONE },
399 /* 43 */ {(uchar *) "get_prop_len",    3, 0, -1, 0x04,     St,      0, 0, ONE },
400 /* 44 */ {(uchar *) "inc",             3, 0, -1, 0x05,      0, VARIAB, 0, ONE },
401 /* 45 */ {(uchar *) "dec",             3, 0, -1, 0x06,      0, VARIAB, 0, ONE },
402 /* 46 */ {(uchar *) "print_addr",      3, 0, -1, 0x07,      0,      0, 0, ONE },
403 /* 47 */ {(uchar *) "remove_obj",      3, 0, -1, 0x09,      0,      0, 0, ONE },
404 /* 48 */ {(uchar *) "print_obj",       3, 0, -1, 0x0A,      0,      0, 0, ONE },
405 /* 49 */ {(uchar *) "ret",             3, 0, -1, 0x0B,     Rf,      0, 0, ONE },
406 /* 50 */ {(uchar *) "jump",            3, 0, -1, 0x0C,     Rf,  LABEL, 0, ONE },
407 /* 51 */ {(uchar *) "print_paddr",     3, 0, -1, 0x0D,      0,      0, 0, ONE },
408 /* 52 */ {(uchar *) "load",            3, 0, -1, 0x0E,     St, VARIAB, 0, ONE },
409 /* 53 */ {(uchar *) "not",             3, 3,  0, 0x0F,     St,      0, 0, ONE },
410 /* 54 */ {(uchar *) "rtrue",           3, 0, -1, 0x00,     Rf,      0, 0,ZERO },
411 /* 55 */ {(uchar *) "rfalse",          3, 0, -1, 0x01,     Rf,      0, 0,ZERO },
412 /* 56 */ {(uchar *) "print",           3, 0, -1, 0x02,      0,   TEXT, 0,ZERO },
413 /* 57 */ {(uchar *) "print_ret",       3, 0, -1, 0x03,     Rf,   TEXT, 0,ZERO },
414 /* 58 */ {(uchar *) "nop",             3, 0, -1, 0x04,      0,      0, 0,ZERO },
415 /* 59 */ {(uchar *) "save",            3, 3,  1, 0x05,     Br,      0, 0,ZERO },
416 /* 60 */ {(uchar *) "restore",         3, 3,  2, 0x06,     Br,      0, 0,ZERO },
417 /* 61 */ {(uchar *) "restart",         3, 0, -1, 0x07,      0,      0, 0,ZERO },
418 /* 62 */ {(uchar *) "ret_popped",      3, 0, -1, 0x08,     Rf,      0, 0,ZERO },
419 /* 63 */ {(uchar *) "pop",             3, 4, -1, 0x09,      0,      0, 0,ZERO },
420 /* 64 */ {(uchar *) "quit",            3, 0, -1, 0x0A,     Rf,      0, 0,ZERO },
421 /* 65 */ {(uchar *) "new_line",        3, 0, -1, 0x0B,      0,      0, 0,ZERO },
422 /* 66 */ {(uchar *) "show_status",     3, 3, -1, 0x0C,      0,      0, 0,ZERO },
423 /* 67 */ {(uchar *) "verify",          3, 0, -1, 0x0D,     Br,      0, 0,ZERO },
424
425     /* Opcodes introduced in Version 4 */
426
427 /* 68 */ {(uchar *) "call_2s",         4, 0, -1, 0x19,     St,   CALL, 0, TWO },
428 /* 69 */ {(uchar *) "call_vs",         4, 0, -1, 0x20,     St,   CALL, 0, VAR },
429             /* This is the version of "read" called "aread" internally: */
430 /* 70 */ {(uchar *) "read",            4, 0, -1, 0x24,     St,      0, 0, VAR },
431 /* 71 */ {(uchar *) "call_vs2",        4, 0, -1, 0x2C,     St,   CALL, 0,
432                                                                      VAR_LONG },
433 /* 72 */ {(uchar *) "erase_window",    4, 0, -1, 0x2D,      0,      0, 0, VAR },
434 /* 73 */ {(uchar *) "erase_line",      4, 0, -1, 0x2E,      0,      0, 0, VAR },
435 /* 74 */ {(uchar *) "set_cursor",      4, 0, -1, 0x2F,      0,      0, 0, VAR },
436 /* 75 */ {(uchar *) "get_cursor",      4, 0, -1, 0x30,      0,      0, 0, VAR },
437 /* 76 */ {(uchar *) "set_text_style",  4, 0, -1, 0x31,      0,      0, 0, VAR },
438 /* 77 */ {(uchar *) "buffer_mode",     4, 0, -1, 0x32,      0,      0, 0, VAR },
439 /* 78 */ {(uchar *) "read_char",       4, 0, -1, 0x36,     St,      0, 0, VAR },
440 /* 79 */ {(uchar *) "scan_table",      4, 0, -1, 0x37,  St+Br,      0, 0, VAR },
441 /* 80 */ {(uchar *) "call_1s",         4, 0, -1, 0x08,     St,   CALL, 0, ONE },
442
443     /* Opcodes introduced in Version 5 */
444
445 /* 81 */ {(uchar *) "call_2n",         5, 0, -1, 0x1a,      0,   CALL, 0, TWO },
446 /* 82 */ {(uchar *) "set_colour",      5, 0, -1, 0x1b,      0,      0, 6, TWO },
447 /* 83 */ {(uchar *) "throw",           5, 0, -1, 0x1c,      0,      0, 0, TWO },
448 /* 84 */ {(uchar *) "call_vn",         5, 0, -1, 0x39,      0,   CALL, 0, VAR },
449 /* 85 */ {(uchar *) "call_vn2",        5, 0, -1, 0x3a,      0,   CALL, 0,
450                                                                      VAR_LONG },
451 /* 86 */ {(uchar *) "tokenise",        5, 0, -1, 0x3b,      0,      0, 0, VAR },
452 /* 87 */ {(uchar *) "encode_text",     5, 0, -1, 0x3c,      0,      0, 0, VAR },
453 /* 88 */ {(uchar *) "copy_table",      5, 0, -1, 0x3d,      0,      0, 0, VAR },
454 /* 89 */ {(uchar *) "print_table",     5, 0, -1, 0x3e,      0,      0, 0, VAR },
455 /* 90 */ {(uchar *) "check_arg_count", 5, 0, -1, 0x3f,     Br,      0, 0, VAR },
456 /* 91 */ {(uchar *) "call_1n",         5, 0, -1, 0x0F,      0,   CALL, 0, ONE },
457 /* 92 */ {(uchar *) "catch",           5, 0, -1, 0x09,     St,      0, 0, ZERO },
458 /* 93 */ {(uchar *) "piracy",          5, 0, -1, 0x0F,     Br,      0, 0, ZERO },
459 /* 94 */ {(uchar *) "log_shift",       5, 0, -1, 0x02,     St,      0, 0, EXT },
460 /* 95 */ {(uchar *) "art_shift",       5, 0, -1, 0x03,     St,      0, 0, EXT },
461 /* 96 */ {(uchar *) "set_font",        5, 0, -1, 0x04,     St,      0, 0, EXT },
462 /* 97 */ {(uchar *) "save_undo",       5, 0, -1, 0x09,     St,      0, 4, EXT },
463 /* 98 */ {(uchar *) "restore_undo",    5, 0, -1, 0x0A,     St,      0, 4, EXT },
464
465     /* Opcodes introduced in Version 6 */
466
467 /* 99 */  { (uchar *) "draw_picture",  6, 6, -1, 0x05,      0,      0, 3, EXT },
468 /* 100 */ { (uchar *) "picture_data",  6, 6, -1, 0x06,     Br,      0, 3, EXT },
469 /* 101 */ { (uchar *) "erase_picture", 6, 6, -1, 0x07,      0,      0, 3, EXT },
470 /* 102 */ { (uchar *) "set_margins",   6, 6, -1, 0x08,      0,      0, 0, EXT },
471 /* 103 */ { (uchar *) "move_window",   6, 6, -1, 0x10,      0,      0, 0, EXT },
472 /* 104 */ { (uchar *) "window_size",   6, 6, -1, 0x11,      0,      0, 0, EXT },
473 /* 105 */ { (uchar *) "window_style",  6, 6, -1, 0x12,      0,      0, 0, EXT },
474 /* 106 */ { (uchar *) "get_wind_prop", 6, 6, -1, 0x13,     St,      0, 0, EXT },
475 /* 107 */ { (uchar *) "scroll_window", 6, 6, -1, 0x14,      0,      0, 0, EXT },
476 /* 108 */ { (uchar *) "pop_stack",     6, 6, -1, 0x15,      0,      0, 0, EXT },
477 /* 109 */ { (uchar *) "read_mouse",    6, 6, -1, 0x16,      0,      0, 5, EXT },
478 /* 110 */ { (uchar *) "mouse_window",  6, 6, -1, 0x17,      0,      0, 5, EXT },
479 /* 111 */ { (uchar *) "push_stack",    6, 6, -1, 0x18,     Br,      0, 0, EXT },
480 /* 112 */ { (uchar *) "put_wind_prop", 6, 6, -1, 0x19,      0,      0, 0, EXT },
481 /* 113 */ { (uchar *) "print_form",    6, 6, -1, 0x1a,      0,      0, 0, EXT },
482 /* 114 */ { (uchar *) "make_menu",     6, 6, -1, 0x1b,     Br,      0, 8, EXT },
483 /* 115 */ { (uchar *) "picture_table", 6, 6, -1, 0x1c,      0,      0, 3, EXT },
484
485     /* Opcodes introduced in Z-Machine Specification Standard 1.0 */
486
487 /* 116 */ { (uchar *) "print_unicode", 5, 0, -1, 0x0b,      0,      0, 0, EXT },
488 /* 117 */ { (uchar *) "check_unicode", 5, 0, -1, 0x0c,     St,      0, 0, EXT }
489 };
490
491     /* Subsequent forms for opcodes whose meaning changes with version */
492
493 static opcodez extension_table_z[] =
494 {
495 /* 0 */ { (uchar *) "not",             4, 4,  3, 0x0F,     St,      0, 0, ONE },
496 /* 1 */ { (uchar *) "save",            4, 4,  4, 0x05,     St,      0, 0,ZERO },
497 /* 2 */ { (uchar *) "restore",         4, 4,  5, 0x06,     St,      0, 0,ZERO },
498 /* 3 */ { (uchar *) "not",             5, 0, -1, 0x38,     St,      0, 0, VAR },
499 /* 4 */ { (uchar *) "save",            5, 0, -1, 0x00,     St,      0, 0, EXT },
500 /* 5 */ { (uchar *) "restore",         5, 0, -1, 0x01,     St,      0, 0, EXT },
501 /* 6 */ { (uchar *) "pull",            6, 6, -1, 0x29,     St,      0, 0, VAR }
502 };
503
504 static opcodez invalid_opcode_z =
505         { (uchar *) "invalid",         0, 0, -1, 0xff,      0,      0, 0, ZERO};
506
507 static opcodez custom_opcode_z;
508
509 /* Note that this table assumes that all opcodes have at most two 
510    branch-label or store operands, and that if they exist, they are the
511    last operands. Glulx does not actually guarantee this. But it is
512    true for all opcodes in the current Glulx spec, so we will assume
513    it for now.
514
515    Also note that Inform can only compile branches to constant offsets,
516    even though the Glulx machine can handle stack or memory-loaded
517    operands in a branch instruction.
518 */
519
520 static opcodeg opcodes_table_g[] = {
521   { (uchar *) "nop",        0x00,  0, 0, 0 },
522   { (uchar *) "add",        0x10, St, 0, 3 },
523   { (uchar *) "sub",        0x11, St, 0, 3 },
524   { (uchar *) "mul",        0x12, St, 0, 3 },
525   { (uchar *) "div",        0x13, St, 0, 3 },
526   { (uchar *) "mod",        0x14, St, 0, 3 },
527   { (uchar *) "neg",        0x15, St, 0, 2 },
528   { (uchar *) "bitand",     0x18, St, 0, 3 },
529   { (uchar *) "bitor",      0x19, St, 0, 3 },
530   { (uchar *) "bitxor",     0x1A, St, 0, 3 },
531   { (uchar *) "bitnot",     0x1B, St, 0, 2 },
532   { (uchar *) "shiftl",     0x1C, St, 0, 3 },
533   { (uchar *) "sshiftr",    0x1D, St, 0, 3 },
534   { (uchar *) "ushiftr",    0x1E, St, 0, 3 },
535   { (uchar *) "jump",       0x20, Br|Rf, 0, 1 },
536   { (uchar *) "jz",     0x22, Br, 0, 2 },
537   { (uchar *) "jnz",        0x23, Br, 0, 2 },
538   { (uchar *) "jeq",        0x24, Br, 0, 3 },
539   { (uchar *) "jne",        0x25, Br, 0, 3 },
540   { (uchar *) "jlt",        0x26, Br, 0, 3 },
541   { (uchar *) "jge",        0x27, Br, 0, 3 },
542   { (uchar *) "jgt",        0x28, Br, 0, 3 },
543   { (uchar *) "jle",        0x29, Br, 0, 3 },
544   { (uchar *) "jltu",       0x2A, Br, 0, 3 },
545   { (uchar *) "jgeu",       0x2B, Br, 0, 3 },
546   { (uchar *) "jgtu",       0x2C, Br, 0, 3 },
547   { (uchar *) "jleu",       0x2D, Br, 0, 3 },
548   { (uchar *) "call",       0x30, St, 0, 3 },
549   { (uchar *) "return",     0x31, Rf, 0, 1 },
550   { (uchar *) "catch",      0x32, Br|St, 0, 2 },
551   { (uchar *) "throw",      0x33, Rf, 0, 2 },
552   { (uchar *) "tailcall",   0x34, Rf, 0, 2 },
553   { (uchar *) "copy",       0x40, St, 0, 2 },
554   { (uchar *) "copys",      0x41, St, 0, 2 },
555   { (uchar *) "copyb",      0x42, St, 0, 2 },
556   { (uchar *) "sexs",       0x44, St, 0, 2 },
557   { (uchar *) "sexb",       0x45, St, 0, 2 },
558   { (uchar *) "aload",      0x48, St, 0, 3 },
559   { (uchar *) "aloads",     0x49, St, 0, 3 },
560   { (uchar *) "aloadb",     0x4A, St, 0, 3 },
561   { (uchar *) "aloadbit",   0x4B, St, 0, 3 },
562   { (uchar *) "astore",     0x4C,  0, 0, 3 },
563   { (uchar *) "astores",    0x4D,  0, 0, 3 },
564   { (uchar *) "astoreb",    0x4E,  0, 0, 3 },
565   { (uchar *) "astorebit",  0x4F,  0, 0, 3 },
566   { (uchar *) "stkcount",   0x50, St, 0, 1 },
567   { (uchar *) "stkpeek",    0x51, St, 0, 2 },
568   { (uchar *) "stkswap",    0x52,  0, 0, 0 },
569   { (uchar *) "stkroll",    0x53,  0, 0, 2 },
570   { (uchar *) "stkcopy",    0x54,  0, 0, 1 },
571   { (uchar *) "streamchar", 0x70,  0, 0, 1 },
572   { (uchar *) "streamnum",  0x71,  0, 0, 1 },
573   { (uchar *) "streamstr",  0x72,  0, 0, 1 },
574   { (uchar *) "gestalt",    0x0100, St, 0, 3 },
575   { (uchar *) "debugtrap",  0x0101, 0, 0, 1 },
576   { (uchar *) "getmemsize",     0x0102, St, 0, 1 },
577   { (uchar *) "setmemsize",     0x0103, St, 0, 2 },
578   { (uchar *) "jumpabs",    0x0104, Rf, 0, 1 },
579   { (uchar *) "random",     0x0110, St, 0, 2 },
580   { (uchar *) "setrandom",  0x0111,  0, 0, 1 },
581   { (uchar *) "quit",       0x0120, Rf, 0, 0 },
582   { (uchar *) "verify",     0x0121, St, 0, 1 },
583   { (uchar *) "restart",    0x0122,  0, 0, 0 },
584   { (uchar *) "save",       0x0123, St, 0, 2 },
585   { (uchar *) "restore",    0x0124, St, 0, 2 },
586   { (uchar *) "saveundo",   0x0125, St, 0, 1 },
587   { (uchar *) "restoreundo",    0x0126, St, 0, 1 },
588   { (uchar *) "protect",    0x0127,  0, 0, 2 },
589   { (uchar *) "glk",        0x0130, St, 0, 3 },
590   { (uchar *) "getstringtbl",   0x0140, St, 0, 1 },
591   { (uchar *) "setstringtbl",   0x0141, 0, 0, 1 },
592   { (uchar *) "getiosys",   0x0148, St|St2, 0, 2 },
593   { (uchar *) "setiosys",   0x0149, 0, 0, 2 },
594   { (uchar *) "linearsearch",   0x0150, St, 0, 8 },
595   { (uchar *) "binarysearch",   0x0151, St, 0, 8 },
596   { (uchar *) "linkedsearch",   0x0152, St, 0, 7 },
597   { (uchar *) "callf",      0x0160, St, 0, 2 },
598   { (uchar *) "callfi",     0x0161, St, 0, 3 },
599   { (uchar *) "callfii",    0x0162, St, 0, 4 },
600   { (uchar *) "callfiii",   0x0163, St, 0, 5 },
601   { (uchar *) "streamunichar", 0x73,  0, GOP_Unicode, 1 },
602   { (uchar *) "mzero",      0x170,  0, GOP_MemHeap, 2 },
603   { (uchar *) "mcopy",      0x171,  0, GOP_MemHeap, 3 },
604   { (uchar *) "malloc",     0x178,  St, GOP_MemHeap, 2 },
605   { (uchar *) "mfree",      0x179,  0, GOP_MemHeap, 1 },
606   { (uchar *) "accelfunc",  0x180,  0, GOP_Acceleration, 2 },
607   { (uchar *) "accelparam", 0x181,  0, GOP_Acceleration, 2 },
608   { (uchar *) "numtof",     0x190,  St, GOP_Float, 2 },
609   { (uchar *) "ftonumz",    0x191,  St, GOP_Float, 2 },
610   { (uchar *) "ftonumn",    0x192,  St, GOP_Float, 2 },
611   { (uchar *) "ceil",       0x198,  St, GOP_Float, 2 },
612   { (uchar *) "floor",      0x199,  St, GOP_Float, 2 },
613   { (uchar *) "fadd",       0x1A0,  St, GOP_Float, 3 },
614   { (uchar *) "fsub",       0x1A1,  St, GOP_Float, 3 },
615   { (uchar *) "fmul",       0x1A2,  St, GOP_Float, 3 },
616   { (uchar *) "fdiv",       0x1A3,  St, GOP_Float, 3 },
617   { (uchar *) "fmod",       0x1A4,  St|St2, GOP_Float, 4 },
618   { (uchar *) "sqrt",       0x1A8,  St, GOP_Float, 2 },
619   { (uchar *) "exp",        0x1A9,  St, GOP_Float, 2 },
620   { (uchar *) "log",        0x1AA,  St, GOP_Float, 2 },
621   { (uchar *) "pow",        0x1AB,  St, GOP_Float, 3 },
622   { (uchar *) "sin",        0x1B0,  St, GOP_Float, 2 },
623   { (uchar *) "cos",        0x1B1,  St, GOP_Float, 2 },
624   { (uchar *) "tan",        0x1B2,  St, GOP_Float, 2 },
625   { (uchar *) "asin",       0x1B3,  St, GOP_Float, 2 },
626   { (uchar *) "acos",       0x1B4,  St, GOP_Float, 2 },
627   { (uchar *) "atan",       0x1B5,  St, GOP_Float, 2 },
628   { (uchar *) "atan2",      0x1B6,  St, GOP_Float, 3 },
629   { (uchar *) "jfeq",       0x1C0,  Br, GOP_Float, 4 },
630   { (uchar *) "jfne",       0x1C1,  Br, GOP_Float, 4 },
631   { (uchar *) "jflt",       0x1C2,  Br, GOP_Float, 3 },
632   { (uchar *) "jfle",       0x1C3,  Br, GOP_Float, 3 },
633   { (uchar *) "jfgt",       0x1C4,  Br, GOP_Float, 3 },
634   { (uchar *) "jfge",       0x1C5,  Br, GOP_Float, 3 },
635   { (uchar *) "jisnan",     0x1C8,  Br, GOP_Float, 2 },
636   { (uchar *) "jisinf",     0x1C9,  Br, GOP_Float, 2 },
637 };
638
639 /* The opmacros table is used for fake opcodes. The opcode numbers are
640    ignored; this table is only used for argument parsing. */
641 static opcodeg opmacros_table_g[] = {
642   { (uchar *) "pull", 0, St, 0, 1 },
643   { (uchar *) "push", 0,  0, 0, 1 },
644 };
645
646 static opcodeg custom_opcode_g;
647
648 static opcodez internal_number_to_opcode_z(int32 i)
649 {   opcodez x;
650     ASSERT_ZCODE();
651     if (i == -1) return custom_opcode_z;
652     x = opcodes_table_z[i];
653     if (instruction_set_number < x.version1) return invalid_opcode_z;
654     if (x.version2 == 0) return x;
655     if (instruction_set_number <= x.version2) return x;
656     i = x.extension;
657     if (i < 0) return invalid_opcode_z;
658     x = extension_table_z[i];
659     if (instruction_set_number < x.version1) return invalid_opcode_z;
660     if (x.version2 == 0) return x;
661     if (instruction_set_number <= x.version2) return x;
662     return extension_table_z[x.extension];
663 }
664
665 static void make_opcode_syntax_z(opcodez opco)
666 {   char *p = "", *q = opcode_syntax_string;
667     sprintf(q, "%s", opco.name);
668     switch(opco.no)
669     {   case ONE: p=" <operand>"; break;
670         case TWO: p=" <operand1> <operand2>"; break;
671         case EXT:
672         case VAR: p=" <0 to 4 operands>"; break;
673         case VAR_LONG: p=" <0 to 8 operands>"; break;
674     }
675     switch(opco.op_rules)
676     {   case TEXT: sprintf(q+strlen(q), " <text>"); return;
677         case LABEL: sprintf(q+strlen(q), " <label>"); return;
678         case VARIAB:
679             sprintf(q+strlen(q), " <variable>");
680         case CALL:
681             if (opco.op_rules==CALL) sprintf(q+strlen(q), " <routine>");
682             switch(opco.no)
683             {   case ONE: p=""; break;
684                 case TWO: p=" <operand>"; break;
685                 case EXT:
686                 case VAR: p=" <1 to 4 operands>"; break;
687                 case VAR_LONG: p=" <1 to 8 operands>"; break;
688             }
689             break;
690     }
691     sprintf(q+strlen(q), "%s", p);
692     if ((opco.flags & St) != 0) sprintf(q+strlen(q), " -> <result-variable>");
693     if ((opco.flags & Br) != 0) sprintf(q+strlen(q), " ?[~]<label>");
694 }
695
696 static opcodeg internal_number_to_opcode_g(int32 i)
697 {   
698     opcodeg x;
699     if (i == -1) return custom_opcode_g;
700     x = opcodes_table_g[i];
701     return x;
702 }
703
704 static opcodeg internal_number_to_opmacro_g(int32 i)
705 {
706     return opmacros_table_g[i];
707 }
708
709 static void make_opcode_syntax_g(opcodeg opco)
710 {
711     int ix;
712     char *cx;
713     char *q = opcode_syntax_string;
714
715     sprintf(q, "%s", opco.name);
716     sprintf(q+strlen(q), " <%d operand%s", opco.no,
717         ((opco.no==1) ? "" : "s"));
718     if (opco.no) {
719         cx = q+strlen(q);
720         strcpy(cx, ": ");
721         cx += strlen(cx);
722         for (ix=0; ix<opco.no; ix++) {
723             if (ix) {
724                 *cx = ' ';
725                 cx++;
726             }
727             if (ix == opco.no-1) {
728                 if (opco.flags & Br) {
729                     strcpy(cx, "Lb");
730                 }
731                 else if (opco.flags & St) {
732                     strcpy(cx, "S");
733                 }
734                 else {
735                     strcpy(cx, "L");
736                 }
737             }
738             else if (ix == opco.no-2 && (opco.flags & Br) && (opco.flags & St)) {
739                 strcpy(cx, "S");
740             }
741             else if (ix == opco.no-2 && (opco.flags & St2)) {
742                 strcpy(cx, "S");
743             }
744             else {
745                 strcpy(cx, "L");
746             }
747             cx += strlen(cx);
748             sprintf(cx, "%d", ix+1);
749             cx += strlen(cx);
750         }
751     }
752     sprintf(q+strlen(q), ">");
753 }
754
755
756 /* ========================================================================= */
757 /*   The assembler itself does four things:                                  */
758 /*                                                                           */
759 /*       assembles instructions                                              */
760 /*       sets label N to the current code position                           */
761 /*       assembles routine headers                                           */
762 /*       assembles routine ends                                              */
763 /* ------------------------------------------------------------------------- */
764
765 /* This is for Z-code only. */
766 static void write_operand(assembly_operand op)
767 {   int32 j;
768     if (module_switch && (op.marker != 0))
769     {   if ((op.marker != VARIABLE_MV) && (op.type == SHORT_CONSTANT_OT))
770             op.type = LONG_CONSTANT_OT;
771     }
772     j=op.value;
773     switch(op.type)
774     {   case LONG_CONSTANT_OT:
775             byteout(j/256, op.marker); byteout(j%256, 0); return;
776         case SHORT_CONSTANT_OT:
777             if (op.marker == 0)
778             byteout(j, 0);
779             else byteout(j, 0x80 + op.marker); return;
780         case VARIABLE_OT:
781             byteout(j, (module_switch)?(0x80 + op.marker):0); return;
782         case CONSTANT_OT:
783         case HALFCONSTANT_OT:
784         case BYTECONSTANT_OT:
785         case ZEROCONSTANT_OT:
786         case SYSFUN_OT:
787         case DEREFERENCE_OT:
788         case LOCALVAR_OT:
789         case GLOBALVAR_OT:
790             compiler_error("Glulx OT in Z-code assembly operand.");
791             return;
792     }
793 }
794
795 extern void assemblez_instruction(assembly_instruction *AI)
796 {
797     uchar *start_pc, *operands_pc;
798     int32 offset, j, topbits=0, types_byte1, types_byte2;
799     int operand_rules, min=0, max=0, no_operands_given, at_seq_point = FALSE;
800     assembly_operand o1, o2;
801     opcodez opco;
802
803     ASSERT_ZCODE();
804
805     offset = zmachine_pc;
806
807     no_instructions++;
808
809     if (veneer_mode) sequence_point_follows = FALSE;
810     if (sequence_point_follows)
811     {   sequence_point_follows = FALSE; at_seq_point = TRUE;
812         if (debugfile_switch)
813         {   sequence_point_labels[next_sequence_point] = next_label;
814             sequence_point_locations[next_sequence_point] =
815                 statement_debug_location;
816             set_label_offset(next_label++, zmachine_pc);
817         }
818         next_sequence_point++;
819     }
820
821     opco = internal_number_to_opcode_z(AI->internal_number);
822     if (opco.version1==0)
823     {   error_named("Opcode unavailable in this Z-machine version",
824             opcode_names.keywords[AI->internal_number]);
825         return;
826     }
827
828     if (execution_never_reaches_here)
829         warning("This statement can never be reached");
830
831     operand_rules = opco.op_rules;
832     execution_never_reaches_here = ((opco.flags & Rf) != 0);
833
834     if (opco.flags2_set != 0) flags2_requirements[opco.flags2_set] = 1;
835
836     no_operands_given = AI->operand_count;
837
838     if ((opco.no == TWO) && ((no_operands_given==3)||(no_operands_given==4)))
839         opco.no = VAR;
840
841     /* 1. Write the opcode byte(s) */
842
843     start_pc = zcode_holding_area + zcode_ha_size;
844
845     switch(opco.no)
846     {   case VAR_LONG: topbits=0xc0; min=0; max=8; break;
847         case VAR:      topbits=0xc0; min=0; max=4; break;
848         case ZERO:     topbits=0xb0; min=0; max=0; break;
849         case ONE:      topbits=0x80; min=1; max=1; break;
850         case TWO:      topbits=0x00; min=2; max=2; break;
851         case EXT:      topbits=0x00; min=0; max=4;
852                        byteout(0xbe, 0); opco.no=VAR; break;
853         case EXT_LONG: topbits=0x00; min=0; max=8;
854                        byteout(0xbe, 0); opco.no=VAR_LONG; break;
855     }
856     byteout(opco.code + topbits, 0);
857
858     operands_pc = zcode_holding_area + zcode_ha_size;
859
860     /* 2. Dispose of the special rules LABEL and TEXT */
861
862     if (operand_rules==LABEL)
863     {   j = (AI->operand[0]).value;
864         byteout(j/256, LABEL_MV); byteout(j%256, 0);
865         goto Instruction_Done;
866     }
867
868     if (operand_rules==TEXT)
869     {   int32 i;
870         uchar *tmp = translate_text(zcode_holding_area + zcode_ha_size, zcode_holding_area+MAX_ZCODE_SIZE, AI->text);
871         if (!tmp)
872             memoryerror("MAX_ZCODE_SIZE", MAX_ZCODE_SIZE);
873         j = subtract_pointers(tmp, (zcode_holding_area + zcode_ha_size));
874         for (i=0; i<j; i++) zcode_markers[zcode_ha_size++] = 0;
875         zmachine_pc += j;
876         goto Instruction_Done;
877     }
878
879     /* 3. Sort out the operands */
880
881     if ((no_operands_given < min) || (no_operands_given > max))
882         goto OpcodeSyntaxError;
883
884     switch(opco.no)
885     {   case VAR:
886         case VAR_LONG:
887             byteout(0, 0);
888             if (opco.no == VAR_LONG) byteout(0, 0);
889             types_byte1=0xff; types_byte2=0xff;
890             for (j=0; j<no_operands_given; j++)
891             {   int multi=0, mask=0;
892                 switch(j)
893                 {   case 0: case 4: multi=0x40; mask=0xc0; break;
894                     case 1: case 5: multi=0x10; mask=0x30; break;
895                     case 2: case 6: multi=0x04; mask=0x0c; break;
896                     case 3: case 7: multi=0x01; mask=0x03; break;
897                 }
898                 o1 = AI->operand[j];
899                 write_operand(o1);
900                 if (j<4)
901                     types_byte1 = (types_byte1 & (~mask)) + o1.type*multi;
902                 else
903                     types_byte2 = (types_byte2 & (~mask)) + o1.type*multi;
904             }
905             *operands_pc=types_byte1;
906             if (opco.no == VAR_LONG) *(operands_pc+1)=types_byte2;
907             break;
908
909         case ONE:
910             o1 = AI->operand[0];
911             *start_pc=(*start_pc) + o1.type*0x10;
912             write_operand(o1);
913             break;
914
915         case TWO:
916             o1 = AI->operand[0];
917             o2 = AI->operand[1];
918
919             /* Transfer to VAR form if either operand is a long constant */
920
921             if ((o1.type==LONG_CONSTANT_OT)||(o2.type==LONG_CONSTANT_OT))
922             {   *start_pc=(*start_pc) + 0xc0;
923                 byteout(o1.type*0x40 + o2.type*0x10 + 0x0f, 0);
924             }
925             else
926             {   if (o1.type==VARIABLE_OT) *start_pc=(*start_pc) + 0x40;
927                 if (o2.type==VARIABLE_OT) *start_pc=(*start_pc) + 0x20;
928             }
929             write_operand(o1);
930             write_operand(o2);
931             break;
932     }
933
934     /* 4. Assemble a Store destination, if needed */
935
936     if ((AI->store_variable_number) != -1)
937     {   if (AI->store_variable_number >= MAX_LOCAL_VARIABLES+MAX_GLOBAL_VARIABLES) {
938             goto OpcodeSyntaxError;
939         }
940         o1.type = VARIABLE_OT;
941         o1.value = AI->store_variable_number;
942         variable_usage[o1.value] = TRUE;
943         o1.marker = 0;
944
945         /*  Note that variable numbers 249 to 255 (i.e. globals 233 to 239)
946             are used as scratch workspace, so need no mapping between
947             modules and story files: nor do local variables 0 to 15  */
948
949         if ((o1.value >= MAX_LOCAL_VARIABLES) && (o1.value < 249))
950             o1.marker = VARIABLE_MV;
951         write_operand(o1);
952     }
953
954     /* 5. Assemble a branch, if needed */
955
956     if (AI->branch_label_number != -1)
957     {   int32 addr, long_form;
958         int branch_on_true = (AI->branch_flag)?1:0;
959
960         switch (AI->branch_label_number)
961         {   case -2: addr = 2; branch_on_true = 0; long_form = 0; break;
962                                                  /* branch nowhere, carry on */
963             case -3: addr = 0; long_form = 0; break;  /* rfalse on condition */
964             case -4: addr = 1; long_form = 0; break;  /* rtrue on condition */
965             default:
966                 long_form = 1; addr = AI->branch_label_number;
967                 break;
968         }
969         if (addr > 0x7fff) fatalerror("Too many branch points in routine.");
970         if (long_form==1)
971         {   byteout(branch_on_true*0x80 + addr/256, BRANCH_MV);
972             byteout(addr%256, 0);
973         }
974         else
975             byteout(branch_on_true*0x80+ 0x40 + (addr&0x3f), 0);
976     }
977
978     Instruction_Done:
979
980     if (asm_trace_level > 0)
981     {   int i;
982         printf("%5d  +%05lx %3s %-12s ", ErrorReport.line_number,
983             ((long int) offset),
984             (at_seq_point)?"<*>":"   ", opco.name);
985
986         if ((AI->internal_number == print_zc)
987             || (AI->internal_number == print_ret_zc))
988         {   printf("\"");
989             for (i=0;(AI->text)[i]!=0 && i<35; i++) printf("%c",(AI->text)[i]);
990             if (i == 35) printf("...");
991             printf("\"");
992         }
993
994         for (i=0; i<AI->operand_count; i++)
995         {   if ((i==0) && (opco.op_rules == VARIAB))
996             {   if ((AI->operand[0]).type == VARIABLE_OT)
997                 {   printf("["); print_operand_z(AI->operand[i]); }
998                 else
999                     printf("%s", variable_name((AI->operand[0]).value));
1000             }
1001             else
1002             if ((i==0) && (opco.op_rules == LABEL))
1003             {   printf("L%d", AI->operand[0].value);
1004             }
1005             else print_operand_z(AI->operand[i]);
1006             printf(" ");
1007         }
1008         if (AI->store_variable_number != -1)
1009         {   assembly_operand AO;
1010             printf("-> ");
1011             AO.type = VARIABLE_OT; AO.value = AI->store_variable_number;
1012             print_operand_z(AO); printf(" ");
1013         }
1014
1015         switch(AI->branch_label_number)
1016         {   case -4: printf("rtrue if %s", (AI->branch_flag)?"TRUE":"FALSE");
1017                 break;
1018             case -3: printf("rfalse if %s", (AI->branch_flag)?"TRUE":"FALSE");
1019                 break;
1020             case -2: printf("(no branch)"); break;
1021             case -1: break;
1022             default:
1023                 printf("to L%d if %s", AI->branch_label_number,
1024                    (AI->branch_flag)?"TRUE":"FALSE"); break;
1025         }
1026
1027         if (asm_trace_level>=2)
1028         {   for (j=0;start_pc<zcode_holding_area + zcode_ha_size;
1029                  j++, start_pc++)
1030             {   if (j%16==0) printf("\n                               ");
1031                 printf("%02x ", *start_pc);
1032             }
1033         }
1034         printf("\n");
1035     }
1036
1037     if (module_switch) flush_link_data();
1038
1039     return;
1040
1041     OpcodeSyntaxError:
1042
1043     make_opcode_syntax_z(opco);
1044     error_named("Assembly mistake: syntax is", opcode_syntax_string);
1045 }
1046
1047 static void assembleg_macro(assembly_instruction *AI)
1048 {
1049     /* validate macro syntax first */
1050     int ix, no_operands_given;
1051     opcodeg opco;
1052     
1053     opco = internal_number_to_opmacro_g(AI->internal_number);
1054     no_operands_given = AI->operand_count;
1055     
1056     if (no_operands_given != opco.no)
1057         goto OpcodeSyntaxError;
1058     
1059     for (ix = 0; ix < no_operands_given; ix++) {
1060         int type = AI->operand[ix].type;
1061         if ((opco.flags & St) 
1062           && ((!(opco.flags & Br) && (ix == no_operands_given-1))
1063           || ((opco.flags & Br) && (ix == no_operands_given-2)))) {
1064             if (is_constant_ot(type)) {
1065                 error("*** assembly macro tried to store to a constant ***");
1066                 goto OpcodeSyntaxError; 
1067             }
1068         }
1069         if ((opco.flags & St2) 
1070             && (ix == no_operands_given-2)) {
1071             if (is_constant_ot(type)) {
1072               error("*** assembly macro tried to store to a constant ***");
1073               goto OpcodeSyntaxError; 
1074             }
1075         }
1076     }
1077     
1078     /* expand the macro */
1079     switch (AI->internal_number) {
1080         case pull_gm:
1081             assembleg_store(AI->operand[0], stack_pointer);
1082             break;
1083         
1084         case push_gm:
1085             assembleg_store(stack_pointer, AI->operand[0]);
1086             break;
1087         
1088         default:
1089             compiler_error("Invalid Glulx assembly macro");
1090             break;
1091     }
1092     
1093     return;
1094     
1095     OpcodeSyntaxError:
1096     
1097     make_opcode_syntax_g(opco);
1098     error_named("Assembly mistake: syntax is", opcode_syntax_string);
1099 }
1100
1101 extern void assembleg_instruction(assembly_instruction *AI)
1102 {
1103     uchar *start_pc, *opmodes_pc;
1104     int32 offset, j;
1105     int no_operands_given, at_seq_point = FALSE;
1106     int ix, k;
1107     opcodeg opco;
1108
1109     ASSERT_GLULX();
1110
1111     offset = zmachine_pc;
1112
1113     no_instructions++;
1114
1115     if (veneer_mode) sequence_point_follows = FALSE;
1116     if (sequence_point_follows)
1117     {   sequence_point_follows = FALSE; at_seq_point = TRUE;
1118         if (debugfile_switch)
1119         {   sequence_point_labels[next_sequence_point] = next_label;
1120             sequence_point_locations[next_sequence_point] =
1121                 statement_debug_location;
1122             set_label_offset(next_label++, zmachine_pc);
1123         }
1124         next_sequence_point++;
1125     }
1126
1127     opco = internal_number_to_opcode_g(AI->internal_number);
1128
1129     if (execution_never_reaches_here)
1130         warning("This statement can never be reached");
1131
1132     execution_never_reaches_here = ((opco.flags & Rf) != 0);
1133
1134     if (opco.op_rules & GOP_Unicode) {
1135         uses_unicode_features = TRUE;
1136     }
1137     if (opco.op_rules & GOP_MemHeap) {
1138         uses_memheap_features = TRUE;
1139     }
1140     if (opco.op_rules & GOP_Acceleration) {
1141         uses_acceleration_features = TRUE;
1142     }
1143     if (opco.op_rules & GOP_Float) {
1144         uses_float_features = TRUE;
1145     }
1146
1147     no_operands_given = AI->operand_count;
1148
1149     /* 1. Write the opcode byte(s) */
1150
1151     start_pc = zcode_holding_area + zcode_ha_size; 
1152
1153     if (opco.code < 0x80) {
1154       byteout(opco.code, 0);
1155     }
1156     else if (opco.code < 0x4000) {
1157       byteout(((opco.code >> 8) & 0xFF) | 0x80, 0);
1158       byteout((opco.code & 0xFF), 0);
1159     }
1160     else {
1161       byteout(((opco.code >> 24) & 0xFF) | 0xC0, 0);
1162       byteout(((opco.code >> 16) & 0xFF), 0);
1163       byteout(((opco.code >> 8) & 0xFF), 0);
1164       byteout(((opco.code) & 0xFF), 0);
1165     }
1166
1167     /* ... and the operand addressing modes. There's one byte for
1168        every two operands (rounded up). We write zeroes for now; 
1169        when the operands are written, we'll go back and fix them. */
1170
1171     opmodes_pc = zcode_holding_area + zcode_ha_size;
1172
1173     for (ix=0; ix<opco.no; ix+=2) {
1174       byteout(0, 0);
1175     }
1176
1177     /* 2. Dispose of the special rules */
1178     /* There aren't any in Glulx. */
1179
1180     /* 3. Sort out the operands */
1181
1182     if (no_operands_given != opco.no) {
1183       goto OpcodeSyntaxError;
1184     }
1185
1186     for (ix=0; ix<no_operands_given; ix++) {
1187         int marker = AI->operand[ix].marker;
1188         int type = AI->operand[ix].type;
1189         k = AI->operand[ix].value;
1190
1191         if ((opco.flags & Br) && (ix == no_operands_given-1)) {
1192             if (!(marker >= BRANCH_MV && marker < BRANCHMAX_MV)) {
1193                 compiler_error("Assembling branch without BRANCH_MV marker");
1194                 goto OpcodeSyntaxError; 
1195             }
1196             if (k == -2) {
1197                 k = 2; /* branch no-op */
1198                 type = BYTECONSTANT_OT;
1199                 marker = 0;
1200             }
1201             else if (k == -3) {
1202                 k = 0; /* branch return 0 */
1203                 type = ZEROCONSTANT_OT;
1204                 marker = 0;
1205             }
1206             else if (k == -4) {
1207                 k = 1; /* branch return 1 */
1208                 type = BYTECONSTANT_OT;
1209                 marker = 0;
1210             }
1211             else {
1212                 /* branch to label k */
1213                 j = subtract_pointers((zcode_holding_area + zcode_ha_size), 
1214                     opmodes_pc);
1215                 j = 2*j - ix;
1216                 marker = BRANCH_MV + j;
1217                 if (!(marker >= BRANCH_MV && marker < BRANCHMAX_MV)) {
1218                     error("*** branch marker too far from opmode byte ***");
1219                     goto OpcodeSyntaxError; 
1220                 }
1221             }
1222         }
1223     if ((opco.flags & St) 
1224       && ((!(opco.flags & Br) && (ix == no_operands_given-1))
1225       || ((opco.flags & Br) && (ix == no_operands_given-2)))) {
1226         if (type == BYTECONSTANT_OT || type == HALFCONSTANT_OT
1227             || type == CONSTANT_OT) {
1228             error("*** instruction tried to store to a constant ***");
1229             goto OpcodeSyntaxError; 
1230         }
1231     }
1232     if ((opco.flags & St2) 
1233         && (ix == no_operands_given-2)) {
1234         if (type == BYTECONSTANT_OT || type == HALFCONSTANT_OT
1235           || type == CONSTANT_OT) {
1236           error("*** instruction tried to store to a constant ***");
1237           goto OpcodeSyntaxError; 
1238         }
1239     }
1240
1241       if (marker && (type == HALFCONSTANT_OT 
1242         || type == BYTECONSTANT_OT
1243         || type == ZEROCONSTANT_OT)) {
1244         compiler_error("Assembling marker in less than 32-bit constant.");
1245         /* Actually we should store marker|0x80 for a byte constant,
1246            but let's hold off on that. */
1247         }
1248
1249       switch (type) {
1250       case LONG_CONSTANT_OT:
1251       case SHORT_CONSTANT_OT:
1252       case VARIABLE_OT:
1253         j = 0;
1254         compiler_error("Z-code OT in Glulx assembly operand.");
1255         break;
1256       case CONSTANT_OT:
1257         j = 3;
1258         byteout((k >> 24) & 0xFF, marker);
1259         byteout((k >> 16) & 0xFF, 0);
1260         byteout((k >> 8) & 0xFF, 0);
1261         byteout((k & 0xFF), 0);
1262         break;
1263       case HALFCONSTANT_OT:
1264         j = 2;
1265         byteout((k >> 8) & 0xFF, marker);
1266         byteout((k & 0xFF), 0);
1267         break;
1268       case BYTECONSTANT_OT:
1269         j = 1;
1270         byteout((k & 0xFF), marker);
1271         break;
1272       case ZEROCONSTANT_OT:
1273         j = 0;
1274         break;
1275       case DEREFERENCE_OT:
1276         j = 7;
1277         byteout((k >> 24) & 0xFF, marker);
1278         byteout((k >> 16) & 0xFF, 0);
1279         byteout((k >> 8) & 0xFF, 0);
1280         byteout((k & 0xFF), 0);
1281         break;
1282       case GLOBALVAR_OT:
1283         /* Global variable -- a constant address. */
1284         k -= MAX_LOCAL_VARIABLES;
1285         if (/* DISABLES CODE */ (0)) {
1286             /* We could write the value as a marker and patch it later... */
1287             j = 7;
1288             byteout(((k) >> 24) & 0xFF, VARIABLE_MV);
1289             byteout(((k) >> 16) & 0xFF, 0);
1290             byteout(((k) >> 8) & 0xFF, 0);
1291             byteout(((k) & 0xFF), 0);
1292         }
1293         else {
1294             /* ...but it's more efficient to write it as a RAM operand,
1295                   which can be 1, 2, or 4 bytes. Remember that global variables
1296                   are the very first thing in RAM. */
1297             k = k * 4; /* each variable is four bytes */
1298             if (k <= 255) {
1299                 j = 13;
1300                 byteout(((k) & 0xFF), 0);
1301             }
1302             else if (k <= 65535) {
1303                 j = 14;
1304                 byteout(((k) >> 8) & 0xFF, 0);
1305                 byteout(((k) & 0xFF), 0);
1306             }
1307             else {
1308                 j = 15;
1309                 byteout(((k) >> 24) & 0xFF, 0);
1310                 byteout(((k) >> 16) & 0xFF, 0);
1311                 byteout(((k) >> 8) & 0xFF, 0);
1312                 byteout(((k) & 0xFF), 0);       
1313             }
1314         }
1315         break;
1316       case LOCALVAR_OT:
1317         if (k == 0) {
1318             /* Stack-pointer magic variable */
1319             j = 8; 
1320         }
1321         else {
1322             /* Local variable -- a byte or short offset from the
1323                frame pointer. It's an unsigned offset, so we can
1324                fit up to long 63 (offset 4*63) in a byte. */
1325             if ((k-1) < 64) {
1326                 j = 9;
1327                 byteout((k-1)*4, 0);
1328             }
1329             else {
1330                 j = 10;
1331                 byteout((((k-1)*4) >> 8) & 0xFF, 0);
1332                 byteout(((k-1)*4) & 0xFF, 0);
1333             }
1334         }
1335         break;
1336       default:
1337         j = 0;
1338         break;
1339       }
1340
1341       if (ix & 1)
1342           j = (j << 4);
1343       opmodes_pc[ix/2] |= j;
1344     }
1345
1346     /* Print assembly trace. */
1347     if (asm_trace_level > 0) {
1348       int i;
1349       printf("%5d  +%05lx %3s %-12s ", ErrorReport.line_number,
1350         ((long int) offset),
1351         (at_seq_point)?"<*>":"   ", opco.name);
1352       for (i=0; i<AI->operand_count; i++) {
1353           if ((opco.flags & Br) && (i == opco.no-1)) {
1354             if (AI->operand[i].value == -4)
1355                 printf("to rtrue");
1356             else if (AI->operand[i].value == -3)
1357                 printf("to rfalse");
1358             else
1359                 printf("to L%d", AI->operand[i].value);
1360             }
1361           else {
1362             print_operand_g(AI->operand[i]);
1363           }
1364           printf(" ");
1365       }
1366
1367       if (asm_trace_level>=2) {
1368         for (j=0;
1369             start_pc<zcode_holding_area + zcode_ha_size;
1370             j++, start_pc++) {
1371             if (j%16==0) printf("\n                               ");
1372             if (/* DISABLES CODE */ (0)) {
1373                 printf("%02x ", *start_pc);
1374             }
1375             else {
1376                 printf("%02x", *start_pc);
1377                 if (zcode_markers[start_pc-zcode_holding_area])
1378                     printf("{%02x}", zcode_markers[start_pc-zcode_holding_area]);
1379                 printf(" ");
1380             }
1381         }
1382       }
1383       printf("\n");
1384     }
1385
1386     if (module_switch) flush_link_data();
1387
1388     return;
1389
1390     OpcodeSyntaxError:
1391
1392     make_opcode_syntax_g(opco);
1393     error_named("Assembly mistake: syntax is", opcode_syntax_string);
1394 }
1395
1396 extern void assemble_label_no(int n)
1397 {
1398     if (asm_trace_level > 0)
1399         printf("%5d  +%05lx    .L%d\n", ErrorReport.line_number,
1400             ((long int) zmachine_pc), n);
1401     set_label_offset(n, zmachine_pc);
1402     execution_never_reaches_here = FALSE;
1403 }
1404
1405 extern void define_symbol_label(int symbol)
1406 {   label_symbols[svals[symbol]] = symbol;
1407 }
1408
1409 extern int32 assemble_routine_header(int no_locals,
1410     int routine_asterisked, char *name, int embedded_flag, int the_symbol)
1411 {   int i, rv;
1412     int stackargs = FALSE;
1413     int name_length;
1414
1415     execution_never_reaches_here = FALSE;
1416
1417     routine_locals = no_locals;
1418     for (i=0; i<MAX_LOCAL_VARIABLES; i++) variable_usage[i] = FALSE;
1419
1420     if (no_locals >= 1 
1421       && !strcmp(local_variables.keywords[0], "_vararg_count")) {
1422       stackargs = TRUE;
1423     }
1424
1425     if (veneer_mode) routine_starts_line = blank_brief_location;
1426     else routine_starts_line = get_brief_location(&ErrorReport);
1427
1428     if (asm_trace_level > 0)
1429     {   printf("\n%5d  +%05lx  [ %s ", ErrorReport.line_number,
1430             ((long int) zmachine_pc), name);
1431         for (i=1; i<=no_locals; i++) printf("%s ", variable_name(i));
1432         printf("\n\n");
1433     }
1434
1435     routine_start_pc = zmachine_pc;
1436
1437     if (track_unused_routines) {
1438         /* The name of an embedded function is in a temporary buffer,
1439            so we shouldn't keep a reference to it. (It is sad that we
1440            have to know this here.) */
1441         char *funcname = name;
1442         if (embedded_flag)
1443             funcname = "<embedded>";
1444
1445         df_note_function_start(funcname, zmachine_pc, embedded_flag,
1446                                routine_starts_line);
1447     }
1448
1449     routine_symbol = the_symbol;
1450     name_length = strlen(name) + 1;
1451     routine_name =
1452       my_malloc(name_length * sizeof(char), "temporary copy of routine name");
1453     strncpy(routine_name, name, name_length);
1454
1455     /*  Update the routine counter                                           */
1456
1457     no_routines++;
1458
1459     /*  Actually assemble the routine header into the code area; note        */
1460     /*  Inform doesn't support the setting of local variables to default     */
1461     /*  values other than 0 in V3 and V4.  (In V5+ the Z-Machine doesn't     */
1462     /*  provide the possibility in any case.)                                */
1463
1464     if (!glulx_mode) {
1465
1466       if (stackargs) 
1467         warning("Z-code does not support stack-argument function definitions.");
1468
1469       byteout(no_locals, 0);
1470
1471       /*  Not the packed address, but the scaled offset from code area start:  */
1472
1473       rv = zmachine_pc/scale_factor;
1474
1475       if (instruction_set_number<5)
1476           for (i=0; i<no_locals; i++) { byteout(0,0); byteout(0,0); }
1477
1478       next_label = 0; next_sequence_point = 0; last_label = -1;
1479
1480       /*  Compile code to print out text like "a=3, b=4, c=5" when the       */
1481       /*  function is called, if it's required.                              */
1482
1483       if ((routine_asterisked) || (define_INFIX_switch))
1484       {   char fnt[256]; assembly_operand PV, RFA, CON, STP, SLF; int ln, ln2;
1485
1486           ln = next_label++;
1487           ln2 = next_label++;
1488
1489           if (define_INFIX_switch)
1490           {
1491                 if (embedded_flag)
1492             {   SLF.value = 251; SLF.type = VARIABLE_OT; SLF.marker = 0;
1493                   CON.value = 0; CON.type = SHORT_CONSTANT_OT; CON.marker = 0;
1494                 assemblez_2_branch(test_attr_zc, SLF, CON, ln2, FALSE);
1495             }
1496             else
1497             {   i = no_named_routines++;
1498                   named_routine_symbols[i] = the_symbol;
1499                 CON.value = i/8; CON.type = LONG_CONSTANT_OT; CON.marker = 0;
1500                 RFA.value = routine_flags_array_SC;
1501                 RFA.type = LONG_CONSTANT_OT; RFA.marker = INCON_MV;
1502                 STP.value = 0; STP.type = VARIABLE_OT; STP.marker = 0;
1503                 assemblez_2_to(loadb_zc, RFA, CON, STP);
1504                 CON.value = (1 << (i%8)); CON.type = SHORT_CONSTANT_OT;
1505                 assemblez_2_to(and_zc, STP, CON, STP);
1506                 assemblez_1_branch(jz_zc, STP, ln2, TRUE);
1507             }
1508         }
1509         sprintf(fnt, "[ %s(", name);
1510         AI.text = fnt; assemblez_0(print_zc);
1511         for (i=1; (i<=7)&&(i<=no_locals); i++)
1512         {   if (version_number >= 5)
1513             {   PV.type = SHORT_CONSTANT_OT;
1514                 PV.value = i; PV.marker = 0;
1515                 assemblez_1_branch(check_arg_count_zc, PV, ln, FALSE);
1516             }
1517             sprintf(fnt, "%s%s = ", (i==1)?"":", ", variable_name(i));
1518             AI.text = fnt; assemblez_0(print_zc);
1519             PV.type = VARIABLE_OT; PV.value = i; PV.marker = 0;
1520             assemblez_1(print_num_zc, PV);
1521         }
1522         assemble_label_no(ln);
1523         sprintf(fnt, ") ]^"); AI.text = fnt;
1524         assemblez_0(print_zc);
1525         assemble_label_no(ln2);
1526       }
1527
1528     }
1529     else {
1530       rv = zmachine_pc;
1531
1532       if (stackargs)
1533         byteout(0xC0, 0); /* Glulx type byte for function */
1534       else
1535         byteout(0xC1, 0); /* Glulx type byte for function */
1536
1537       /* Now the locals format list. This is simple; we only use
1538         four-byte locals. That's a single pair, unless we have more
1539         than 255 locals, or none at all. */
1540       i = no_locals;
1541       while (i) {
1542         int j = i;
1543         if (j > 255)
1544           j = 255;
1545         byteout(4, 0); 
1546         byteout(j, 0);
1547         i -= j;
1548       }
1549       /* Terminate the list with a (0, 0) pair. */
1550       byteout(0, 0);
1551       byteout(0, 0);
1552
1553       if (stackargs) {
1554         /* The top stack value is the number of function arguments. Let's
1555            move that into the first local, which is _vararg_count. */
1556         /* @copy sp _vararg_count; */
1557         byteout(0x40, 0); byteout(0x98, 0); byteout(0x00, 0);
1558       }
1559
1560       next_label = 0; next_sequence_point = 0; last_label = -1; 
1561
1562       if ((routine_asterisked) || (define_INFIX_switch)) {
1563         int ix;
1564         char fnt[256];
1565         assembly_operand AO, AO2;
1566         if (define_INFIX_switch) {
1567           /* This isn't supported */
1568           if (embedded_flag) {
1569           }
1570           else {
1571             i = no_named_routines++;
1572             named_routine_symbols[i] = the_symbol;
1573           }
1574         }
1575         sprintf(fnt, "[ %s(", name);
1576         AO.marker = STRING_MV;
1577         AO.type   = CONSTANT_OT;
1578         AO.value  = compile_string(fnt, FALSE, FALSE);
1579         assembleg_1(streamstr_gc, AO);
1580
1581         if (!stackargs) {
1582           for (ix=1; ix<=no_locals; ix++) {
1583             sprintf(fnt, "%s%s = ", (ix==1)?"":", ", variable_name(ix));
1584             AO.marker = STRING_MV;
1585             AO.type   = CONSTANT_OT;
1586             AO.value  = compile_string(fnt, FALSE, FALSE);
1587             assembleg_1(streamstr_gc, AO);
1588             AO.marker = 0;
1589             AO.type = LOCALVAR_OT;
1590             AO.value = ix;
1591             assembleg_1(streamnum_gc, AO);
1592           }
1593         }
1594         else {
1595           int lntop, lnbottom;
1596           sprintf(fnt, "%s = ", variable_name(1));
1597           AO.marker = STRING_MV;
1598           AO.type   = CONSTANT_OT;
1599           AO.value  = compile_string(fnt, FALSE, FALSE);
1600           assembleg_1(streamstr_gc, AO);
1601           AO.marker = 0;
1602           AO.type = LOCALVAR_OT;
1603           AO.value = 1;
1604           assembleg_1(streamnum_gc, AO);
1605           AO2.type = BYTECONSTANT_OT;
1606           AO2.marker = 0;
1607           AO2.value = ':';
1608           assembleg_1(streamchar_gc, AO2);
1609           AO2.type = BYTECONSTANT_OT;
1610           AO2.marker = 0;
1611           AO2.value = ' ';
1612           /* for (temp_var4=0 : temp_var4<_vararg_count : temp_var4++) {
1613                @streamchar ' ';
1614                @stkpeek temp_var4 sp;
1615                @stream_num sp;
1616              }
1617           */
1618           assembleg_store(temp_var4, zero_operand);
1619           lntop = next_label++;
1620           lnbottom = next_label++;
1621           assemble_label_no(lntop);
1622           assembleg_2_branch(jge_gc, temp_var4, AO, lnbottom); /* AO is _vararg_count */
1623           assembleg_1(streamchar_gc, AO2); /* AO2 is space */
1624           assembleg_2(stkpeek_gc, temp_var4, stack_pointer);
1625           assembleg_1(streamnum_gc, stack_pointer);
1626           assembleg_3(add_gc, temp_var4, one_operand, temp_var4);
1627           assembleg_0_branch(jump_gc, lntop);
1628           assemble_label_no(lnbottom);
1629         }
1630
1631         AO.marker = STRING_MV;
1632         AO.type   = CONSTANT_OT;
1633         AO.value  = compile_string(") ]^", FALSE, FALSE);
1634         assembleg_1(streamstr_gc, AO);
1635       }
1636     }
1637
1638     return rv;
1639 }
1640
1641 void assemble_routine_end(int embedded_flag, debug_locations locations)
1642 {   int32 i;
1643
1644     /* No marker is made in the Z-machine's code area to indicate the        */
1645     /* end of a routine.  Instead, we simply assemble a return opcode if     */
1646     /* need be (it won't be if the last instruction was, say, a "quit").     */
1647     /* The return value is true (1) for normal routines, false (0) for       */
1648     /* embedded routines (e.g. the library uses this for "before"            */
1649     /* properties).                                                          */
1650
1651     if (!execution_never_reaches_here)
1652     {   
1653       if (!glulx_mode) {
1654         if (embedded_flag) assemblez_0(rfalse_zc);
1655                       else assemblez_0(rtrue_zc);
1656       }
1657       else {
1658         assembly_operand AO;
1659         if (embedded_flag) 
1660             AO = zero_operand;
1661         else 
1662             AO = one_operand;
1663         assembleg_1(return_gc, AO);
1664       }
1665     }
1666
1667     /* Dump the contents of the current routine into longer-term Z-code
1668        storage                                                               */
1669
1670     if (!glulx_mode)
1671       transfer_routine_z();
1672     else
1673       transfer_routine_g();
1674
1675     if (track_unused_routines)
1676         df_note_function_end(zmachine_pc);
1677
1678     /* Tell the debugging file about the routine just ended.                 */
1679
1680     if (debugfile_switch)
1681     {
1682         debug_file_printf("<routine>");
1683         if (embedded_flag)
1684         {   debug_file_printf
1685                 ("<identifier artificial=\"true\">%s</identifier>",
1686                  routine_name);
1687         }
1688         else if (sflags[routine_symbol] & REPLACE_SFLAG)
1689         {   /* The symbol type will be set to ROUTINE_T once the replaced
1690                version has been given; if it is already set, we must be dealing
1691                with a replacement, and we can use the routine name as-is.
1692                Otherwise we look for a rename.  And if that doesn't work, we
1693                fall back to an artificial identifier. */
1694             if (stypes[routine_symbol] == ROUTINE_T)
1695             {   /* Optional because there may be further replacements. */
1696                 write_debug_optional_identifier(routine_symbol);
1697             }
1698             else if (find_symbol_replacement(&routine_symbol))
1699             {   debug_file_printf
1700                     ("<identifier>%s</identifier>", symbs[routine_symbol]);
1701             }
1702             else
1703             {   debug_file_printf
1704                     ("<identifier artificial=\"true\">%s (replaced)"
1705                          "</identifier>",
1706                      routine_name);
1707             }
1708         } else
1709         {   debug_file_printf("<identifier>%s</identifier>", routine_name);
1710         }
1711         debug_file_printf("<value>");
1712         if (glulx_mode)
1713         {   write_debug_code_backpatch(routine_start_pc);
1714         } else
1715         {   write_debug_packed_code_backpatch(routine_start_pc);
1716         }
1717         debug_file_printf("</value>");
1718         debug_file_printf("<address>");
1719         write_debug_code_backpatch(routine_start_pc);
1720         debug_file_printf("</address>");
1721         debug_file_printf
1722             ("<byte-count>%d</byte-count>", zmachine_pc - routine_start_pc);
1723         write_debug_locations(locations);
1724         for (i = 1; i <= routine_locals; ++i)
1725         {   debug_file_printf("<local-variable>");
1726             debug_file_printf("<identifier>%s</identifier>", variable_name(i));
1727             if (glulx_mode)
1728             {   debug_file_printf
1729                     ("<frame-offset>%d</frame-offset>", 4 * (i - 1));
1730             }
1731             else
1732             {   debug_file_printf("<index>%d</index>", i);
1733             }
1734             debug_file_printf("</local-variable>");
1735         }
1736         for (i = 0; i < next_sequence_point; ++i)
1737         {   debug_file_printf("<sequence-point>");
1738             debug_file_printf("<address>");
1739             write_debug_code_backpatch
1740                 (label_offsets[sequence_point_labels[i]]);
1741             debug_file_printf("</address>");
1742             write_debug_location(sequence_point_locations[i]);
1743             debug_file_printf("</sequence-point>");
1744         }
1745         debug_file_printf("</routine>");
1746     }
1747
1748     my_free(&routine_name, "temporary copy of routine name");
1749
1750     /* Issue warnings about any local variables not used in the routine. */
1751
1752     for (i=1; i<=routine_locals; i++)
1753         if (!(variable_usage[i]))
1754             dbnu_warning("Local variable", variable_name(i),
1755                 routine_starts_line);
1756
1757     for (i=0; i<next_label; i++)
1758     {   int j = label_symbols[i];
1759         if (j != -1)
1760         {   if (sflags[j] & CHANGE_SFLAG)
1761                 error_named_at("Routine contains no such label as",
1762                     (char *) symbs[j], slines[j]);
1763             else
1764                 if ((sflags[j] & USED_SFLAG) == 0)
1765                     dbnu_warning("Label", (char *) symbs[j], slines[j]);
1766             stypes[j] = CONSTANT_T;
1767             sflags[j] = UNKNOWN_SFLAG;
1768         }
1769     }
1770     no_sequence_points += next_sequence_point;
1771     next_label = 0; next_sequence_point = 0;
1772 }
1773
1774 /* ------------------------------------------------------------------------- */
1775 /*   Called when the holding area contains an entire routine of code:        */
1776 /*   backpatches the labels, issues module markers, then dumps the routine   */
1777 /*   into longer-term storage.                                               */
1778 /*   Note that in the code received, all branches have long form, and their  */
1779 /*   contents are not an offset but the label numbers they branch to.        */
1780 /*   Similarly, LABEL operands (those of "jump" instructions) are label      */
1781 /*   numbers.  So this routine must change the label numbers to offsets,     */
1782 /*   slimming the code down as it does so to take advantage of short-form    */
1783 /*   branch operands where possible.                                         */
1784 /* ------------------------------------------------------------------------- */
1785
1786 static int32 adjusted_pc;
1787
1788 static void transfer_to_temp_file(uchar *c)
1789 {   fputc(*c,Temp2_fp);
1790     adjusted_pc++;
1791 }
1792
1793 static void transfer_to_zcode_area(uchar *c)
1794 {   write_byte_to_memory_block(&zcode_area, adjusted_pc++, *c);
1795 }
1796
1797 static void transfer_routine_z(void)
1798 {   int32 i, j, pc, new_pc, label, long_form, offset_of_next, addr,
1799           branch_on_true, rstart_pc;
1800     void (* transfer_byte)(uchar *);
1801
1802     adjusted_pc = zmachine_pc - zcode_ha_size; rstart_pc = adjusted_pc;
1803
1804     if (asm_trace_level >= 3)
1805     {   printf("Backpatching routine at %05lx: initial size %d, %d labels\n",
1806              (long int) adjusted_pc, zcode_ha_size, next_label);
1807     }
1808
1809     transfer_byte =
1810         (temporary_files_switch)?transfer_to_temp_file:transfer_to_zcode_area;
1811
1812     /*  (1) Scan through for branches and make short/long decisions in each
1813             case.  Mark omitted bytes (2nd bytes in branches converted to
1814             short form) with DELETED_MV.                                     */
1815
1816     for (i=0, pc=adjusted_pc; i<zcode_ha_size; i++, pc++)
1817     {   if (zcode_markers[i] == BRANCH_MV)
1818         {   if (asm_trace_level >= 4)
1819                 printf("Branch detected at offset %04x\n", pc);
1820             j = (256*zcode_holding_area[i] + zcode_holding_area[i+1]) & 0x7fff;
1821             if (asm_trace_level >= 4)
1822                 printf("To label %d, which is %d from here\n",
1823                     j, label_offsets[j]-pc);
1824             if ((label_offsets[j] >= pc+2) && (label_offsets[j] < pc+64))
1825             {   if (asm_trace_level >= 4) printf("Short form\n");
1826                 zcode_markers[i+1] = DELETED_MV;
1827             }
1828         }
1829     }
1830
1831     /*  (2) Calculate the new positions of the labels.  Note that since the
1832             long/short decision was taken on the basis of the old labels,
1833             and since the new labels are slightly closer together because
1834             of branch bytes deleted, there may be a few further branch
1835             optimisations which are possible but which have been missed
1836             (if two labels move inside the "short" range as a result of
1837             a previous optimisation).  However, this is acceptably uncommon. */
1838
1839     if (next_label > 0)
1840     {   if (asm_trace_level >= 4)
1841         {   printf("Opening label: %d\n", first_label);
1842             for (i=0;i<next_label;i++)
1843                 printf("Label %d offset %04x next -> %d previous -> %d\n",
1844                     i, label_offsets[i], label_next[i], label_prev[i]);
1845         }
1846
1847         for (i=0, pc=adjusted_pc, new_pc=adjusted_pc, label = first_label;
1848             i<zcode_ha_size; i++, pc++)
1849         {   while ((label != -1) && (label_offsets[label] == pc))
1850             {   if (asm_trace_level >= 4)
1851                     printf("Position of L%d corrected from %04x to %04x\n",
1852                         label, label_offsets[label], new_pc);
1853                 label_offsets[label] = new_pc;
1854                 label = label_next[label];
1855             }
1856            if (zcode_markers[i] != DELETED_MV) new_pc++;
1857         }
1858     }
1859
1860     /*  (3) As we are transferring, replace the label numbers in branch
1861             operands with offsets to those labels.  Also issue markers, now
1862             that we know where they occur in the final Z-code area.          */
1863
1864     for (i=0, new_pc=adjusted_pc; i<zcode_ha_size; i++)
1865     {   switch(zcode_markers[i])
1866         { case BRANCH_MV:
1867             long_form = 1; if (zcode_markers[i+1] == DELETED_MV) long_form = 0;
1868
1869             j = (256*zcode_holding_area[i] + zcode_holding_area[i+1]) & 0x7fff;
1870             branch_on_true = ((zcode_holding_area[i]) & 0x80);
1871             offset_of_next = new_pc + long_form + 1;
1872
1873             addr = label_offsets[j] - offset_of_next + 2;
1874             if (addr<-0x2000 || addr>0x1fff) 
1875                 fatalerror("Branch out of range: divide the routine up?");
1876             if (addr<0) addr+=(int32) 0x10000L;
1877
1878             addr=addr&0x3fff;
1879             if (long_form==1)
1880             {   zcode_holding_area[i] = branch_on_true + addr/256;
1881                 zcode_holding_area[i+1] = addr%256;
1882             }
1883             else
1884             {   if (addr >= 64)
1885                 {   compiler_error("Label out of range for branch");
1886                     printf("Addr is %04x\n", addr);
1887                 }
1888                 zcode_holding_area[i] = branch_on_true + 0x40 + (addr&0x3f);
1889             }
1890             transfer_byte(zcode_holding_area + i); new_pc++;
1891             break;
1892
1893           case LABEL_MV:
1894             j = 256*zcode_holding_area[i] + zcode_holding_area[i+1];
1895             addr = label_offsets[j] - new_pc;
1896             if (addr<-0x8000 || addr>0x7fff) 
1897                 fatalerror("Jump out of range: divide the routine up?");
1898             if (addr<0) addr += (int32) 0x10000L;
1899             zcode_holding_area[i] = addr/256;
1900             zcode_holding_area[i+1] = addr%256;
1901             transfer_byte(zcode_holding_area + i); new_pc++;
1902             break;
1903
1904           case DELETED_MV:
1905             break;
1906
1907           default:
1908             switch(zcode_markers[i] & 0x7f)
1909             {   case NULL_MV: break;
1910                 case VARIABLE_MV:
1911                 case OBJECT_MV:
1912                 case ACTION_MV:
1913                 case IDENT_MV:
1914                     if (!module_switch) break;
1915                 default:
1916                     if ((zcode_markers[i] & 0x7f) > LARGEST_BPATCH_MV)
1917                     {   compiler_error("Illegal code backpatch value");
1918                         printf("Illegal value of %02x at PC = %04x\n",
1919                             zcode_markers[i] & 0x7f, new_pc);
1920                         break;
1921                     }
1922
1923                     write_byte_to_memory_block(&zcode_backpatch_table,
1924                         zcode_backpatch_size++,
1925                         zcode_markers[i] + 32*(new_pc/65536));
1926                     write_byte_to_memory_block(&zcode_backpatch_table,
1927                         zcode_backpatch_size++, (new_pc/256)%256);
1928                     write_byte_to_memory_block(&zcode_backpatch_table,
1929                         zcode_backpatch_size++, new_pc%256);
1930                     break;
1931             }
1932             transfer_byte(zcode_holding_area + i); new_pc++;
1933             break;
1934         }
1935     }
1936
1937     if (asm_trace_level >= 3)
1938     {   printf("After branch optimisation, routine length is %d bytes\n",
1939              new_pc - rstart_pc);
1940     }
1941
1942     /*  Insert null bytes if necessary to ensure the next routine address is */
1943     /*  expressible as a packed address                                      */
1944
1945     {   uchar zero[1];
1946         zero[0] = 0;
1947         if (oddeven_packing_switch)
1948             while ((adjusted_pc%(scale_factor*2))!=0) transfer_byte(zero);
1949         else
1950             while ((adjusted_pc%scale_factor)!=0) transfer_byte(zero);
1951     }
1952
1953     zmachine_pc = adjusted_pc;
1954     zcode_ha_size = 0;
1955 }
1956
1957 static void transfer_routine_g(void)
1958 {   int32 i, j, pc, new_pc, label, form_len, offset_of_next, addr,
1959           rstart_pc;
1960     void (* transfer_byte)(uchar *);
1961
1962     adjusted_pc = zmachine_pc - zcode_ha_size; rstart_pc = adjusted_pc;
1963
1964     if (asm_trace_level >= 3)
1965     {   printf("Backpatching routine at %05lx: initial size %d, %d labels\n",
1966              (long int) adjusted_pc, zcode_ha_size, next_label);
1967     }
1968
1969     transfer_byte =
1970         (temporary_files_switch)?transfer_to_temp_file:transfer_to_zcode_area;
1971
1972     /*  (1) Scan through for branches and make short/long decisions in each
1973             case.  Mark omitted bytes (bytes 2-4 in branches converted to
1974             short form) with DELETED_MV.                                     */
1975
1976     for (i=0, pc=adjusted_pc; i<zcode_ha_size; i++, pc++) {
1977       if (zcode_markers[i] >= BRANCH_MV && zcode_markers[i] < BRANCHMAX_MV) {
1978         int opmodeoffset = (zcode_markers[i] - BRANCH_MV);
1979         int32 opmodebyte;
1980         if (asm_trace_level >= 4)
1981             printf("Branch detected at offset %04x\n", pc);
1982         j = ((zcode_holding_area[i] << 24) 
1983             | (zcode_holding_area[i+1] << 16)
1984             | (zcode_holding_area[i+2] << 8)
1985             | (zcode_holding_area[i+3]));
1986         offset_of_next = pc + 4;
1987         addr = (label_offsets[j] - offset_of_next) + 2;
1988         if (asm_trace_level >= 4)
1989             printf("To label %d, which is (%d-2) = %d from here\n",
1990                 j, addr, label_offsets[j] - offset_of_next);
1991         if (addr >= -0x80 && addr < 0x80) {
1992             if (asm_trace_level >= 4) printf("...Byte form\n");
1993             zcode_markers[i+1] = DELETED_MV;
1994             zcode_markers[i+2] = DELETED_MV;
1995             zcode_markers[i+3] = DELETED_MV;
1996             opmodebyte = i - ((opmodeoffset+1)/2);
1997             if ((opmodeoffset & 1) == 0)
1998                 zcode_holding_area[opmodebyte] = 
1999                     (zcode_holding_area[opmodebyte] & 0xF0) | 0x01;
2000             else
2001                 zcode_holding_area[opmodebyte] = 
2002                     (zcode_holding_area[opmodebyte] & 0x0F) | 0x10;
2003         }
2004         else if (addr >= -0x8000 && addr < 0x8000) {
2005             if (asm_trace_level >= 4) printf("...Short form\n");
2006             zcode_markers[i+2] = DELETED_MV;
2007             zcode_markers[i+3] = DELETED_MV;
2008             opmodebyte = i - ((opmodeoffset+1)/2);
2009             if ((opmodeoffset & 1) == 0)
2010                 zcode_holding_area[opmodebyte] = 
2011                     (zcode_holding_area[opmodebyte] & 0xF0) | 0x02;
2012             else
2013                 zcode_holding_area[opmodebyte] = 
2014                     (zcode_holding_area[opmodebyte] & 0x0F) | 0x20;
2015         }
2016       }
2017     }
2018
2019     /*  (2) Calculate the new positions of the labels.  Note that since the
2020             long/short decision was taken on the basis of the old labels,
2021             and since the new labels are slightly closer together because
2022             of branch bytes deleted, there may be a few further branch
2023             optimisations which are possible but which have been missed
2024             (if two labels move inside the "short" range as a result of
2025             a previous optimisation).  However, this is acceptably uncommon. */
2026     if (next_label > 0) {
2027       if (asm_trace_level >= 4) {
2028         printf("Opening label: %d\n", first_label);
2029         for (i=0;i<next_label;i++)
2030             printf("Label %d offset %04x next -> %d previous -> %d\n",
2031                 i, label_offsets[i], label_next[i], label_prev[i]);
2032       }
2033
2034       for (i=0, pc=adjusted_pc, new_pc=adjusted_pc, label = first_label;
2035         i<zcode_ha_size; 
2036         i++, pc++) {
2037         while ((label != -1) && (label_offsets[label] == pc)) {
2038             if (asm_trace_level >= 4)
2039                 printf("Position of L%d corrected from %04x to %04x\n",
2040                 label, label_offsets[label], new_pc);
2041             label_offsets[label] = new_pc;
2042             label = label_next[label];
2043         }
2044         if (zcode_markers[i] != DELETED_MV) new_pc++;
2045       }
2046     }
2047
2048     /*  (3) As we are transferring, replace the label numbers in branch
2049             operands with offsets to those labels.  Also issue markers, now
2050             that we know where they occur in the final Z-code area.          */
2051
2052     for (i=0, new_pc=adjusted_pc; i<zcode_ha_size; i++) {
2053
2054       if (zcode_markers[i] >= BRANCH_MV && zcode_markers[i] < BRANCHMAX_MV) {
2055         form_len = 4;
2056         if (zcode_markers[i+1] == DELETED_MV) {
2057             form_len = 1;
2058         }
2059         else {
2060             if (zcode_markers[i+2] == DELETED_MV)
2061                 form_len = 2;
2062         }
2063         j = ((zcode_holding_area[i] << 24) 
2064             | (zcode_holding_area[i+1] << 16)
2065             | (zcode_holding_area[i+2] << 8)
2066             | (zcode_holding_area[i+3]));
2067
2068         /* At the moment, we can safely assume that the branch operand
2069            is the end of the opcode, so the next opcode starts right
2070            after it. */
2071         offset_of_next = new_pc + form_len;
2072
2073         addr = (label_offsets[j] - offset_of_next) + 2;
2074         if (asm_trace_level >= 4) {
2075             printf("Branch at offset %04x: %04x (%s)\n",
2076                 new_pc, addr, ((form_len == 1) ? "byte" :
2077                 ((form_len == 2) ? "short" : "long")));
2078         }
2079         if (form_len == 1) {
2080             if (addr < -0x80 || addr >= 0x80) {
2081                 error("*** Label out of range for byte branch ***");
2082             }
2083             zcode_holding_area[i] = (addr) & 0xFF;
2084         }
2085         else if (form_len == 2) {
2086             if (addr < -0x8000 || addr >= 0x8000) {
2087                 error("*** Label out of range for short branch ***");
2088             }
2089             zcode_holding_area[i] = (addr >> 8) & 0xFF;
2090             zcode_holding_area[i+1] = (addr) & 0xFF;
2091         }
2092         else {
2093             zcode_holding_area[i] = (addr >> 24) & 0xFF;
2094             zcode_holding_area[i+1] = (addr >> 16) & 0xFF;
2095             zcode_holding_area[i+2] = (addr >> 8) & 0xFF;
2096             zcode_holding_area[i+3] = (addr) & 0xFF;
2097         }
2098         transfer_byte(zcode_holding_area + i); new_pc++;
2099       }
2100       else if (zcode_markers[i] == LABEL_MV) {
2101           error("*** No LABEL opcodes in Glulx ***");
2102       }
2103       else if (zcode_markers[i] == DELETED_MV) {
2104         /* skip it */
2105       }
2106       else {
2107         switch(zcode_markers[i] & 0x7f) {
2108         case NULL_MV: 
2109             break;
2110         case ACTION_MV:
2111         case IDENT_MV:
2112             if (!module_switch) break;
2113         case OBJECT_MV:
2114         case VARIABLE_MV:
2115         default:
2116             if ((zcode_markers[i] & 0x7f) > LARGEST_BPATCH_MV) {
2117                 error("*** Illegal code backpatch value ***");
2118                 printf("Illegal value of %02x at PC = %04x\n",
2119                 zcode_markers[i] & 0x7f, new_pc);
2120                 break;
2121             }
2122           /* The backpatch table format for Glulx:
2123              First, the marker byte (0..LARGEST_BPATCH_MV).
2124              Then a byte indicating the data size to be patched (1, 2, 4).
2125              Then the four-byte address (new_pc).
2126           */
2127           write_byte_to_memory_block(&zcode_backpatch_table,
2128             zcode_backpatch_size++,
2129             zcode_markers[i]);
2130           write_byte_to_memory_block(&zcode_backpatch_table,
2131             zcode_backpatch_size++,
2132             4);
2133           write_byte_to_memory_block(&zcode_backpatch_table,
2134             zcode_backpatch_size++, ((new_pc >> 24) & 0xFF));
2135           write_byte_to_memory_block(&zcode_backpatch_table,
2136             zcode_backpatch_size++, ((new_pc >> 16) & 0xFF));
2137           write_byte_to_memory_block(&zcode_backpatch_table,
2138             zcode_backpatch_size++, ((new_pc >> 8) & 0xFF));
2139           write_byte_to_memory_block(&zcode_backpatch_table,
2140             zcode_backpatch_size++, (new_pc & 0xFF));
2141           break;
2142         }
2143         transfer_byte(zcode_holding_area + i); new_pc++;
2144       }
2145     }
2146
2147     if (asm_trace_level >= 3)
2148     {   printf("After branch optimisation, routine length is %d bytes\n",
2149              new_pc - rstart_pc);
2150     }
2151
2152     zmachine_pc = adjusted_pc;
2153     zcode_ha_size = 0;
2154 }
2155
2156
2157 /* ========================================================================= */
2158 /*   Front ends for the instruction assembler: convenient shorthand forms    */
2159 /*   used in various code generation routines all over Inform.               */
2160 /* ------------------------------------------------------------------------- */
2161
2162 void assemble_jump(int n)
2163 {
2164     if (!glulx_mode)
2165         assemblez_jump(n);
2166     else
2167         assembleg_jump(n);
2168 }
2169
2170 void assemblez_0(int internal_number)
2171 {   AI.internal_number = internal_number;
2172     AI.operand_count = 0;
2173     AI.store_variable_number = -1;
2174     AI.branch_label_number = -1;
2175     assemblez_instruction(&AI);
2176 }
2177
2178 void assemblez_0_to(int internal_number, assembly_operand o)
2179 {   AI.internal_number = internal_number;
2180     AI.operand_count = 0;
2181     AI.store_variable_number = o.value;
2182     AI.branch_label_number = -1;
2183     assemblez_instruction(&AI);
2184 }
2185
2186 void assemblez_0_branch(int internal_number, int label, int flag)
2187 {   AI.internal_number = internal_number;
2188     AI.operand_count = 0;
2189     AI.store_variable_number = -1;
2190     AI.branch_label_number = label;
2191     AI.branch_flag = flag;
2192     assemblez_instruction(&AI);
2193 }
2194
2195 void assemblez_1(int internal_number, assembly_operand o1)
2196 {   AI.internal_number = internal_number;
2197     AI.operand_count = 1;
2198     AI.operand[0] = o1;
2199     AI.store_variable_number = -1;
2200     AI.branch_label_number = -1;
2201     assemblez_instruction(&AI);
2202 }
2203
2204 void assemblez_1_to(int internal_number,
2205     assembly_operand o1, assembly_operand st)
2206 {   AI.internal_number = internal_number;
2207     AI.operand_count = 1;
2208     AI.operand[0] = o1;
2209     AI.store_variable_number = st.value;
2210     AI.branch_label_number = -1;
2211     assemblez_instruction(&AI);
2212 }
2213
2214 void assemblez_1_branch(int internal_number,
2215     assembly_operand o1, int label, int flag)
2216 {   AI.internal_number = internal_number;
2217     AI.operand_count = 1;
2218     AI.operand[0] = o1;
2219     AI.branch_label_number = label;
2220     AI.store_variable_number = -1;
2221     AI.branch_flag = flag;
2222     assemblez_instruction(&AI);
2223 }
2224
2225 void assemblez_2(int internal_number,
2226     assembly_operand o1, assembly_operand o2)
2227 {   AI.internal_number = internal_number;
2228     AI.operand_count = 2;
2229     AI.operand[0] = o1;
2230     AI.operand[1] = o2;
2231     AI.store_variable_number = -1;
2232     AI.branch_label_number = -1;
2233     assemblez_instruction(&AI);
2234 }
2235
2236 void assemblez_3(int internal_number,
2237     assembly_operand o1, assembly_operand o2, assembly_operand o3)
2238 {   AI.internal_number = internal_number;
2239     AI.operand_count = 3;
2240     AI.operand[0] = o1;
2241     AI.operand[1] = o2;
2242     AI.operand[2] = o3;
2243     AI.store_variable_number = -1;
2244     AI.branch_label_number = -1;
2245     assemblez_instruction(&AI);
2246 }
2247
2248 void assemblez_3_to(int internal_number,
2249     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2250     assembly_operand st)
2251 {   AI.internal_number = internal_number;
2252     AI.operand_count = 3;
2253     AI.operand[0] = o1;
2254     AI.operand[1] = o2;
2255     AI.operand[2] = o3;
2256     AI.store_variable_number = st.value;
2257     AI.branch_label_number = -1;
2258     assemblez_instruction(&AI);
2259 }
2260
2261 void assemblez_3_branch(int internal_number,
2262     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2263     int label, int flag)
2264 {   AI.internal_number = internal_number;
2265     AI.operand_count = 3;
2266     AI.operand[0] = o1;
2267     AI.operand[1] = o2;
2268     AI.operand[2] = o3;
2269     AI.store_variable_number = -1;
2270     AI.branch_label_number = label;
2271     AI.branch_flag = flag;
2272     assemblez_instruction(&AI);
2273 }
2274
2275 void assemblez_4(int internal_number,
2276     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2277     assembly_operand o4)
2278 {   AI.internal_number = internal_number;
2279     AI.operand_count = 4;
2280     AI.operand[0] = o1;
2281     AI.operand[1] = o2;
2282     AI.operand[2] = o3;
2283     AI.operand[3] = o4;
2284     AI.store_variable_number = -1;
2285     AI.branch_label_number = -1;
2286     assemblez_instruction(&AI);
2287 }
2288
2289 void assemblez_5(int internal_number,
2290     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2291     assembly_operand o4, assembly_operand o5)
2292 {   AI.internal_number = internal_number;
2293     AI.operand_count = 5;
2294     AI.operand[0] = o1;
2295     AI.operand[1] = o2;
2296     AI.operand[2] = o3;
2297     AI.operand[3] = o4;
2298     AI.operand[4] = o5;
2299     AI.store_variable_number = -1;
2300     AI.branch_label_number = -1;
2301     assemblez_instruction(&AI);
2302 }
2303
2304 void assemblez_6(int internal_number,
2305     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2306     assembly_operand o4, assembly_operand o5, assembly_operand o6)
2307 {   AI.internal_number = internal_number;
2308     AI.operand_count = 6;
2309     AI.operand[0] = o1;
2310     AI.operand[1] = o2;
2311     AI.operand[2] = o3;
2312     AI.operand[3] = o4;
2313     AI.operand[4] = o5;
2314     AI.operand[5] = o6;
2315     AI.store_variable_number = -1;
2316     AI.branch_label_number = -1;
2317     assemblez_instruction(&AI);
2318 }
2319
2320 void assemblez_4_branch(int internal_number,
2321     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2322     assembly_operand o4, int label, int flag)
2323 {   AI.internal_number = internal_number;
2324     AI.operand_count = 4;
2325     AI.operand[0] = o1;
2326     AI.operand[1] = o2;
2327     AI.operand[2] = o3;
2328     AI.operand[3] = o4;
2329     AI.store_variable_number = -1;
2330     AI.branch_label_number = label;
2331     AI.branch_flag = flag;
2332     assemblez_instruction(&AI);
2333 }
2334
2335 void assemblez_4_to(int internal_number,
2336     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2337     assembly_operand o4, assembly_operand st)
2338 {   AI.internal_number = internal_number;
2339     AI.operand_count = 4;
2340     AI.operand[0] = o1;
2341     AI.operand[1] = o2;
2342     AI.operand[2] = o3;
2343     AI.operand[3] = o4;
2344     AI.store_variable_number = st.value;
2345     AI.branch_label_number = -1;
2346     assemblez_instruction(&AI);
2347 }
2348
2349 void assemblez_5_to(int internal_number,
2350     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2351     assembly_operand o4, assembly_operand o5, assembly_operand st)
2352 {   AI.internal_number = internal_number;
2353     AI.operand_count = 5;
2354     AI.operand[0] = o1;
2355     AI.operand[1] = o2;
2356     AI.operand[2] = o3;
2357     AI.operand[3] = o4;
2358     AI.operand[4] = o5;
2359     AI.store_variable_number = st.value;
2360     AI.branch_label_number = -1;
2361     assemblez_instruction(&AI);
2362 }
2363
2364 void assemblez_2_to(int internal_number,
2365     assembly_operand o1, assembly_operand o2, assembly_operand st)
2366 {   AI.internal_number = internal_number;
2367     AI.operand_count = 2;
2368     AI.operand[0] = o1;
2369     AI.operand[1] = o2;
2370     AI.store_variable_number = st.value;
2371     AI.branch_label_number = -1;
2372     assemblez_instruction(&AI);
2373 }
2374
2375 void assemblez_2_branch(int internal_number,
2376     assembly_operand o1, assembly_operand o2, int label, int flag)
2377 {   AI.internal_number = internal_number;
2378     AI.operand_count = 2;
2379     AI.operand[0] = o1;
2380     AI.operand[1] = o2;
2381     AI.branch_label_number = label;
2382     AI.store_variable_number = -1;
2383     AI.branch_flag = flag;
2384     assemblez_instruction(&AI);
2385 }
2386
2387 void assemblez_objcode(int internal_number,
2388     assembly_operand o1, assembly_operand st, int label, int flag)
2389 {   AI.internal_number = internal_number;
2390     AI.operand_count = 1;
2391     AI.operand[0] = o1;
2392     AI.branch_label_number = label;
2393     AI.store_variable_number = st.value;
2394     AI.branch_flag = flag;
2395     assemblez_instruction(&AI);
2396 }
2397
2398 extern void assemblez_inc(assembly_operand o1)
2399 {   int m = 0;
2400     if ((o1.value >= MAX_LOCAL_VARIABLES) 
2401         && (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
2402             m = VARIABLE_MV;
2403     AI.internal_number = inc_zc;
2404     AI.operand_count = 1;
2405     AI.operand[0].value = o1.value;
2406     AI.operand[0].type = SHORT_CONSTANT_OT;
2407     AI.operand[0].marker = m;
2408     AI.store_variable_number = -1;
2409     AI.branch_label_number = -1;
2410     assemblez_instruction(&AI);
2411 }
2412
2413 extern void assemblez_dec(assembly_operand o1)
2414 {   int m = 0;
2415     if ((o1.value >= MAX_LOCAL_VARIABLES) 
2416         && (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
2417             m = VARIABLE_MV;
2418     AI.internal_number = dec_zc;
2419     AI.operand_count = 1;
2420     AI.operand[0].value = o1.value;
2421     AI.operand[0].type = SHORT_CONSTANT_OT;
2422     AI.operand[0].marker = m;
2423     AI.store_variable_number = -1;
2424     AI.branch_label_number = -1;
2425     assemblez_instruction(&AI);
2426 }
2427
2428 extern void assemblez_store(assembly_operand o1, assembly_operand o2)
2429 {   int m = 0;
2430     if ((o1.value >= MAX_LOCAL_VARIABLES)
2431         && (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
2432             m = VARIABLE_MV;
2433
2434     if ((o2.type == VARIABLE_OT) && (o2.value == 0))
2435     {
2436         /*  Assemble "pull VAR" rather than "store VAR sp",
2437             saving 1 byte  */
2438
2439         AI.internal_number = pull_zc;
2440         if (instruction_set_number == 6)
2441         {   AI.operand_count = 0;
2442             AI.store_variable_number = o1.value;
2443         }
2444         else
2445         {   AI.operand_count = 1;
2446             AI.operand[0].value = o1.value;
2447             AI.operand[0].type = SHORT_CONSTANT_OT;
2448             AI.operand[0].marker = m;
2449             AI.store_variable_number = -1;
2450         }
2451         AI.branch_label_number = -1;
2452         assemblez_instruction(&AI);
2453         return;
2454     }
2455
2456     if ((o1.type == VARIABLE_OT) && (o1.value == 0))
2457     {   /*  Assemble "push VAR" rather than "store sp VAR",
2458             saving 1 byte  */
2459
2460         AI.internal_number = push_zc;
2461         AI.operand_count = 1;
2462         AI.operand[0] = o2;
2463         AI.store_variable_number = -1;
2464         AI.branch_label_number = -1;
2465         assemblez_instruction(&AI);
2466         return;
2467     }
2468     AI.internal_number = store_zc;
2469     AI.operand_count = 2;
2470     AI.operand[0].value = o1.value;
2471     AI.operand[0].type = SHORT_CONSTANT_OT;
2472     AI.operand[0].marker = m;
2473     AI.operand[1] = o2;
2474     AI.store_variable_number = -1;
2475     AI.branch_label_number = -1;
2476     assemblez_instruction(&AI);
2477 }
2478
2479 void assemblez_jump(int n)
2480 {   assembly_operand AO;
2481     if (n==-4) assemblez_0(rtrue_zc);
2482     else if (n==-3) assemblez_0(rfalse_zc);
2483     else
2484     {   AO.type = LONG_CONSTANT_OT; AO.value = n; AO.marker = 0;
2485         assemblez_1(jump_zc, AO);
2486     }
2487 }
2488
2489 void assembleg_0(int internal_number)
2490 {   AI.internal_number = internal_number;
2491     AI.operand_count = 0;
2492     assembleg_instruction(&AI);
2493 }
2494
2495 void assembleg_1(int internal_number, assembly_operand o1)
2496 {   AI.internal_number = internal_number;
2497     AI.operand_count = 1;
2498     AI.operand[0] = o1;
2499     assembleg_instruction(&AI);
2500 }
2501
2502 void assembleg_2(int internal_number, assembly_operand o1,
2503   assembly_operand o2)
2504 {   AI.internal_number = internal_number;
2505     AI.operand_count = 2;
2506     AI.operand[0] = o1;
2507     AI.operand[1] = o2;
2508     assembleg_instruction(&AI);
2509 }
2510
2511 void assembleg_3(int internal_number, assembly_operand o1,
2512   assembly_operand o2, assembly_operand o3)
2513 {   AI.internal_number = internal_number;
2514     AI.operand_count = 3;
2515     AI.operand[0] = o1;
2516     AI.operand[1] = o2;
2517     AI.operand[2] = o3;
2518     assembleg_instruction(&AI);
2519 }
2520
2521 void assembleg_4(int internal_number, assembly_operand o1,
2522   assembly_operand o2, assembly_operand o3,
2523   assembly_operand o4)
2524 {   AI.internal_number = internal_number;
2525     AI.operand_count = 4;
2526     AI.operand[0] = o1;
2527     AI.operand[1] = o2;
2528     AI.operand[2] = o3;
2529     AI.operand[3] = o4;
2530     assembleg_instruction(&AI);
2531 }
2532
2533 void assembleg_5(int internal_number, assembly_operand o1,
2534   assembly_operand o2, assembly_operand o3,
2535   assembly_operand o4, assembly_operand o5)
2536 {   AI.internal_number = internal_number;
2537     AI.operand_count = 5;
2538     AI.operand[0] = o1;
2539     AI.operand[1] = o2;
2540     AI.operand[2] = o3;
2541     AI.operand[3] = o4;
2542     AI.operand[4] = o5;
2543     assembleg_instruction(&AI);
2544 }
2545
2546 void assembleg_0_branch(int internal_number,
2547     int label)
2548 {
2549     AI.internal_number = internal_number;
2550     AI.operand_count = 1;
2551     AI.operand[0].type = CONSTANT_OT;
2552     AI.operand[0].value = label;
2553     AI.operand[0].marker = BRANCH_MV;
2554     assembleg_instruction(&AI);
2555 }
2556
2557 void assembleg_1_branch(int internal_number,
2558     assembly_operand o1, int label)
2559 {
2560     /* Some clever optimizations first. A constant is always or never equal
2561        to zero. */
2562     if (o1.marker == 0 && is_constant_ot(o1.type)) {
2563         if ((internal_number == jz_gc && o1.value == 0)
2564           || (internal_number == jnz_gc && o1.value != 0)) {
2565             assembleg_0_branch(jump_gc, label);
2566             /* We clear the "can't reach statement" flag here, 
2567                so that "if (1)" doesn't produce that warning. */
2568             execution_never_reaches_here = 0;
2569             return;
2570         }
2571         if ((internal_number == jz_gc && o1.value != 0)
2572           || (internal_number == jnz_gc && o1.value == 0)) {
2573             /* assemble nothing at all! */
2574             return;
2575         }
2576     }
2577     AI.internal_number = internal_number;
2578     AI.operand_count = 2;
2579     AI.operand[0] = o1;
2580     AI.operand[1].type = CONSTANT_OT;
2581     AI.operand[1].value = label;
2582     AI.operand[1].marker = BRANCH_MV;
2583     assembleg_instruction(&AI);
2584 }
2585
2586 void assembleg_2_branch(int internal_number,
2587     assembly_operand o1, assembly_operand o2, int label)
2588 {
2589     AI.internal_number = internal_number;
2590     AI.operand_count = 3;
2591     AI.operand[0] = o1;
2592     AI.operand[1] = o2;
2593     AI.operand[2].type = CONSTANT_OT;
2594     AI.operand[2].value = label;
2595     AI.operand[2].marker = BRANCH_MV;
2596     assembleg_instruction(&AI);
2597 }
2598
2599 void assembleg_call_1(assembly_operand oaddr, assembly_operand o1, 
2600   assembly_operand odest)
2601 {
2602   assembleg_3(callfi_gc, oaddr, o1, odest);
2603 }
2604
2605 void assembleg_call_2(assembly_operand oaddr, assembly_operand o1, 
2606   assembly_operand o2, assembly_operand odest)
2607 {
2608   assembleg_4(callfii_gc, oaddr, o1, o2, odest);
2609 }
2610
2611 void assembleg_call_3(assembly_operand oaddr, assembly_operand o1, 
2612   assembly_operand o2, assembly_operand o3, assembly_operand odest)
2613 {
2614   assembleg_5(callfiii_gc, oaddr, o1, o2, o3, odest);
2615 }
2616
2617 void assembleg_inc(assembly_operand o1)
2618 {
2619   AI.internal_number = add_gc;
2620   AI.operand_count = 3;
2621   AI.operand[0] = o1;
2622   AI.operand[1] = one_operand;
2623   AI.operand[2] = o1;
2624   assembleg_instruction(&AI);
2625 }
2626
2627 void assembleg_dec(assembly_operand o1)
2628 {
2629   AI.internal_number = sub_gc;
2630   AI.operand_count = 3;
2631   AI.operand[0] = o1;
2632   AI.operand[1] = one_operand;
2633   AI.operand[2] = o1;
2634   assembleg_instruction(&AI);
2635 }
2636
2637 void assembleg_store(assembly_operand o1, assembly_operand o2)
2638 {
2639     /* Note the order is reversed: "o1 = o2;" */
2640     assembleg_2(copy_gc, o2, o1);
2641 }
2642
2643 void assembleg_jump(int n)
2644 {
2645   if (n==-4) {
2646       assembleg_1(return_gc, one_operand);
2647   }
2648   else if (n==-3) {
2649       assembleg_1(return_gc, zero_operand); 
2650   }
2651   else {
2652       assembleg_0_branch(jump_gc, n);
2653   }
2654 }
2655
2656 /* ========================================================================= */
2657 /*   Parsing and then calling the assembler for @ (assembly language)        */
2658 /*   statements                                                              */
2659 /* ------------------------------------------------------------------------- */
2660
2661 static assembly_operand parse_operand_z(void)
2662 {   assembly_operand AO;
2663
2664     AO = parse_expression(ASSEMBLY_CONTEXT);
2665     if (AO.type == EXPRESSION_OT)
2666     {   ebf_error("variable or constant", "expression");
2667         AO.type = SHORT_CONSTANT_OT;
2668     }
2669     return(AO);
2670 }
2671
2672 static void parse_assembly_z(void)
2673 {   int n, min, max, indirect_addressed, error_flag = FALSE;
2674     opcodez O;
2675
2676     AI.operand_count = 0;
2677     AI.store_variable_number = -1;
2678     AI.branch_label_number = -1;
2679     AI.text = NULL;
2680
2681     opcode_names.enabled = TRUE;
2682     get_next_token();
2683     opcode_names.enabled = FALSE;
2684
2685     if (token_type == DQ_TT)
2686     {   int i;
2687         AI.internal_number = -1;
2688
2689         custom_opcode_z.name = (uchar *) token_text;
2690         custom_opcode_z.version1 = instruction_set_number;
2691         custom_opcode_z.version2 = instruction_set_number;
2692         custom_opcode_z.extension = -1;
2693         custom_opcode_z.flags = 0;
2694         custom_opcode_z.op_rules = 0;
2695         custom_opcode_z.flags2_set = 0;
2696         custom_opcode_z.no = ZERO;
2697
2698         for (i=0; token_text[i]!=0; i++)
2699         {   if (token_text[i] == ':')
2700             {   token_text[i++] = 0;
2701                 break;
2702             }
2703         }
2704         if (token_text[i] == 0)
2705             error("Opcode specification should have form \"VAR:102\"");
2706
2707         n = -1;
2708         if (strcmp(token_text, "0OP")==0)      n=ZERO;
2709         if (strcmp(token_text, "1OP")==0)      n=ONE;
2710         if (strcmp(token_text, "2OP")==0)      n=TWO;
2711         if (strcmp(token_text, "VAR")==0)      n=VAR;
2712         if (strcmp(token_text, "EXT")==0)      n=EXT;
2713         if (strcmp(token_text, "VAR_LONG")==0) n=VAR_LONG;
2714         if (strcmp(token_text, "EXT_LONG")==0) n=EXT_LONG;
2715
2716         if (i>0) token_text[i-1] = ':';
2717
2718         if (n==-1)
2719         {   ebf_error("Expected 0OP, 1OP, 2OP, VAR, EXT, VAR_LONG or EXT_LONG",
2720                 token_text);
2721             n = EXT;
2722         }
2723         custom_opcode_z.no = n;
2724
2725         custom_opcode_z.code = atoi(token_text+i);
2726         while (isdigit(token_text[i])) i++;
2727
2728         {   max = 0; min = 0;
2729             switch(n)
2730             {   case ZERO: case ONE: max = 16; break;
2731                 case VAR: case VAR_LONG: min = 32; max = 64; break;
2732                 case EXT: case EXT_LONG: max = 256; break;
2733                 case TWO: max = 32; break;
2734             }
2735             if ((custom_opcode_z.code < min) || (custom_opcode_z.code >= max))
2736             {   char range[32];
2737                 sprintf(range, "%d to %d", min, max-1);
2738             error_named("For this operand type, opcode number must be in range",
2739                     range);
2740                 custom_opcode_z.code = min;
2741             }
2742         }
2743
2744         while (token_text[i++] != 0)
2745         {   switch(token_text[i-1])
2746             {   case 'B': custom_opcode_z.flags |= Br; break;
2747                 case 'S': custom_opcode_z.flags |= St; break;
2748                 case 'T': custom_opcode_z.op_rules = TEXT; break;
2749                 case 'I': custom_opcode_z.op_rules = VARIAB; break;
2750                 case 'F': custom_opcode_z.flags2_set = atoi(token_text+i);
2751                           while (isdigit(token_text[i])) i++; break;
2752                 default:
2753                     error("Unknown flag: options are B (branch), S (store), \
2754 T (text), I (indirect addressing), F** (set this Flags 2 bit)");
2755                     break;
2756             }
2757         }
2758         O = custom_opcode_z;
2759     }
2760     else
2761     {   if (token_type != OPCODE_NAME_TT)
2762         {   ebf_error("an opcode name", token_text);
2763             panic_mode_error_recovery();
2764             return;
2765         }
2766         AI.internal_number = token_value;
2767         O = internal_number_to_opcode_z(AI.internal_number);
2768     }
2769
2770     indirect_addressed = (O.op_rules == VARIAB);
2771
2772     if (O.op_rules == TEXT)
2773     {   get_next_token();
2774         if (token_type != DQ_TT)
2775             ebf_error("literal text in double-quotes", token_text);
2776         AI.text = token_text;
2777         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
2778         get_next_token();
2779         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
2780         {   assemblez_instruction(&AI);
2781             return;
2782         }
2783         ebf_error("semicolon ';' after print string", token_text);
2784         put_token_back();
2785         return;
2786     }
2787
2788     return_sp_as_variable = TRUE;
2789     do
2790     {   get_next_token();
2791
2792         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
2793
2794         if ((token_type == SEP_TT) && (token_value == ARROW_SEP))
2795         {   if (AI.store_variable_number != -1)
2796                 error("Only one '->' store destination can be given");
2797             get_next_token();
2798             if ((token_type != SYMBOL_TT)
2799                 && (token_type != LOCAL_VARIABLE_TT))
2800                 ebf_error("variable name or 'sp'", token_text);
2801             n = 255;
2802             if (token_type == LOCAL_VARIABLE_TT) n = token_value;
2803             else
2804             {   if (strcmp(token_text, "sp") == 0) n = 0;
2805                 else
2806                 {   if (stypes[token_value] != GLOBAL_VARIABLE_T)
2807                         error_named(
2808                             "Store '->' destination not 'sp' or a variable:",
2809                             token_text);
2810                     else n = svals[token_value];
2811                 }
2812             }
2813             AI.store_variable_number = n;
2814             continue;
2815         }
2816
2817         if ((token_type == SEP_TT) &&
2818             ((token_value == BRANCH_SEP) || (token_value == NBRANCH_SEP)))
2819         {   if (AI.branch_label_number != -1)
2820                 error("Only one '?' branch destination can be given");
2821
2822             AI.branch_flag = (token_value == BRANCH_SEP);
2823
2824             opcode_names.enabled = TRUE;
2825             get_next_token();
2826             opcode_names.enabled = FALSE;
2827
2828             n = -2;
2829             if ((token_type == OPCODE_NAME_TT)
2830                 && (token_value == rfalse_zc)) n = -3;
2831             else
2832             if ((token_type == OPCODE_NAME_TT)
2833                 && (token_value == rtrue_zc)) n = -4;
2834             else
2835             {   if (token_type == SYMBOL_TT)
2836                 {   put_token_back();
2837                     n = parse_label();
2838                 }
2839                 else
2840                     ebf_error("label name after '?' or '?~'", token_text);
2841             }
2842             AI.branch_label_number = n;
2843             continue;
2844         }
2845
2846         if (AI.operand_count == 8)
2847         {   error("No assembly instruction may have more than 8 operands");
2848             panic_mode_error_recovery(); break;
2849         }
2850
2851         if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
2852         {   if (!indirect_addressed)
2853                 error("This opcode does not use indirect addressing");
2854             if (AI.operand_count > 0)
2855             error("Indirect addressing can only be used on the first operand");
2856             AI.operand[AI.operand_count++] = parse_operand_z();
2857             get_next_token();
2858             if (!((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP)))
2859             {   ebf_error("']'", token_text);
2860                 put_token_back();
2861             }
2862         }
2863         else
2864         {   put_token_back();
2865             AI.operand[AI.operand_count++] = parse_operand_z();
2866             if ((indirect_addressed) && (AI.operand_count == 1)
2867                 && (AI.operand[AI.operand_count-1].type == VARIABLE_OT))
2868             {   AI.operand[AI.operand_count-1].type = SHORT_CONSTANT_OT;
2869                 AI.operand[AI.operand_count-1].marker = VARIABLE_MV;
2870             }
2871         }
2872
2873     } while (TRUE);
2874
2875     return_sp_as_variable = FALSE;
2876
2877
2878     if (O.version1 == 0)
2879     {   error_named("Opcode unavailable in this Z-machine version:",
2880             opcode_names.keywords[AI.internal_number]);
2881         return;
2882     }
2883
2884     if (((O.flags) & Br) != 0)
2885     {   if (AI.branch_label_number == -1)
2886         {   error_flag = TRUE;
2887             AI.branch_label_number = -2;
2888         }
2889     }
2890     else
2891     {   if (AI.branch_label_number != -1)
2892         {   error_flag = TRUE;
2893             AI.branch_label_number = -1;
2894         }
2895     }
2896     if (((O.flags) & St) != 0)
2897     {   if (AI.store_variable_number == -1)
2898         {   if (AI.operand_count == 0)
2899             {   error_flag = TRUE;
2900                 AI.store_variable_number = 255;
2901             }
2902             else
2903             {   AI.store_variable_number
2904                     = AI.operand[--AI.operand_count].value;
2905                 if (AI.operand[AI.operand_count].type != VARIABLE_OT)
2906             error("Store destination (the last operand) is not a variable");
2907             }
2908         }
2909     }
2910     else
2911     {   if (AI.store_variable_number != -1)
2912         {   error_flag = TRUE;
2913             AI.store_variable_number = -1;
2914         }
2915     }
2916
2917     min = 0; max = 0;
2918     switch(O.no)
2919     {   case TWO:      min = 2; max = 2;
2920                        /* Exception for the V6 set_colour, which can take
2921                           a third argument, thus forcing it into VAR form: */
2922                        if ((version_number == 6) && (O.code == 0x1b)) max = 3;
2923                        /* Also an exception for je, which can take from 1
2924                           argument (useless) to 4 arguments */
2925                        if (O.code == 0x01) { min = 1; max = 4; }
2926                        break;
2927         case VAR:      min = 0; max = 4; break;
2928         case VAR_LONG: min = 0; max = 8; break;
2929         case ONE:      min = 1; max = 1; break;
2930         case ZERO:     min = 0; max = 0; break;
2931         case EXT:      min = 0; max = 4; break;
2932         case EXT_LONG: min = 0; max = 8; break;
2933     }
2934
2935     if ((AI.operand_count >= min) && (AI.operand_count <= max))
2936         assemblez_instruction(&AI);
2937     else error_flag = TRUE;
2938
2939     if (error_flag)
2940     {   make_opcode_syntax_z(O);
2941         error_named("Assembly mistake: syntax is",
2942             opcode_syntax_string);
2943     }
2944 }
2945
2946 static assembly_operand parse_operand_g(void)
2947 {   assembly_operand AO;
2948
2949     AO = parse_expression(ASSEMBLY_CONTEXT);
2950     if (AO.type == EXPRESSION_OT)
2951     {   ebf_error("variable or constant", "expression");
2952         AO.type = CONSTANT_OT;
2953     }
2954     return(AO);
2955 }
2956
2957 static void parse_assembly_g(void)
2958 {
2959   opcodeg O;
2960   assembly_operand AO;
2961   int error_flag = FALSE, is_macro = FALSE;
2962
2963   AI.operand_count = 0;
2964
2965   opcode_names.enabled = TRUE;
2966   opcode_macros.enabled = TRUE;
2967   get_next_token();
2968   opcode_names.enabled = FALSE;
2969   opcode_macros.enabled = FALSE;
2970
2971   if (token_type == DQ_TT) {
2972     char *cx;
2973     int badflags;
2974
2975     AI.internal_number = -1;
2976
2977     /* The format is @"FlagsCount:Code". Flags (which are optional)
2978        can include "S" for store, "SS" for two stores, "B" for branch
2979        format, "R" if execution never continues after the opcode. The
2980        Count is the number of arguments (currently limited to 0-9),
2981        and the Code is a decimal integer representing the opcode
2982        number.
2983
2984        So: @"S3:123" for a three-argument opcode (load, load, store)
2985        whose opcode number is (decimal) 123. Or: @"2:234" for a
2986        two-argument opcode (load, load) whose number is 234. */
2987
2988     custom_opcode_g.name = (uchar *) token_text;
2989     custom_opcode_g.flags = 0;
2990     custom_opcode_g.op_rules = 0;
2991     custom_opcode_g.no = 0;
2992
2993     badflags = FALSE;
2994
2995     for (cx = token_text; *cx && *cx != ':'; cx++) {
2996       if (badflags)
2997       continue;
2998
2999       switch (*cx) {
3000       case 'S':
3001       if (custom_opcode_g.flags & St)
3002         custom_opcode_g.flags |= St2;
3003       else
3004         custom_opcode_g.flags |= St;
3005       break;
3006       case 'B':
3007       custom_opcode_g.flags |= Br;
3008       break;
3009       case 'R':
3010       custom_opcode_g.flags |= Rf;
3011       break;
3012       default:
3013       if (isdigit(*cx)) {
3014         custom_opcode_g.no = (*cx) - '0';
3015         break;
3016       }
3017       badflags = TRUE;
3018       error("Unknown custom opcode flag: options are B (branch), \
3019 S (store), SS (two stores), R (execution never continues)");
3020       break;
3021       }
3022     }
3023
3024     if (*cx != ':') {
3025       error("Custom opcode must have colon");
3026     }
3027     else {
3028       cx++;
3029       if (!(*cx))
3030       error("Custom opcode must have colon followed by opcode number");
3031       else
3032       custom_opcode_g.code = atoi(cx);
3033     }
3034
3035     O = custom_opcode_g;
3036   }
3037   else {
3038     if (token_type != OPCODE_NAME_TT && token_type != OPCODE_MACRO_TT) {
3039       ebf_error("an opcode name", token_text);
3040       panic_mode_error_recovery();
3041       return;
3042     }
3043     AI.internal_number = token_value;
3044     if (token_type == OPCODE_MACRO_TT) {
3045       O = internal_number_to_opmacro_g(AI.internal_number);
3046       is_macro = TRUE;
3047     }
3048     else
3049       O = internal_number_to_opcode_g(AI.internal_number);
3050   }
3051   
3052   return_sp_as_variable = TRUE;
3053
3054   while (1) {
3055     get_next_token();
3056     
3057     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) 
3058       break;
3059
3060     if (AI.operand_count == 8) {
3061       error("No assembly instruction may have more than 8 operands");
3062       panic_mode_error_recovery(); 
3063       break;
3064     }
3065
3066     if ((O.flags & Br) && (AI.operand_count == O.no-1)) {
3067       if (!((token_type == SEP_TT) && (token_value == BRANCH_SEP))) {
3068         error_flag = TRUE;
3069         error("Branch opcode must have '?' label");
3070         put_token_back();
3071       }
3072       AO.type = CONSTANT_OT;
3073       AO.value = parse_label();
3074       AO.marker = BRANCH_MV;
3075     }
3076     else {
3077       put_token_back();
3078       AO = parse_operand_g();
3079     }
3080
3081     AI.operand[AI.operand_count] = AO;
3082     AI.operand_count++;
3083   }
3084
3085   return_sp_as_variable = FALSE;
3086
3087   if (O.no != AI.operand_count) {
3088     error_flag = TRUE;
3089   }
3090
3091   if (!error_flag) {
3092     if (is_macro)
3093       assembleg_macro(&AI);
3094     else
3095       assembleg_instruction(&AI);
3096   }
3097
3098   if (error_flag) {
3099     make_opcode_syntax_g(O);
3100     error_named("Assembly mistake: syntax is",
3101       opcode_syntax_string);
3102   }
3103 }
3104
3105 extern void parse_assembly(void)
3106 {
3107   if (!glulx_mode)
3108     parse_assembly_z();
3109   else
3110     parse_assembly_g();
3111 }
3112
3113 /* ========================================================================= */
3114 /*   Data structure management routines                                      */
3115 /* ------------------------------------------------------------------------- */
3116
3117 extern void asm_begin_pass(void)
3118 {   no_instructions = 0;
3119     zmachine_pc = 0;
3120     no_sequence_points = 0;
3121     next_label = 0;
3122     next_sequence_point = 0;
3123     zcode_ha_size = 0;
3124 }
3125
3126 extern void init_asm_vars(void)
3127 {   int i;
3128
3129     for (i=0;i<16;i++) flags2_requirements[i]=0;
3130
3131     uses_unicode_features = FALSE;
3132     uses_memheap_features = FALSE;
3133     uses_acceleration_features = FALSE;
3134     uses_float_features = FALSE;
3135
3136     sequence_point_follows = TRUE;
3137     label_moved_error_already_given = FALSE;
3138
3139     initialise_memory_block(&zcode_area);
3140 }
3141
3142 extern void asm_allocate_arrays(void)
3143 {   if ((debugfile_switch) && (MAX_LABELS < 2000)) MAX_LABELS = 2000;
3144
3145     variable_tokens = my_calloc(sizeof(int32),  
3146         MAX_LOCAL_VARIABLES+MAX_GLOBAL_VARIABLES, "variable tokens");
3147     variable_usage = my_calloc(sizeof(int),  
3148         MAX_LOCAL_VARIABLES+MAX_GLOBAL_VARIABLES, "variable usage");
3149
3150     label_offsets = my_calloc(sizeof(int32), MAX_LABELS, "label offsets");
3151     label_symbols = my_calloc(sizeof(int32), MAX_LABELS, "label symbols");
3152     label_next = my_calloc(sizeof(int), MAX_LABELS, "label dll 1");
3153     label_prev = my_calloc(sizeof(int), MAX_LABELS, "label dll 1");
3154     sequence_point_labels
3155         = my_calloc(sizeof(int), MAX_LABELS, "sequence point labels");
3156     sequence_point_locations
3157         = my_calloc(sizeof(debug_location),
3158                     MAX_LABELS,
3159                     "sequence point locations");
3160
3161     zcode_holding_area = my_malloc(MAX_ZCODE_SIZE,"compiled routine code area");
3162     zcode_markers = my_malloc(MAX_ZCODE_SIZE, "compiled routine code area");
3163
3164     named_routine_symbols
3165         = my_calloc(sizeof(int32), MAX_SYMBOLS, "named routine symbols");
3166 }
3167
3168 extern void asm_free_arrays(void)
3169 {
3170     my_free(&variable_tokens, "variable tokens");
3171     my_free(&variable_usage, "variable usage");
3172
3173     my_free(&label_offsets, "label offsets");
3174     my_free(&label_symbols, "label symbols");
3175     my_free(&label_next, "label dll 1");
3176     my_free(&label_prev, "label dll 2");
3177     my_free(&sequence_point_labels, "sequence point labels");
3178     my_free(&sequence_point_locations, "sequence point locations");
3179
3180     my_free(&zcode_holding_area, "compiled routine code area");
3181     my_free(&zcode_markers, "compiled routine code markers");
3182
3183     my_free(&named_routine_symbols, "named routine symbols");
3184     deallocate_memory_block(&zcode_area);
3185 }
3186
3187 /* ========================================================================= */