1
/* ------------------------------------------------------------------------- */
2
/* "asm" : The Inform assembler */
4
/* Part of Inform 6.30 */
5
/* copyright (c) Graham Nelson 1993 - 2004 */
7
/* ------------------------------------------------------------------------- */
11
uchar *zcode_holding_area; /* Area holding code yet to be transferred
12
to either zcode_area or temp file no 1 */
13
uchar *zcode_markers; /* Bytes holding marker values for this
15
static int zcode_ha_size; /* Number of bytes in holding area */
17
memory_block zcode_area; /* Block to hold assembled code (if
18
temporary files are not being used) */
20
int32 zmachine_pc; /* PC position of assembly (byte offset
21
from start of Z-code area) */
23
int32 no_instructions; /* Number of instructions assembled */
24
int execution_never_reaches_here, /* TRUE if the current PC value in the
25
code area cannot be reached: e.g. if
26
the previous instruction was a "quit"
27
opcode and no label is set to here */
28
next_label, /* Used to count the labels created all
29
over Inform in current routine, from 0 */
30
next_sequence_point; /* Likewise, for sequence points */
31
int no_sequence_points; /* Kept for statistics purposes only */
33
static int label_moved_error_already_given;
34
/* When one label has moved, all subsequent
35
ones probably have too, and this flag
36
suppresses the runaway chain of error
37
messages which would otherwise result */
39
int sequence_point_follows; /* Will the next instruction assembled */
40
/* be at a sequence point in the routine? */
42
dbgl debug_line_ref; /* Source code ref of current statement */
45
int32 *variable_tokens; /* The allocated size is
46
(MAX_LOCAL_VARIABLES +
47
MAX_GLOBAL_VARIABLES). The entries
48
MAX_LOCAL_VARIABLES and up give the
49
symbol table index for the names of
50
the global variables */
51
int *variable_usage; /* TRUE if referred to, FALSE otherwise */
53
assembly_instruction AI; /* A structure used to hold the full
54
specification of a single Z-code
55
instruction: effectively this is the
57
assemble_instruction() */
59
static char opcode_syntax_string[128]; /* Text buffer holding the correct
60
syntax for an opcode: used to produce
61
helpful assembler error messages */
63
static int routine_locals; /* The number of local variables used by
64
the routine currently being compiled */
66
static int32 routine_start_pc;
68
int32 *named_routine_symbols;
70
static void transfer_routine_z(void);
71
static void transfer_routine_g(void);
73
/* ------------------------------------------------------------------------- */
75
/* ------------------------------------------------------------------------- */
77
static int first_label, last_label;
78
static int32 *label_offsets; /* Double-linked list of label offsets */
79
static int *label_next, /* (i.e. zmachine_pc values) in PC order */
81
static int32 *label_symbols; /* Symbol numbers if defined in source */
83
static int *sequence_point_labels; /* Label numbers for each */
84
static dbgl *sequence_point_refs; /* Source code references for each */
85
/* (used for making debugging file) */
87
static void set_label_offset(int label, int32 offset)
89
if (label >= MAX_LABELS) memoryerror("MAX_LABELS", MAX_LABELS);
91
label_offsets[label] = offset;
93
{ label_prev[label] = -1;
97
{ label_prev[label] = last_label;
98
label_next[last_label] = label;
101
label_next[label] = -1;
102
label_symbols[label] = -1;
105
/* ------------------------------------------------------------------------- */
106
/* Useful tool for building operands */
107
/* ------------------------------------------------------------------------- */
109
extern void set_constant_ot(assembly_operand *AO)
112
if (AO->value >= 0 && AO->value <= 255)
113
AO->type = SHORT_CONSTANT_OT;
115
AO->type = LONG_CONSTANT_OT;
119
AO->type = ZEROCONSTANT_OT;
120
else if (AO->value >= -0x80 && AO->value < 0x80)
121
AO->type = BYTECONSTANT_OT;
122
else if (AO->value >= -0x8000 && AO->value < 0x8000)
123
AO->type = HALFCONSTANT_OT;
125
AO->type = CONSTANT_OT;
129
extern int is_constant_ot(int otval)
132
return ((otval == LONG_CONSTANT_OT)
133
|| (otval == SHORT_CONSTANT_OT));
136
return ((otval == CONSTANT_OT)
137
|| (otval == HALFCONSTANT_OT)
138
|| (otval == BYTECONSTANT_OT)
139
|| (otval == ZEROCONSTANT_OT));
143
extern int is_variable_ot(int otval)
146
return (otval == VARIABLE_OT);
149
return ((otval == LOCALVAR_OT)
150
|| (otval == GLOBALVAR_OT));
154
/* ------------------------------------------------------------------------- */
155
/* Used in printing assembly traces */
156
/* ------------------------------------------------------------------------- */
158
extern char *variable_name(int32 i)
160
if (i==0) return("sp");
161
if (i<MAX_LOCAL_VARIABLES) return local_variable_texts[i-1];
164
if (i==255) return("TEMP1");
165
if (i==254) return("TEMP2");
166
if (i==253) return("TEMP3");
167
if (i==252) return("TEMP4");
168
if (i==251) return("self");
169
if (i==250) return("sender");
170
if (i==249) return("sw__var");
173
switch (i - MAX_LOCAL_VARIABLES) {
174
case 0: return "temp_global";
175
case 1: return "temp__global2";
176
case 2: return "temp__global3";
177
case 3: return "temp__global4";
178
case 4: return "self";
179
case 5: return "sender";
180
case 6: return "sw__var";
181
case 7: return "sys__glob0";
182
case 8: return "sys__glob1";
183
case 9: return "sys__glob2";
184
case 10: return "sys_statusline_flag";
188
return ((char *) symbs[variable_tokens[i]]);
191
static void print_operand_z(assembly_operand o)
193
{ case EXPRESSION_OT: printf("expr_"); break;
194
case LONG_CONSTANT_OT: printf("long_"); break;
195
case SHORT_CONSTANT_OT: printf("short_"); break;
197
if (o.value==0) { printf("sp"); return; }
198
printf("%s", variable_name(o.value)); return;
199
case OMITTED_OT: printf("<no value>"); return;
201
printf("%d", o.value);
204
static void print_operand_g(assembly_operand o)
207
case EXPRESSION_OT: printf("expr_"); break;
208
case CONSTANT_OT: printf("long_"); break;
209
case HALFCONSTANT_OT: printf("short_"); break;
210
case BYTECONSTANT_OT: printf("byte_"); break;
211
case ZEROCONSTANT_OT: printf("zero_"); return;
212
case DEREFERENCE_OT: printf("*"); break;
214
printf("%s (global_%d)", variable_name(o.value), o.value);
220
printf("%s (local_%d)", variable_name(o.value), o.value-1);
222
case SYSFUN_OT: printf("sysfun_"); break;
223
case OMITTED_OT: printf("<no value>"); return;
224
/* case STACK_OT: printf("<sp>"); return; */
225
default: printf("???_"); break;
227
printf("%d", o.value);
230
extern void print_operand(assembly_operand o)
238
/* ------------------------------------------------------------------------- */
239
/* Writing bytes to the code area */
240
/* ------------------------------------------------------------------------- */
242
static void byteout(int32 i, int mv)
243
{ if (zcode_ha_size >= MAX_ZCODE_SIZE)
244
memoryerror("MAX_ZCODE_SIZE",MAX_ZCODE_SIZE);
245
zcode_markers[zcode_ha_size] = (uchar) mv;
246
zcode_holding_area[zcode_ha_size++] = (uchar) i;
250
/* ------------------------------------------------------------------------- */
251
/* A database of the 115 canonical Infocom opcodes in Versions 3 to 6 */
252
/* And of the however-many-there-are Glulx opcode */
253
/* ------------------------------------------------------------------------- */
255
typedef struct opcodez
256
{ uchar *name; /* Lower case standard name */
257
int version1; /* Valid from this version number... */
258
int version2; /* ...until this one (or forever if this is 0) */
259
int extension; /* In later versions, see this line in extension table:
260
if -1, the opcode is illegal in later versions */
261
int code; /* Opcode number within its operand-number block */
262
int flags; /* Flags (see below) */
263
int op_rules; /* Any unusual operand rule applying (see below) */
264
int flags2_set; /* If not zero, set this bit in Flags 2 in the header
265
of any game using the opcode */
266
int no; /* Number of operands (see below) */
269
typedef struct opcodeg
270
{ uchar *name; /* Lower case standard name */
271
int32 code; /* Opcode number */
272
int flags; /* Flags (see below) */
273
int op_rules; /* Any unusual operand rule applying (see below) */
274
int no; /* Number of operands */
277
/* Flags which can be set */
279
#define St 1 /* Store */
280
#define Br 2 /* Branch */
281
#define Rf 4 /* "Return flag": execution never continues after this
282
opcode (e.g., is a return or unconditional jump) */
283
#define St2 8 /* Store2 (second-to-last operand is store (Glulx)) */
285
/* Codes for any unusual operand assembly rules */
287
#define VARIAB 1 /* First operand expected to be a variable name and
288
assembled to a short constant: the variable number */
289
#define TEXT 2 /* One text operand, to be Z-encoded into the program */
290
#define LABEL 3 /* One operand, a label, given as long constant offset */
291
#define CALL 4 /* First operand is name of a routine, to be assembled
292
as long constant (the routine's packed address):
293
as if the name were prefixed by #r$ */
295
/* Codes for the number of operands */
297
#define TWO 1 /* 2 (with certain types of operand, compiled as VAR) */
298
#define VAR 2 /* 0 to 4 */
299
#define VAR_LONG 3 /* 0 to 8 */
300
#define ONE 4 /* 1 */
301
#define ZERO 5 /* 0 */
302
#define EXT 6 /* Extended opcode set VAR: 0 to 4 */
303
#define EXT_LONG 7 /* Extended: 0 to 8 (not used by the canonical opcodes) */
305
static opcodez opcodes_table_z[] =
307
/* Opcodes introduced in Version 3 */
309
/* 0 */ { (uchar *) "je", 3, 0, -1, 0x01, Br, 0, 0, TWO },
310
/* 1 */ { (uchar *) "jl", 3, 0, -1, 0x02, Br, 0, 0, TWO },
311
/* 2 */ { (uchar *) "jg", 3, 0, -1, 0x03, Br, 0, 0, TWO },
312
/* 3 */ { (uchar *) "dec_chk", 3, 0, -1, 0x04, Br, VARIAB, 0, TWO },
313
/* 4 */ { (uchar *) "inc_chk", 3, 0, -1, 0x05, Br, VARIAB, 0, TWO },
314
/* 5 */ { (uchar *) "jin", 3, 0, -1, 0x06, Br, 0, 0, TWO },
315
/* 6 */ { (uchar *) "test", 3, 0, -1, 0x07, Br, 0, 0, TWO },
316
/* 7 */ { (uchar *) "or", 3, 0, -1, 0x08, St, 0, 0, TWO },
317
/* 8 */ { (uchar *) "and", 3, 0, -1, 0x09, St, 0, 0, TWO },
318
/* 9 */ { (uchar *) "test_attr", 3, 0, -1, 0x0A, Br, 0, 0, TWO },
319
/* 10 */ {(uchar *) "set_attr", 3, 0, -1, 0x0B, 0, 0, 0, TWO },
320
/* 11 */ {(uchar *) "clear_attr", 3, 0, -1, 0x0C, 0, 0, 0, TWO },
321
/* 12 */ {(uchar *) "store", 3, 0, -1, 0x0D, 0, VARIAB, 0, TWO },
322
/* 13 */ {(uchar *) "insert_obj", 3, 0, -1, 0x0E, 0, 0, 0, TWO },
323
/* 14 */ {(uchar *) "loadw", 3, 0, -1, 0x0F, St, 0, 0, TWO },
324
/* 15 */ {(uchar *) "loadb", 3, 0, -1, 0x10, St, 0, 0, TWO },
325
/* 16 */ {(uchar *) "get_prop", 3, 0, -1, 0x11, St, 0, 0, TWO },
326
/* 17 */ {(uchar *) "get_prop_addr", 3, 0, -1, 0x12, St, 0, 0, TWO },
327
/* 18 */ {(uchar *) "get_next_prop", 3, 0, -1, 0x13, St, 0, 0, TWO },
328
/* 19 */ {(uchar *) "add", 3, 0, -1, 0x14, St, 0, 0, TWO },
329
/* 20 */ {(uchar *) "sub", 3, 0, -1, 0x15, St, 0, 0, TWO },
330
/* 21 */ {(uchar *) "mul", 3, 0, -1, 0x16, St, 0, 0, TWO },
331
/* 22 */ {(uchar *) "div", 3, 0, -1, 0x17, St, 0, 0, TWO },
332
/* 23 */ {(uchar *) "mod", 3, 0, -1, 0x18, St, 0, 0, TWO },
333
/* 24 */ {(uchar *) "call", 3, 0, -1, 0x20, St, CALL, 0, VAR },
334
/* 25 */ {(uchar *) "storew", 3, 0, -1, 0x21, 0, 0, 0, VAR },
335
/* 26 */ {(uchar *) "storeb", 3, 0, -1, 0x22, 0, 0, 0, VAR },
336
/* 27 */ {(uchar *) "put_prop", 3, 0, -1, 0x23, 0, 0, 0, VAR },
337
/* This is the version of "read" called "sread" internally: */
338
/* 28 */ {(uchar *) "read", 3, 0, -1, 0x24, 0, 0, 0, VAR },
339
/* 29 */ {(uchar *) "print_char", 3, 0, -1, 0x25, 0, 0, 0, VAR },
340
/* 30 */ {(uchar *) "print_num", 3, 0, -1, 0x26, 0, 0, 0, VAR },
341
/* 31 */ {(uchar *) "random", 3, 0, -1, 0x27, St, 0, 0, VAR },
342
/* 32 */ {(uchar *) "push", 3, 0, -1, 0x28, 0, 0, 0, VAR },
343
/* 33 */ {(uchar *) "pull", 3, 5, 6, 0x29, 0, VARIAB, 0, VAR },
344
/* 34 */ {(uchar *) "split_window", 3, 0, -1, 0x2A, 0, 0, 0, VAR },
345
/* 35 */ {(uchar *) "set_window", 3, 0, -1, 0x2B, 0, 0, 0, VAR },
346
/* 36 */ {(uchar *) "output_stream", 3, 0, -1, 0x33, 0, 0, 0, VAR },
347
/* 37 */ {(uchar *) "input_stream", 3, 0, -1, 0x34, 0, 0, 0, VAR },
348
/* 38 */ {(uchar *) "sound_effect", 3, 0, -1, 0x35, 0, 0, 7, VAR },
349
/* 39 */ {(uchar *) "jz", 3, 0, -1, 0x00, Br, 0, 0, ONE },
350
/* 40 */ {(uchar *) "get_sibling", 3, 0, -1, 0x01, St+Br, 0, 0, ONE },
351
/* 41 */ {(uchar *) "get_child", 3, 0, -1, 0x02, St+Br, 0, 0, ONE },
352
/* 42 */ {(uchar *) "get_parent", 3, 0, -1, 0x03, St, 0, 0, ONE },
353
/* 43 */ {(uchar *) "get_prop_len", 3, 0, -1, 0x04, St, 0, 0, ONE },
354
/* 44 */ {(uchar *) "inc", 3, 0, -1, 0x05, 0, VARIAB, 0, ONE },
355
/* 45 */ {(uchar *) "dec", 3, 0, -1, 0x06, 0, VARIAB, 0, ONE },
356
/* 46 */ {(uchar *) "print_addr", 3, 0, -1, 0x07, 0, 0, 0, ONE },
357
/* 47 */ {(uchar *) "remove_obj", 3, 0, -1, 0x09, 0, 0, 0, ONE },
358
/* 48 */ {(uchar *) "print_obj", 3, 0, -1, 0x0A, 0, 0, 0, ONE },
359
/* 49 */ {(uchar *) "ret", 3, 0, -1, 0x0B, Rf, 0, 0, ONE },
360
/* 50 */ {(uchar *) "jump", 3, 0, -1, 0x0C, Rf, LABEL, 0, ONE },
361
/* 51 */ {(uchar *) "print_paddr", 3, 0, -1, 0x0D, 0, 0, 0, ONE },
362
/* 52 */ {(uchar *) "load", 3, 0, -1, 0x0E, St, VARIAB, 0, ONE },
363
/* 53 */ {(uchar *) "not", 3, 3, 0, 0x0F, St, 0, 0, ONE },
364
/* 54 */ {(uchar *) "rtrue", 3, 0, -1, 0x00, Rf, 0, 0,ZERO },
365
/* 55 */ {(uchar *) "rfalse", 3, 0, -1, 0x01, Rf, 0, 0,ZERO },
366
/* 56 */ {(uchar *) "print", 3, 0, -1, 0x02, 0, TEXT, 0,ZERO },
367
/* 57 */ {(uchar *) "print_ret", 3, 0, -1, 0x03, Rf, TEXT, 0,ZERO },
368
/* 58 */ {(uchar *) "nop", 3, 0, -1, 0x04, 0, 0, 0,ZERO },
369
/* 59 */ {(uchar *) "save", 3, 3, 1, 0x05, Br, 0, 0,ZERO },
370
/* 60 */ {(uchar *) "restore", 3, 3, 2, 0x06, Br, 0, 0,ZERO },
371
/* 61 */ {(uchar *) "restart", 3, 0, -1, 0x07, 0, 0, 0,ZERO },
372
/* 62 */ {(uchar *) "ret_popped", 3, 0, -1, 0x08, Rf, 0, 0,ZERO },
373
/* 63 */ {(uchar *) "pop", 3, 4, -1, 0x09, 0, 0, 0,ZERO },
374
/* 64 */ {(uchar *) "quit", 3, 0, -1, 0x0A, Rf, 0, 0,ZERO },
375
/* 65 */ {(uchar *) "new_line", 3, 0, -1, 0x0B, 0, 0, 0,ZERO },
376
/* 66 */ {(uchar *) "show_status", 3, 3, -1, 0x0C, 0, 0, 0,ZERO },
377
/* 67 */ {(uchar *) "verify", 3, 0, -1, 0x0D, Br, 0, 0,ZERO },
379
/* Opcodes introduced in Version 4 */
381
/* 68 */ {(uchar *) "call_2s", 4, 0, -1, 0x19, St, CALL, 0, TWO },
382
/* 69 */ {(uchar *) "call_vs", 4, 0, -1, 0x20, St, CALL, 0, VAR },
383
/* This is the version of "read" called "aread" internally: */
384
/* 70 */ {(uchar *) "read", 4, 0, -1, 0x24, St, 0, 0, VAR },
385
/* 71 */ {(uchar *) "call_vs2", 4, 0, -1, 0x2C, St, CALL, 0,
387
/* 72 */ {(uchar *) "erase_window", 4, 0, -1, 0x2D, 0, 0, 0, VAR },
388
/* 73 */ {(uchar *) "erase_line", 4, 0, -1, 0x2E, 0, 0, 0, VAR },
389
/* 74 */ {(uchar *) "set_cursor", 4, 0, -1, 0x2F, 0, 0, 0, VAR },
390
/* 75 */ {(uchar *) "get_cursor", 4, 0, -1, 0x30, 0, 0, 0, VAR },
391
/* 76 */ {(uchar *) "set_text_style", 4, 0, -1, 0x31, 0, 0, 0, VAR },
392
/* 77 */ {(uchar *) "buffer_mode", 4, 0, -1, 0x32, 0, 0, 0, VAR },
393
/* 78 */ {(uchar *) "read_char", 4, 0, -1, 0x36, St, 0, 0, VAR },
394
/* 79 */ {(uchar *) "scan_table", 4, 0, -1, 0x37, St+Br, 0, 0, VAR },
395
/* 80 */ {(uchar *) "call_1s", 4, 0, -1, 0x08, St, CALL, 0, ONE },
397
/* Opcodes introduced in Version 5 */
399
/* 81 */ {(uchar *) "call_2n", 5, 0, -1, 0x1a, 0, CALL, 0, TWO },
400
/* 82 */ {(uchar *) "set_colour", 5, 0, -1, 0x1b, 0, 0, 6, TWO },
401
/* 83 */ {(uchar *) "throw", 5, 0, -1, 0x1c, 0, 0, 0, TWO },
402
/* 84 */ {(uchar *) "call_vn", 5, 0, -1, 0x39, 0, CALL, 0, VAR },
403
/* 85 */ {(uchar *) "call_vn2", 5, 0, -1, 0x3a, 0, CALL, 0,
405
/* 86 */ {(uchar *) "tokenise", 5, 0, -1, 0x3b, 0, 0, 0, VAR },
406
/* 87 */ {(uchar *) "encode_text", 5, 0, -1, 0x3c, 0, 0, 0, VAR },
407
/* 88 */ {(uchar *) "copy_table", 5, 0, -1, 0x3d, 0, 0, 0, VAR },
408
/* 89 */ {(uchar *) "print_table", 5, 0, -1, 0x3e, 0, 0, 0, VAR },
409
/* 90 */ {(uchar *) "check_arg_count", 5, 0, -1, 0x3f, Br, 0, 0, VAR },
410
/* 91 */ {(uchar *) "call_1n", 5, 0, -1, 0x0F, 0, CALL, 0, ONE },
411
/* 92 */ {(uchar *) "catch", 5, 0, -1, 0x09, St, 0, 0, ZERO },
412
/* 93 */ {(uchar *) "piracy", 5, 0, -1, 0x0F, Br, 0, 0, ZERO },
413
/* 94 */ {(uchar *) "log_shift", 5, 0, -1, 0x02, St, 0, 0, EXT },
414
/* 95 */ {(uchar *) "art_shift", 5, 0, -1, 0x03, St, 0, 0, EXT },
415
/* 96 */ {(uchar *) "set_font", 5, 0, -1, 0x04, St, 0, 0, EXT },
416
/* 97 */ {(uchar *) "save_undo", 5, 0, -1, 0x09, St, 0, 4, EXT },
417
/* 98 */ {(uchar *) "restore_undo", 5, 0, -1, 0x0A, St, 0, 4, EXT },
419
/* Opcodes introduced in Version 6 */
421
/* 99 */ { (uchar *) "draw_picture", 6, 6, -1, 0x05, 0, 0, 3, EXT },
422
/* 100 */ { (uchar *) "picture_data", 6, 6, -1, 0x06, Br, 0, 3, EXT },
423
/* 101 */ { (uchar *) "erase_picture", 6, 6, -1, 0x07, 0, 0, 3, EXT },
424
/* 102 */ { (uchar *) "set_margins", 6, 6, -1, 0x08, 0, 0, 0, EXT },
425
/* 103 */ { (uchar *) "move_window", 6, 6, -1, 0x10, 0, 0, 0, EXT },
426
/* 104 */ { (uchar *) "window_size", 6, 6, -1, 0x11, 0, 0, 0, EXT },
427
/* 105 */ { (uchar *) "window_style", 6, 6, -1, 0x12, 0, 0, 0, EXT },
428
/* 106 */ { (uchar *) "get_wind_prop", 6, 6, -1, 0x13, St, 0, 0, EXT },
429
/* 107 */ { (uchar *) "scroll_window", 6, 6, -1, 0x14, 0, 0, 0, EXT },
430
/* 108 */ { (uchar *) "pop_stack", 6, 6, -1, 0x15, 0, 0, 0, EXT },
431
/* 109 */ { (uchar *) "read_mouse", 6, 6, -1, 0x16, 0, 0, 5, EXT },
432
/* 110 */ { (uchar *) "mouse_window", 6, 6, -1, 0x17, 0, 0, 5, EXT },
433
/* 111 */ { (uchar *) "push_stack", 6, 6, -1, 0x18, Br, 0, 0, EXT },
434
/* 112 */ { (uchar *) "put_wind_prop", 6, 6, -1, 0x19, 0, 0, 0, EXT },
435
/* 113 */ { (uchar *) "print_form", 6, 6, -1, 0x1a, 0, 0, 0, EXT },
436
/* 114 */ { (uchar *) "make_menu", 6, 6, -1, 0x1b, Br, 0, 8, EXT },
437
/* 115 */ { (uchar *) "picture_table", 6, 6, -1, 0x1c, 0, 0, 3, EXT },
439
/* Opcodes introduced in Z-Machine Specification Standard 1.0 */
441
/* 116 */ { (uchar *) "print_unicode", 5, 0, -1, 0x0b, 0, 0, 0, EXT },
442
/* 117 */ { (uchar *) "check_unicode", 5, 0, -1, 0x0c, St, 0, 0, EXT }
445
/* Subsequent forms for opcodes whose meaning changes with version */
447
static opcodez extension_table_z[] =
449
/* 0 */ { (uchar *) "not", 4, 4, 3, 0x0F, St, 0, 0, ONE },
450
/* 1 */ { (uchar *) "save", 4, 4, 4, 0x05, St, 0, 0,ZERO },
451
/* 2 */ { (uchar *) "restore", 4, 4, 5, 0x06, St, 0, 0,ZERO },
452
/* 3 */ { (uchar *) "not", 5, 0, -1, 0x38, St, 0, 0, VAR },
453
/* 4 */ { (uchar *) "save", 5, 0, -1, 0x00, St, 0, 0, EXT },
454
/* 5 */ { (uchar *) "restore", 5, 0, -1, 0x01, St, 0, 0, EXT },
455
/* 6 */ { (uchar *) "pull", 6, 6, -1, 0x29, St, 0, 0, VAR }
458
static opcodez invalid_opcode_z =
459
{ (uchar *) "invalid", 0, 0, -1, 0xff, 0, 0, 0, ZERO};
461
static opcodez custom_opcode_z;
463
/* Note that this table assumes that all opcodes have at most two
464
branch-label or store operands, and that if they exist, they are the
465
last operands. Glulx does not actually guarantee this. But it is
466
true for all opcodes in the current Glulx spec, so we will assume
469
Also note that Inform can only compile branches to constant offsets,
470
even though the Glulx machine can handle stack or memory-loaded
471
operands in a branch instruction.
474
static opcodeg opcodes_table_g[] = {
475
{ (uchar *) "nop", 0x00, 0, 0, 0 },
476
{ (uchar *) "add", 0x10, St, 0, 3 },
477
{ (uchar *) "sub", 0x11, St, 0, 3 },
478
{ (uchar *) "mul", 0x12, St, 0, 3 },
479
{ (uchar *) "div", 0x13, St, 0, 3 },
480
{ (uchar *) "mod", 0x14, St, 0, 3 },
481
{ (uchar *) "neg", 0x15, St, 0, 2 },
482
{ (uchar *) "bitand", 0x18, St, 0, 3 },
483
{ (uchar *) "bitor", 0x19, St, 0, 3 },
484
{ (uchar *) "bitxor", 0x1A, St, 0, 3 },
485
{ (uchar *) "bitnot", 0x1B, St, 0, 2 },
486
{ (uchar *) "shiftl", 0x1C, St, 0, 3 },
487
{ (uchar *) "sshiftr", 0x1D, St, 0, 3 },
488
{ (uchar *) "ushiftr", 0x1E, St, 0, 3 },
489
{ (uchar *) "jump", 0x20, Br|Rf, 0, 1 },
490
{ (uchar *) "jz", 0x22, Br, 0, 2 },
491
{ (uchar *) "jnz", 0x23, Br, 0, 2 },
492
{ (uchar *) "jeq", 0x24, Br, 0, 3 },
493
{ (uchar *) "jne", 0x25, Br, 0, 3 },
494
{ (uchar *) "jlt", 0x26, Br, 0, 3 },
495
{ (uchar *) "jge", 0x27, Br, 0, 3 },
496
{ (uchar *) "jgt", 0x28, Br, 0, 3 },
497
{ (uchar *) "jle", 0x29, Br, 0, 3 },
498
{ (uchar *) "jltu", 0x2A, Br, 0, 3 },
499
{ (uchar *) "jgeu", 0x2B, Br, 0, 3 },
500
{ (uchar *) "jgtu", 0x2C, Br, 0, 3 },
501
{ (uchar *) "jleu", 0x2D, Br, 0, 3 },
502
{ (uchar *) "call", 0x30, St, 0, 3 },
503
{ (uchar *) "return", 0x31, Rf, 0, 1 },
504
{ (uchar *) "catch", 0x32, Br|St, 0, 2 },
505
{ (uchar *) "throw", 0x33, Rf, 0, 2 },
506
{ (uchar *) "tailcall", 0x34, Rf, 0, 2 },
507
{ (uchar *) "copy", 0x40, St, 0, 2 },
508
{ (uchar *) "copys", 0x41, St, 0, 2 },
509
{ (uchar *) "copyb", 0x42, St, 0, 2 },
510
{ (uchar *) "sexs", 0x44, St, 0, 2 },
511
{ (uchar *) "sexb", 0x45, St, 0, 2 },
512
{ (uchar *) "aload", 0x48, St, 0, 3 },
513
{ (uchar *) "aloads", 0x49, St, 0, 3 },
514
{ (uchar *) "aloadb", 0x4A, St, 0, 3 },
515
{ (uchar *) "aloadbit", 0x4B, St, 0, 3 },
516
{ (uchar *) "astore", 0x4C, 0, 0, 3 },
517
{ (uchar *) "astores", 0x4D, 0, 0, 3 },
518
{ (uchar *) "astoreb", 0x4E, 0, 0, 3 },
519
{ (uchar *) "astorebit", 0x4F, 0, 0, 3 },
520
{ (uchar *) "stkcount", 0x50, St, 0, 1 },
521
{ (uchar *) "stkpeek", 0x51, St, 0, 2 },
522
{ (uchar *) "stkswap", 0x52, 0, 0, 0 },
523
{ (uchar *) "stkroll", 0x53, 0, 0, 2 },
524
{ (uchar *) "stkcopy", 0x54, 0, 0, 1 },
525
{ (uchar *) "streamchar", 0x70, 0, 0, 1 },
526
{ (uchar *) "streamnum", 0x71, 0, 0, 1 },
527
{ (uchar *) "streamstr", 0x72, 0, 0, 1 },
528
{ (uchar *) "gestalt", 0x0100, St, 0, 3 },
529
{ (uchar *) "debugtrap", 0x0101, 0, 0, 1 },
530
{ (uchar *) "getmemsize", 0x0102, St, 0, 1 },
531
{ (uchar *) "setmemsize", 0x0103, St, 0, 2 },
532
{ (uchar *) "jumpabs", 0x0104, Rf, 0, 1 },
533
{ (uchar *) "random", 0x0110, St, 0, 2 },
534
{ (uchar *) "setrandom", 0x0111, 0, 0, 1 },
535
{ (uchar *) "quit", 0x0120, Rf, 0, 0 },
536
{ (uchar *) "verify", 0x0121, St, 0, 1 },
537
{ (uchar *) "restart", 0x0122, 0, 0, 0 },
538
{ (uchar *) "save", 0x0123, St, 0, 2 },
539
{ (uchar *) "restore", 0x0124, St, 0, 2 },
540
{ (uchar *) "saveundo", 0x0125, St, 0, 1 },
541
{ (uchar *) "restoreundo", 0x0126, St, 0, 1 },
542
{ (uchar *) "protect", 0x0127, 0, 0, 2 },
543
{ (uchar *) "glk", 0x0130, St, 0, 3 },
544
{ (uchar *) "getstringtbl", 0x0140, St, 0, 1 },
545
{ (uchar *) "setstringtbl", 0x0141, 0, 0, 1 },
546
{ (uchar *) "getiosys", 0x0148, St|St2, 0, 2 },
547
{ (uchar *) "setiosys", 0x0149, 0, 0, 2 },
548
{ (uchar *) "linearsearch", 0x0150, St, 0, 8 },
549
{ (uchar *) "binarysearch", 0x0151, St, 0, 8 },
550
{ (uchar *) "linkedsearch", 0x0152, St, 0, 7 },
551
{ (uchar *) "callf", 0x0160, St, 0, 2 },
552
{ (uchar *) "callfi", 0x0161, St, 0, 3 },
553
{ (uchar *) "callfii", 0x0162, St, 0, 4 },
554
{ (uchar *) "callfiii", 0x0163, St, 0, 5 },
557
static opcodeg custom_opcode_g;
559
static opcodez internal_number_to_opcode_z(int32 i)
562
if (i == -1) return custom_opcode_z;
563
x = opcodes_table_z[i];
564
if (instruction_set_number < x.version1) return invalid_opcode_z;
565
if (x.version2 == 0) return x;
566
if (instruction_set_number <= x.version2) return x;
568
x = extension_table_z[i];
569
if (instruction_set_number < x.version1) return invalid_opcode_z;
570
if (x.version2 == 0) return x;
571
if (instruction_set_number <= x.version2) return x;
572
return extension_table_z[x.extension];
575
static void make_opcode_syntax_z(opcodez opco)
576
{ char *p = "", *q = opcode_syntax_string;
577
sprintf(q, "%s", opco.name);
579
{ case ONE: p=" <operand>"; break;
580
case TWO: p=" <operand1> <operand2>"; break;
582
case VAR: p=" <0 to 4 operands>"; break;
583
case VAR_LONG: p=" <0 to 8 operands>"; break;
585
switch(opco.op_rules)
586
{ case TEXT: sprintf(q+strlen(q), " <text>"); return;
587
case LABEL: sprintf(q+strlen(q), " <label>"); return;
589
sprintf(q+strlen(q), " <variable>");
591
if (opco.op_rules==CALL) sprintf(q+strlen(q), " <routine>");
593
{ case ONE: p=""; break;
594
case TWO: p=" <operand>"; break;
596
case VAR: p=" <1 to 4 operands>"; break;
597
case VAR_LONG: p=" <1 to 8 operands>"; break;
601
sprintf(q+strlen(q), "%s", p);
602
if ((opco.flags & St) != 0) sprintf(q+strlen(q), " -> <result-variable>");
603
if ((opco.flags & Br) != 0) sprintf(q+strlen(q), " ?[~]<label>");
606
static opcodeg internal_number_to_opcode_g(int32 i)
609
if (i == -1) return custom_opcode_g;
610
x = opcodes_table_g[i];
614
static void make_opcode_syntax_g(opcodeg opco)
618
char *q = opcode_syntax_string;
620
sprintf(q, "%s", opco.name);
621
sprintf(q+strlen(q), " <%d operand%s", opco.no,
622
((opco.no==1) ? "" : "s"));
627
for (ix=0; ix<opco.no; ix++) {
632
if (ix == opco.no-1) {
633
if (opco.flags & Br) {
636
else if (opco.flags & St) {
643
else if (ix == opco.no-2 && (opco.flags & Br) && (opco.flags & St)) {
646
else if (ix == opco.no-2 && (opco.flags & St2)) {
653
sprintf(cx, "%d", ix+1);
657
sprintf(q+strlen(q), ">");
661
/* ========================================================================= */
662
/* The assembler itself does four things: */
664
/* assembles instructions */
665
/* sets label N to the current code position */
666
/* assembles routine headers */
667
/* assembles routine ends */
668
/* ------------------------------------------------------------------------- */
670
/* This is for Z-code only. */
671
static void write_operand(assembly_operand op)
673
if (module_switch && (op.marker != 0))
674
{ if ((op.marker != VARIABLE_MV) && (op.type == SHORT_CONSTANT_OT))
675
op.type = LONG_CONSTANT_OT;
679
{ case LONG_CONSTANT_OT:
680
byteout(j/256, op.marker); byteout(j%256, 0); return;
681
case SHORT_CONSTANT_OT:
684
else byteout(j, 0x80 + op.marker); return;
686
byteout(j, (module_switch)?(0x80 + op.marker):0); return;
688
case HALFCONSTANT_OT:
689
case BYTECONSTANT_OT:
690
case ZEROCONSTANT_OT:
695
compiler_error("Glulx OT in Z-code assembly operand.");
700
extern void assemblez_instruction(assembly_instruction *AI)
702
uchar *start_pc, *operands_pc;
703
int32 offset, j, topbits, types_byte1, types_byte2;
704
int operand_rules, min, max, no_operands_given, at_seq_point = FALSE;
705
assembly_operand o1, o2;
710
offset = zmachine_pc;
714
if (veneer_mode) sequence_point_follows = FALSE;
715
if (sequence_point_follows)
716
{ sequence_point_follows = FALSE; at_seq_point = TRUE;
717
if (debugfile_switch)
718
{ sequence_point_labels[next_sequence_point] = next_label;
719
sequence_point_refs[next_sequence_point] = debug_line_ref;
720
set_label_offset(next_label++, zmachine_pc);
722
next_sequence_point++;
725
opco = internal_number_to_opcode_z(AI->internal_number);
726
if (opco.version1==0)
727
{ error_named("Opcode unavailable in this Z-machine version",
728
opcode_names.keywords[AI->internal_number]);
732
if (execution_never_reaches_here)
733
warning("This statement can never be reached");
735
operand_rules = opco.op_rules;
736
execution_never_reaches_here = ((opco.flags & Rf) != 0);
738
if (opco.flags2_set != 0) flags2_requirements[opco.flags2_set] = 1;
740
no_operands_given = AI->operand_count;
742
if ((opco.no == TWO) && ((no_operands_given==3)||(no_operands_given==4)))
745
/* 1. Write the opcode byte(s) */
747
start_pc = zcode_holding_area + zcode_ha_size;
750
{ case VAR_LONG: topbits=0xc0; min=0; max=8; break;
751
case VAR: topbits=0xc0; min=0; max=4; break;
752
case ZERO: topbits=0xb0; min=0; max=0; break;
753
case ONE: topbits=0x80; min=1; max=1; break;
754
case TWO: topbits=0x00; min=2; max=2; break;
755
case EXT: topbits=0x00; min=0; max=4;
756
byteout(0xbe, 0); opco.no=VAR; break;
757
case EXT_LONG: topbits=0x00; min=0; max=8;
758
byteout(0xbe, 0); opco.no=VAR_LONG; break;
760
byteout(opco.code + topbits, 0);
762
operands_pc = zcode_holding_area + zcode_ha_size;
764
/* 2. Dispose of the special rules LABEL and TEXT */
766
if (operand_rules==LABEL)
767
{ j = (AI->operand[0]).value;
768
byteout(j/256, LABEL_MV); byteout(j%256, 0);
769
goto Instruction_Done;
772
if (operand_rules==TEXT)
774
j = subtract_pointers(
775
(translate_text(zcode_holding_area + zcode_ha_size, AI->text)),
776
(zcode_holding_area + zcode_ha_size));
777
for (i=0; i<j; i++) zcode_markers[zcode_ha_size++] = 0;
779
goto Instruction_Done;
782
/* 3. Sort out the operands */
784
if ((no_operands_given < min) || (no_operands_given > max))
785
goto OpcodeSyntaxError;
791
if (opco.no == VAR_LONG) byteout(0, 0);
792
types_byte1=0xff; types_byte2=0xff;
793
for (j=0; j<no_operands_given; j++)
796
{ case 0: case 4: multi=0x40; mask=0xc0; break;
797
case 1: case 5: multi=0x10; mask=0x30; break;
798
case 2: case 6: multi=0x04; mask=0x0c; break;
799
case 3: case 7: multi=0x01; mask=0x03; break;
804
types_byte1 = (types_byte1 & (~mask)) + o1.type*multi;
806
types_byte2 = (types_byte2 & (~mask)) + o1.type*multi;
808
*operands_pc=types_byte1;
809
if (opco.no == VAR_LONG) *(operands_pc+1)=types_byte2;
814
*start_pc=(*start_pc) + o1.type*0x10;
822
/* Transfer to VAR form if either operand is a long constant */
824
if ((o1.type==LONG_CONSTANT_OT)||(o2.type==LONG_CONSTANT_OT))
825
{ *start_pc=(*start_pc) + 0xc0;
826
byteout(o1.type*0x40 + o2.type*0x10 + 0x0f, 0);
829
{ if (o1.type==VARIABLE_OT) *start_pc=(*start_pc) + 0x40;
830
if (o2.type==VARIABLE_OT) *start_pc=(*start_pc) + 0x20;
837
/* 4. Assemble a Store destination, if needed */
839
if ((AI->store_variable_number) != -1)
840
{ o1.type = VARIABLE_OT;
841
o1.value = AI->store_variable_number;
842
variable_usage[o1.value] = TRUE;
845
/* Note that variable numbers 249 to 255 (i.e. globals 233 to 239)
846
are used as scratch workspace, so need no mapping between
847
modules and story files: nor do local variables 0 to 15 */
849
if ((o1.value >= MAX_LOCAL_VARIABLES) && (o1.value < 249))
850
o1.marker = VARIABLE_MV;
854
/* 5. Assemble a branch, if needed */
856
if (AI->branch_label_number != -1)
857
{ int32 addr, long_form;
858
int branch_on_true = (AI->branch_flag)?1:0;
860
switch (AI->branch_label_number)
861
{ case -2: addr = 2; branch_on_true = 0; long_form = 0; break;
862
/* branch nowhere, carry on */
863
case -3: addr = 0; long_form = 0; break; /* rfalse on condition */
864
case -4: addr = 1; long_form = 0; break; /* rtrue on condition */
866
long_form = 1; addr = AI->branch_label_number;
869
if (addr > 0x7fff) fatalerror("Too many branch points in routine.");
871
{ byteout(branch_on_true*0x80 + addr/256, BRANCH_MV);
872
byteout(addr%256, 0);
875
byteout(branch_on_true*0x80+ 0x40 + (addr&0x3f), 0);
880
if ((asm_trace_level > 0) && (veneer_mode == FALSE))
882
printf("%5d +%05lx %3s %-12s ", ErrorReport.line_number,
884
(at_seq_point)?"<*>":" ", opco.name);
886
if ((AI->internal_number == print_zc)
887
|| (AI->internal_number == print_ret_zc))
889
for (i=0;(AI->text)[i]!=0 && i<35; i++) printf("%c",(AI->text)[i]);
890
if (i == 35) printf("...");
894
for (i=0; i<AI->operand_count; i++)
895
{ if ((i==0) && (opco.op_rules == VARIAB))
896
{ if ((AI->operand[0]).type == VARIABLE_OT)
897
{ printf("["); print_operand_z(AI->operand[i]); }
899
printf("%s", variable_name((AI->operand[0]).value));
902
if ((i==0) && (opco.op_rules == LABEL))
903
{ printf("L%d", AI->operand[0].value);
905
else print_operand_z(AI->operand[i]);
908
if (AI->store_variable_number != -1)
909
{ assembly_operand AO;
911
AO.type = VARIABLE_OT; AO.value = AI->store_variable_number;
912
print_operand_z(AO); printf(" ");
915
switch(AI->branch_label_number)
916
{ case -4: printf("rtrue if %s", (AI->branch_flag)?"TRUE":"FALSE");
918
case -3: printf("rfalse if %s", (AI->branch_flag)?"TRUE":"FALSE");
920
case -2: printf("(no branch)"); break;
923
printf("to L%d if %s", AI->branch_label_number,
924
(AI->branch_flag)?"TRUE":"FALSE"); break;
927
if (asm_trace_level>=2)
928
{ for (j=0;start_pc<zcode_holding_area + zcode_ha_size;
930
{ if (j%16==0) printf("\n ");
931
printf("%02x ", *start_pc);
937
if (module_switch) flush_link_data();
943
make_opcode_syntax_z(opco);
944
error_named("Assembly mistake: syntax is", opcode_syntax_string);
947
extern void assembleg_instruction(assembly_instruction *AI)
949
uchar *start_pc, *opmodes_pc;
951
int no_operands_given, at_seq_point = FALSE;
957
offset = zmachine_pc;
961
if (veneer_mode) sequence_point_follows = FALSE;
962
if (sequence_point_follows)
963
{ sequence_point_follows = FALSE; at_seq_point = TRUE;
964
if (debugfile_switch)
965
{ sequence_point_labels[next_sequence_point] = next_label;
966
sequence_point_refs[next_sequence_point] = debug_line_ref;
967
set_label_offset(next_label++, zmachine_pc);
969
next_sequence_point++;
972
opco = internal_number_to_opcode_g(AI->internal_number);
974
if (execution_never_reaches_here)
975
warning("This statement can never be reached");
977
execution_never_reaches_here = ((opco.flags & Rf) != 0);
979
no_operands_given = AI->operand_count;
981
/* 1. Write the opcode byte(s) */
983
start_pc = zcode_holding_area + zcode_ha_size;
985
if (opco.code < 0x80) {
986
byteout(opco.code, 0);
988
else if (opco.code < 0x4000) {
989
byteout(((opco.code >> 8) & 0xFF) | 0x80, 0);
990
byteout((opco.code & 0xFF), 0);
993
byteout(((opco.code >> 24) & 0xFF) | 0xC0, 0);
994
byteout(((opco.code >> 16) & 0xFF), 0);
995
byteout(((opco.code >> 8) & 0xFF), 0);
996
byteout(((opco.code) & 0xFF), 0);
999
/* ... and the operand addressing modes. There's one byte for
1000
every two operands (rounded up). We write zeroes for now;
1001
when the operands are written, we'll go back and fix them. */
1003
opmodes_pc = zcode_holding_area + zcode_ha_size;
1005
for (ix=0; ix<opco.no; ix+=2) {
1009
/* 2. Dispose of the special rules */
1010
/* There aren't any in Glulx. */
1012
/* 3. Sort out the operands */
1014
if (no_operands_given != opco.no) {
1015
goto OpcodeSyntaxError;
1018
for (ix=0; ix<no_operands_given; ix++) {
1019
int marker = AI->operand[ix].marker;
1020
int type = AI->operand[ix].type;
1021
k = AI->operand[ix].value;
1023
if ((opco.flags & Br) && (ix == no_operands_given-1)) {
1024
if (!(marker >= BRANCH_MV && marker < BRANCHMAX_MV)) {
1025
compiler_error("Assembling branch without BRANCH_MV marker");
1026
goto OpcodeSyntaxError;
1029
k = 2; /* branch no-op */
1030
type = BYTECONSTANT_OT;
1034
k = 0; /* branch return 0 */
1035
type = ZEROCONSTANT_OT;
1039
k = 1; /* branch return 1 */
1040
type = BYTECONSTANT_OT;
1044
/* branch to label k */
1045
j = subtract_pointers((zcode_holding_area + zcode_ha_size),
1048
marker = BRANCH_MV + j;
1049
if (!(marker >= BRANCH_MV && marker < BRANCHMAX_MV)) {
1050
error("*** branch marker too far from opmode byte ***");
1051
goto OpcodeSyntaxError;
1055
if ((opco.flags & St)
1056
&& ((!(opco.flags & Br) && (ix == no_operands_given-1))
1057
|| ((opco.flags & Br) && (ix == no_operands_given-2)))) {
1058
if (type == BYTECONSTANT_OT || type == HALFCONSTANT_OT
1059
|| type == CONSTANT_OT) {
1060
error("*** instruction tried to store to a constant ***");
1061
goto OpcodeSyntaxError;
1064
if ((opco.flags & St2)
1065
&& (ix == no_operands_given-2)) {
1066
if (type == BYTECONSTANT_OT || type == HALFCONSTANT_OT
1067
|| type == CONSTANT_OT) {
1068
error("*** instruction tried to store to a constant ***");
1069
goto OpcodeSyntaxError;
1073
if (marker && (type == HALFCONSTANT_OT
1074
|| type == BYTECONSTANT_OT
1075
|| type == ZEROCONSTANT_OT)) {
1076
compiler_error("Assembling marker in less than 32-bit constant.");
1077
/* Actually we should store marker|0x80 for a byte constant,
1078
but let's hold off on that. */
1082
case LONG_CONSTANT_OT:
1083
case SHORT_CONSTANT_OT:
1086
compiler_error("Z-code OT in Glulx assembly operand.");
1090
byteout((k >> 24) & 0xFF, marker);
1091
byteout((k >> 16) & 0xFF, 0);
1092
byteout((k >> 8) & 0xFF, 0);
1093
byteout((k & 0xFF), 0);
1095
case HALFCONSTANT_OT:
1097
byteout((k >> 8) & 0xFF, marker);
1098
byteout((k & 0xFF), 0);
1100
case BYTECONSTANT_OT:
1102
byteout((k & 0xFF), marker);
1104
case ZEROCONSTANT_OT:
1107
case DEREFERENCE_OT:
1109
byteout((k >> 24) & 0xFF, marker);
1110
byteout((k >> 16) & 0xFF, 0);
1111
byteout((k >> 8) & 0xFF, 0);
1112
byteout((k & 0xFF), 0);
1115
/* Global variable -- a constant address. */
1116
k -= MAX_LOCAL_VARIABLES;
1118
/* We could write the value as a marker and patch it later... */
1120
byteout(((k) >> 24) & 0xFF, VARIABLE_MV);
1121
byteout(((k) >> 16) & 0xFF, 0);
1122
byteout(((k) >> 8) & 0xFF, 0);
1123
byteout(((k) & 0xFF), 0);
1126
/* ...but it's more efficient to write it as a RAM operand,
1127
which can be 1, 2, or 4 bytes. Remember that global variables
1128
are the very first thing in RAM. */
1129
k = k * 4; /* each variable is four bytes */
1132
byteout(((k) & 0xFF), 0);
1134
else if (k <= 65535) {
1136
byteout(((k) >> 8) & 0xFF, 0);
1137
byteout(((k) & 0xFF), 0);
1141
byteout(((k) >> 24) & 0xFF, 0);
1142
byteout(((k) >> 16) & 0xFF, 0);
1143
byteout(((k) >> 8) & 0xFF, 0);
1144
byteout(((k) & 0xFF), 0);
1150
/* Stack-pointer magic variable */
1154
/* Local variable -- a byte or short offset from the
1155
frame pointer. It's an unsigned offset, so we can
1156
fit up to long 63 (offset 4*63) in a byte. */
1159
byteout((k-1)*4, 0);
1163
byteout((((k-1)*4) >> 8) & 0xFF, 0);
1164
byteout(((k-1)*4) & 0xFF, 0);
1175
opmodes_pc[ix/2] |= j;
1178
/* Print assembly trace. */
1179
if ((asm_trace_level > 0) && (veneer_mode == FALSE)) {
1181
printf("%5d +%05lx %3s %-12s ", ErrorReport.line_number,
1182
((long int) offset),
1183
(at_seq_point)?"<*>":" ", opco.name);
1184
for (i=0; i<AI->operand_count; i++) {
1185
if ((opco.flags & Br) && (i == opco.no-1)) {
1186
if (AI->operand[i].value == -4)
1188
else if (AI->operand[i].value == -3)
1189
printf("to rfalse");
1191
printf("to L%d", AI->operand[i].value);
1194
print_operand_g(AI->operand[i]);
1199
if (asm_trace_level>=2) {
1201
start_pc<zcode_holding_area + zcode_ha_size;
1203
if (j%16==0) printf("\n ");
1205
printf("%02x ", *start_pc);
1208
printf("%02x", *start_pc);
1209
if (zcode_markers[start_pc-zcode_holding_area])
1210
printf("{%02x}", zcode_markers[start_pc-zcode_holding_area]);
1218
if (module_switch) flush_link_data();
1224
make_opcode_syntax_g(opco);
1225
error_named("Assembly mistake: syntax is", opcode_syntax_string);
1228
extern void assemble_label_no(int n)
1230
if ((asm_trace_level > 0) && (veneer_mode == FALSE))
1231
printf("%5d +%05lx .L%d\n", ErrorReport.line_number,
1232
((long int) zmachine_pc), n);
1233
set_label_offset(n, zmachine_pc);
1234
execution_never_reaches_here = FALSE;
1237
extern void define_symbol_label(int symbol)
1238
{ label_symbols[svals[symbol]] = symbol;
1241
extern int32 assemble_routine_header(int no_locals,
1242
int routine_asterisked, char *name, dbgl *line_ref, int embedded_flag,
1245
int stackargs = FALSE;
1247
execution_never_reaches_here = FALSE;
1249
routine_locals = no_locals;
1250
for (i=0; i<MAX_LOCAL_VARIABLES; i++) variable_usage[i] = FALSE;
1253
&& !strcmp(local_variables.keywords[0], "_vararg_count")) {
1257
if (veneer_mode) routine_starts_line = -1;
1258
else routine_starts_line = ErrorReport.line_number
1259
+ 0x10000*ErrorReport.file_number;
1261
if ((asm_trace_level > 0) && (veneer_mode == FALSE))
1262
{ printf("\n%5d +%05lx [ %s ", ErrorReport.line_number,
1263
((long int) zmachine_pc), name);
1264
for (i=1; i<=no_locals; i++) printf("%s ", variable_name(i));
1268
if (debugfile_switch)
1269
{ write_debug_byte(ROUTINE_DBR);
1270
write_debug_byte(no_routines/256);
1271
write_debug_byte(no_routines%256);
1272
write_dbgl(*line_ref);
1273
write_debug_address(zmachine_pc);
1274
write_debug_string(name);
1276
for (i=1; i<=no_locals; i++) write_debug_string(variable_name(i));
1278
write_debug_byte(0);
1280
routine_start_pc = zmachine_pc;
1283
/* Update the routine counter */
1287
/* Actually assemble the routine header into the code area; note */
1288
/* Inform doesn't support the setting of local variables to default */
1289
/* values other than 0 in V3 and V4. (In V5+ the Z-Machine doesn't */
1290
/* provide the possibility in any case.) */
1295
warning("Z-code does not support stack-argument function definitions.");
1297
byteout(no_locals, 0);
1299
/* Not the packed address, but the scaled offset from code area start: */
1301
rv = zmachine_pc/scale_factor;
1303
if (instruction_set_number<5)
1304
for (i=0; i<no_locals; i++) { byteout(0,0); byteout(0,0); }
1306
next_label = 0; next_sequence_point = 0; last_label = -1;
1308
/* Compile code to print out text like "a=3, b=4, c=5" when the */
1309
/* function is called, if it's required. */
1311
if ((routine_asterisked) || (define_INFIX_switch))
1312
{ char fnt[80]; assembly_operand PV, RFA, CON, STP, SLF; int ln, ln2;
1317
if (define_INFIX_switch)
1320
{ SLF.value = 251; SLF.type = VARIABLE_OT; SLF.marker = 0;
1321
CON.value = 0; CON.type = SHORT_CONSTANT_OT; CON.marker = 0;
1322
assemblez_2_branch(test_attr_zc, SLF, CON, ln2, FALSE);
1325
{ i = no_named_routines++;
1326
named_routine_symbols[i] = the_symbol;
1327
CON.value = i/8; CON.type = LONG_CONSTANT_OT; CON.marker = 0;
1328
RFA.value = routine_flags_array_SC;
1329
RFA.type = LONG_CONSTANT_OT; RFA.marker = INCON_MV;
1330
STP.value = 0; STP.type = VARIABLE_OT; STP.marker = 0;
1331
assemblez_2_to(loadb_zc, RFA, CON, STP);
1332
CON.value = (1 << (i%8)); CON.type = SHORT_CONSTANT_OT;
1333
assemblez_2_to(and_zc, STP, CON, STP);
1334
assemblez_1_branch(jz_zc, STP, ln2, TRUE);
1337
sprintf(fnt, "[ %s(", name);
1338
AI.text = fnt; assemblez_0(print_zc);
1339
for (i=1; (i<=7)&&(i<=no_locals); i++)
1340
{ if (version_number >= 5)
1341
{ PV.type = SHORT_CONSTANT_OT;
1342
PV.value = i; PV.marker = 0;
1343
assemblez_1_branch(check_arg_count_zc, PV, ln, FALSE);
1345
sprintf(fnt, "%s%s = ", (i==1)?"":", ", variable_name(i));
1346
AI.text = fnt; assemblez_0(print_zc);
1347
PV.type = VARIABLE_OT; PV.value = i; PV.marker = 0;
1348
assemblez_1(print_num_zc, PV);
1350
assemble_label_no(ln);
1351
sprintf(fnt, ") ]^"); AI.text = fnt;
1352
assemblez_0(print_zc);
1353
assemble_label_no(ln2);
1361
byteout(0xC0, 0); /* Glulx type byte for function */
1363
byteout(0xC1, 0); /* Glulx type byte for function */
1365
/* Now the locals format list. This is simple; we only use
1366
four-byte locals. That's a single pair, unless we have more
1367
than 255 locals, or none at all. */
1377
/* Terminate the list with a (0, 0) pair. */
1382
/* The top stack value is the number of function arguments. Let's
1383
move that into the first local, which is _vararg_count. */
1384
/* @copy sp _vararg_count; */
1385
byteout(0x40, 0); byteout(0x98, 0); byteout(0x00, 0);
1388
next_label = 0; next_sequence_point = 0; last_label = -1;
1390
if (define_INFIX_switch) {
1391
if (embedded_flag) {
1394
i = no_named_routines++;
1395
named_routine_symbols[i] = the_symbol;
1403
void assemble_routine_end(int embedded_flag, dbgl *line_ref)
1406
/* No marker is made in the Z-machine's code area to indicate the */
1407
/* end of a routine. Instead, we simply assemble a return opcode if */
1408
/* need be (it won't be if the last instruction was, say, a "quit"). */
1409
/* The return value is true (1) for normal routines, false (0) for */
1410
/* embedded routines (e.g. the library uses this for "before" */
1413
if (!execution_never_reaches_here)
1416
if (embedded_flag) assemblez_0(rfalse_zc);
1417
else assemblez_0(rtrue_zc);
1420
assembly_operand AO;
1425
assembleg_1(return_gc, AO);
1429
/* Dump the contents of the current routine into longer-term Z-code
1433
transfer_routine_z();
1435
transfer_routine_g();
1437
/* Tell the debugging file about the routine just ended. */
1439
if (debugfile_switch)
1441
write_debug_byte(LINEREF_DBR);
1442
write_debug_byte((no_routines-1)/256);
1443
write_debug_byte((no_routines-1)%256);
1444
write_debug_byte(next_sequence_point/256);
1445
write_debug_byte(next_sequence_point%256);
1447
for (i=0; i<next_sequence_point; i++)
1448
{ int32 j = label_offsets[sequence_point_labels[i]]
1451
write_dbgl(sequence_point_refs[i]);
1452
write_debug_byte(j / 256);
1453
write_debug_byte(j % 256);
1456
write_debug_byte(ROUTINE_END_DBR);
1457
write_debug_byte((no_routines-1)/256);
1458
write_debug_byte((no_routines-1)%256);
1459
write_dbgl(*line_ref);
1460
write_debug_address(zmachine_pc);
1463
/* Issue warnings about any local variables not used in the routine. */
1465
for (i=1; i<=routine_locals; i++)
1466
if (!(variable_usage[i]))
1467
dbnu_warning("Local variable", variable_name(i),
1468
routine_starts_line);
1470
for (i=0; i<next_label; i++)
1471
{ int j = label_symbols[i];
1473
{ if (sflags[j] & CHANGE_SFLAG)
1474
error_named_at("Routine contains no such label as",
1475
(char *) symbs[j], slines[j]);
1477
if ((sflags[j] & USED_SFLAG) == 0)
1478
dbnu_warning("Label", (char *) symbs[j], slines[j]);
1479
stypes[j] = CONSTANT_T;
1480
sflags[j] = UNKNOWN_SFLAG;
1483
no_sequence_points += next_sequence_point;
1484
next_label = 0; next_sequence_point = 0;
1487
/* ------------------------------------------------------------------------- */
1488
/* Called when the holding area contains an entire routine of code: */
1489
/* backpatches the labels, issues module markers, then dumps the routine */
1490
/* into longer-term storage. */
1491
/* Note that in the code received, all branches have long form, and their */
1492
/* contents are not an offset but the label numbers they branch to. */
1493
/* Similarly, LABEL operands (those of "jump" instructions) are label */
1494
/* numbers. So this routine must change the label numbers to offsets, */
1495
/* slimming the code down as it does so to take advantage of short-form */
1496
/* branch operands where possible. */
1497
/* ------------------------------------------------------------------------- */
1499
static int32 adjusted_pc;
1501
static void transfer_to_temp_file(uchar *c)
1502
{ fputc(*c,Temp2_fp);
1506
static void transfer_to_zcode_area(uchar *c)
1507
{ write_byte_to_memory_block(&zcode_area, adjusted_pc++, *c);
1510
static void transfer_routine_z(void)
1511
{ int32 i, j, pc, new_pc, label, long_form, offset_of_next, addr,
1512
branch_on_true, rstart_pc;
1513
void (* transfer_byte)(uchar *);
1515
adjusted_pc = zmachine_pc - zcode_ha_size; rstart_pc = adjusted_pc;
1517
if (asm_trace_level >= 3)
1518
{ printf("Backpatching routine at %05lx: initial size %d, %d labels\n",
1519
(long int) adjusted_pc, zcode_ha_size, next_label);
1523
(temporary_files_switch)?transfer_to_temp_file:transfer_to_zcode_area;
1525
/* (1) Scan through for branches and make short/long decisions in each
1526
case. Mark omitted bytes (2nd bytes in branches converted to
1527
short form) with DELETED_MV. */
1529
for (i=0, pc=adjusted_pc; i<zcode_ha_size; i++, pc++)
1530
{ if (zcode_markers[i] == BRANCH_MV)
1531
{ if (asm_trace_level >= 4)
1532
printf("Branch detected at offset %04x\n", pc);
1533
j = (256*zcode_holding_area[i] + zcode_holding_area[i+1]) & 0x7fff;
1534
if (asm_trace_level >= 4)
1535
printf("To label %d, which is %d from here\n",
1536
j, label_offsets[j]-pc);
1537
if ((label_offsets[j] >= pc+2) && (label_offsets[j] < pc+64))
1538
{ if (asm_trace_level >= 4) printf("Short form\n");
1539
zcode_markers[i+1] = DELETED_MV;
1544
/* (2) Calculate the new positions of the labels. Note that since the
1545
long/short decision was taken on the basis of the old labels,
1546
and since the new labels are slightly closer together because
1547
of branch bytes deleted, there may be a few further branch
1548
optimisations which are possible but which have been missed
1549
(if two labels move inside the "short" range as a result of
1550
a previous optimisation). However, this is acceptably uncommon. */
1553
{ if (asm_trace_level >= 4)
1554
{ printf("Opening label: %d\n", first_label);
1555
for (i=0;i<next_label;i++)
1556
printf("Label %d offset %04x next -> %d previous -> %d\n",
1557
i, label_offsets[i], label_next[i], label_prev[i]);
1560
for (i=0, pc=adjusted_pc, new_pc=adjusted_pc, label = first_label;
1561
i<zcode_ha_size; i++, pc++)
1562
{ while ((label != -1) && (label_offsets[label] == pc))
1563
{ if (asm_trace_level >= 4)
1564
printf("Position of L%d corrected from %04x to %04x\n",
1565
label, label_offsets[label], new_pc);
1566
label_offsets[label] = new_pc;
1567
label = label_next[label];
1569
if (zcode_markers[i] != DELETED_MV) new_pc++;
1573
/* (3) As we are transferring, replace the label numbers in branch
1574
operands with offsets to those labels. Also issue markers, now
1575
that we know where they occur in the final Z-code area. */
1577
for (i=0, new_pc=adjusted_pc; i<zcode_ha_size; i++)
1578
{ switch(zcode_markers[i])
1580
long_form = 1; if (zcode_markers[i+1] == DELETED_MV) long_form = 0;
1582
j = (256*zcode_holding_area[i] + zcode_holding_area[i+1]) & 0x7fff;
1583
branch_on_true = ((zcode_holding_area[i]) & 0x80);
1584
offset_of_next = new_pc + long_form + 1;
1586
addr = label_offsets[j] - offset_of_next + 2;
1587
if (addr<-0x2000 || addr>0x1fff)
1588
fatalerror("Branch out of range: divide the routine up?");
1589
if (addr<0) addr+=(int32) 0x10000L;
1593
{ zcode_holding_area[i] = branch_on_true + addr/256;
1594
zcode_holding_area[i+1] = addr%256;
1598
{ compiler_error("Label out of range for branch");
1599
printf("Addr is %04x\n", addr);
1601
zcode_holding_area[i] = branch_on_true + 0x40 + (addr&0x3f);
1603
transfer_byte(zcode_holding_area + i); new_pc++;
1607
j = 256*zcode_holding_area[i] + zcode_holding_area[i+1];
1608
addr = label_offsets[j] - new_pc;
1609
if (addr<-0x8000 || addr>0x7fff)
1610
fatalerror("Jump out of range: divide the routine up?");
1611
if (addr<0) addr += (int32) 0x10000L;
1612
zcode_holding_area[i] = addr/256;
1613
zcode_holding_area[i+1] = addr%256;
1614
transfer_byte(zcode_holding_area + i); new_pc++;
1621
switch(zcode_markers[i] & 0x7f)
1622
{ case NULL_MV: break;
1627
if (!module_switch) break;
1629
if ((zcode_markers[i] & 0x7f) > LARGEST_BPATCH_MV)
1630
{ compiler_error("Illegal code backpatch value");
1631
printf("Illegal value of %02x at PC = %04x\n",
1632
zcode_markers[i] & 0x7f, new_pc);
1636
write_byte_to_memory_block(&zcode_backpatch_table,
1637
zcode_backpatch_size++,
1638
zcode_markers[i] + 32*(new_pc/65536));
1639
write_byte_to_memory_block(&zcode_backpatch_table,
1640
zcode_backpatch_size++, (new_pc/256)%256);
1641
write_byte_to_memory_block(&zcode_backpatch_table,
1642
zcode_backpatch_size++, new_pc%256);
1645
transfer_byte(zcode_holding_area + i); new_pc++;
1650
if (asm_trace_level >= 3)
1651
{ printf("After branch optimisation, routine length is %d bytes\n",
1652
new_pc - rstart_pc);
1655
/* Insert null bytes if necessary to ensure the next routine address is */
1656
/* expressible as a packed address */
1660
if (oddeven_packing_switch)
1661
while ((adjusted_pc%(scale_factor*2))!=0) transfer_byte(zero);
1663
while ((adjusted_pc%scale_factor)!=0) transfer_byte(zero);
1666
zmachine_pc = adjusted_pc;
1670
static void transfer_routine_g(void)
1671
{ int32 i, j, pc, new_pc, label, form_len, offset_of_next, addr,
1673
void (* transfer_byte)(uchar *);
1675
adjusted_pc = zmachine_pc - zcode_ha_size; rstart_pc = adjusted_pc;
1677
if (asm_trace_level >= 3)
1678
{ printf("Backpatching routine at %05lx: initial size %d, %d labels\n",
1679
(long int) adjusted_pc, zcode_ha_size, next_label);
1683
(temporary_files_switch)?transfer_to_temp_file:transfer_to_zcode_area;
1685
/* (1) Scan through for branches and make short/long decisions in each
1686
case. Mark omitted bytes (bytes 2-4 in branches converted to
1687
short form) with DELETED_MV. */
1689
for (i=0, pc=adjusted_pc; i<zcode_ha_size; i++, pc++) {
1690
if (zcode_markers[i] >= BRANCH_MV && zcode_markers[i] < BRANCHMAX_MV) {
1691
int opmodeoffset = (zcode_markers[i] - BRANCH_MV);
1693
if (asm_trace_level >= 4)
1694
printf("Branch detected at offset %04x\n", pc);
1695
j = ((zcode_holding_area[i] << 24)
1696
| (zcode_holding_area[i+1] << 16)
1697
| (zcode_holding_area[i+2] << 8)
1698
| (zcode_holding_area[i+3]));
1699
offset_of_next = pc + 4;
1700
addr = (label_offsets[j] - offset_of_next) + 2;
1701
if (asm_trace_level >= 4)
1702
printf("To label %d, which is (%d-2) = %d from here\n",
1703
j, addr, label_offsets[j] - offset_of_next);
1704
if (addr >= -0x80 && addr < 0x80) {
1705
if (asm_trace_level >= 4) printf("...Byte form\n");
1706
zcode_markers[i+1] = DELETED_MV;
1707
zcode_markers[i+2] = DELETED_MV;
1708
zcode_markers[i+3] = DELETED_MV;
1709
opmodebyte = i - ((opmodeoffset+1)/2);
1710
if ((opmodeoffset & 1) == 0)
1711
zcode_holding_area[opmodebyte] =
1712
(zcode_holding_area[opmodebyte] & 0xF0) | 0x01;
1714
zcode_holding_area[opmodebyte] =
1715
(zcode_holding_area[opmodebyte] & 0x0F) | 0x10;
1717
else if (addr >= -0x8000 && addr < 0x8000) {
1718
if (asm_trace_level >= 4) printf("...Short form\n");
1719
zcode_markers[i+2] = DELETED_MV;
1720
zcode_markers[i+3] = DELETED_MV;
1721
opmodebyte = i - ((opmodeoffset+1)/2);
1722
if ((opmodeoffset & 1) == 0)
1723
zcode_holding_area[opmodebyte] =
1724
(zcode_holding_area[opmodebyte] & 0xF0) | 0x02;
1726
zcode_holding_area[opmodebyte] =
1727
(zcode_holding_area[opmodebyte] & 0x0F) | 0x20;
1732
/* (2) Calculate the new positions of the labels. Note that since the
1733
long/short decision was taken on the basis of the old labels,
1734
and since the new labels are slightly closer together because
1735
of branch bytes deleted, there may be a few further branch
1736
optimisations which are possible but which have been missed
1737
(if two labels move inside the "short" range as a result of
1738
a previous optimisation). However, this is acceptably uncommon. */
1739
if (next_label > 0) {
1740
if (asm_trace_level >= 4) {
1741
printf("Opening label: %d\n", first_label);
1742
for (i=0;i<next_label;i++)
1743
printf("Label %d offset %04x next -> %d previous -> %d\n",
1744
i, label_offsets[i], label_next[i], label_prev[i]);
1747
for (i=0, pc=adjusted_pc, new_pc=adjusted_pc, label = first_label;
1750
while ((label != -1) && (label_offsets[label] == pc)) {
1751
if (asm_trace_level >= 4)
1752
printf("Position of L%d corrected from %04x to %04x\n",
1753
label, label_offsets[label], new_pc);
1754
label_offsets[label] = new_pc;
1755
label = label_next[label];
1757
if (zcode_markers[i] != DELETED_MV) new_pc++;
1761
/* (3) As we are transferring, replace the label numbers in branch
1762
operands with offsets to those labels. Also issue markers, now
1763
that we know where they occur in the final Z-code area. */
1765
for (i=0, new_pc=adjusted_pc; i<zcode_ha_size; i++) {
1767
if (zcode_markers[i] >= BRANCH_MV && zcode_markers[i] < BRANCHMAX_MV) {
1769
if (zcode_markers[i+1] == DELETED_MV) {
1773
if (zcode_markers[i+2] == DELETED_MV)
1776
j = ((zcode_holding_area[i] << 24)
1777
| (zcode_holding_area[i+1] << 16)
1778
| (zcode_holding_area[i+2] << 8)
1779
| (zcode_holding_area[i+3]));
1781
/* At the moment, we can safely assume that the branch operand
1782
is the end of the opcode, so the next opcode starts right
1784
offset_of_next = new_pc + form_len;
1786
addr = (label_offsets[j] - offset_of_next) + 2;
1787
if (asm_trace_level >= 4) {
1788
printf("Branch at offset %04x: %04x (%s)\n",
1789
new_pc, addr, ((form_len == 1) ? "byte" :
1790
((form_len == 2) ? "short" : "long")));
1792
if (form_len == 1) {
1793
if (addr < -0x80 && addr >= 0x80) {
1794
error("*** Label out of range for byte branch ***");
1796
zcode_holding_area[i] = (addr) & 0xFF;
1798
else if (form_len == 2) {
1799
if (addr < -0x8000 && addr >= 0x8000) {
1800
error("*** Label out of range for short branch ***");
1802
zcode_holding_area[i] = (addr >> 8) & 0xFF;
1803
zcode_holding_area[i+1] = (addr) & 0xFF;
1806
zcode_holding_area[i] = (addr >> 24) & 0xFF;
1807
zcode_holding_area[i+1] = (addr >> 16) & 0xFF;
1808
zcode_holding_area[i+2] = (addr >> 8) & 0xFF;
1809
zcode_holding_area[i+3] = (addr) & 0xFF;
1811
transfer_byte(zcode_holding_area + i); new_pc++;
1813
else if (zcode_markers[i] == LABEL_MV) {
1814
error("*** No LABEL opcodes in Glulx ***");
1816
else if (zcode_markers[i] == DELETED_MV) {
1820
switch(zcode_markers[i] & 0x7f) {
1825
if (!module_switch) break;
1829
if ((zcode_markers[i] & 0x7f) > LARGEST_BPATCH_MV) {
1830
error("*** Illegal code backpatch value ***");
1831
printf("Illegal value of %02x at PC = %04x\n",
1832
zcode_markers[i] & 0x7f, new_pc);
1835
/* The backpatch table format for Glulx:
1836
First, the marker byte (0..LARGEST_BPATCH_MV).
1837
Then a byte indicating the data size to be patched (1, 2, 4).
1838
Then the four-byte address (new_pc).
1840
write_byte_to_memory_block(&zcode_backpatch_table,
1841
zcode_backpatch_size++,
1843
write_byte_to_memory_block(&zcode_backpatch_table,
1844
zcode_backpatch_size++,
1846
write_byte_to_memory_block(&zcode_backpatch_table,
1847
zcode_backpatch_size++, ((new_pc >> 24) & 0xFF));
1848
write_byte_to_memory_block(&zcode_backpatch_table,
1849
zcode_backpatch_size++, ((new_pc >> 16) & 0xFF));
1850
write_byte_to_memory_block(&zcode_backpatch_table,
1851
zcode_backpatch_size++, ((new_pc >> 8) & 0xFF));
1852
write_byte_to_memory_block(&zcode_backpatch_table,
1853
zcode_backpatch_size++, (new_pc & 0xFF));
1856
transfer_byte(zcode_holding_area + i); new_pc++;
1860
if (asm_trace_level >= 3)
1861
{ printf("After branch optimisation, routine length is %d bytes\n",
1862
new_pc - rstart_pc);
1865
zmachine_pc = adjusted_pc;
1870
/* ========================================================================= */
1871
/* Front ends for the instruction assembler: convenient shorthand forms */
1872
/* used in various code generation routines all over Inform. */
1873
/* ------------------------------------------------------------------------- */
1875
void assemble_jump(int n)
1883
void assemblez_0(int internal_number)
1884
{ AI.internal_number = internal_number;
1885
AI.operand_count = 0;
1886
AI.store_variable_number = -1;
1887
AI.branch_label_number = -1;
1888
assemblez_instruction(&AI);
1891
void assemblez_0_to(int internal_number, assembly_operand o)
1892
{ AI.internal_number = internal_number;
1893
AI.operand_count = 0;
1894
AI.store_variable_number = o.value;
1895
AI.branch_label_number = -1;
1896
assemblez_instruction(&AI);
1899
void assemblez_0_branch(int internal_number, int label, int flag)
1900
{ AI.internal_number = internal_number;
1901
AI.operand_count = 0;
1902
AI.store_variable_number = -1;
1903
AI.branch_label_number = label;
1904
AI.branch_flag = flag;
1905
assemblez_instruction(&AI);
1908
void assemblez_1(int internal_number, assembly_operand o1)
1909
{ AI.internal_number = internal_number;
1910
AI.operand_count = 1;
1912
AI.store_variable_number = -1;
1913
AI.branch_label_number = -1;
1914
assemblez_instruction(&AI);
1917
void assemblez_1_to(int internal_number,
1918
assembly_operand o1, assembly_operand st)
1919
{ AI.internal_number = internal_number;
1920
AI.operand_count = 1;
1922
AI.store_variable_number = st.value;
1923
AI.branch_label_number = -1;
1924
assemblez_instruction(&AI);
1927
void assemblez_1_branch(int internal_number,
1928
assembly_operand o1, int label, int flag)
1929
{ AI.internal_number = internal_number;
1930
AI.operand_count = 1;
1932
AI.branch_label_number = label;
1933
AI.store_variable_number = -1;
1934
AI.branch_flag = flag;
1935
assemblez_instruction(&AI);
1938
void assemblez_2(int internal_number,
1939
assembly_operand o1, assembly_operand o2)
1940
{ AI.internal_number = internal_number;
1941
AI.operand_count = 2;
1944
AI.store_variable_number = -1;
1945
AI.branch_label_number = -1;
1946
assemblez_instruction(&AI);
1949
void assemblez_3(int internal_number,
1950
assembly_operand o1, assembly_operand o2, assembly_operand o3)
1951
{ AI.internal_number = internal_number;
1952
AI.operand_count = 3;
1956
AI.store_variable_number = -1;
1957
AI.branch_label_number = -1;
1958
assemblez_instruction(&AI);
1961
void assemblez_3_to(int internal_number,
1962
assembly_operand o1, assembly_operand o2, assembly_operand o3,
1963
assembly_operand st)
1964
{ AI.internal_number = internal_number;
1965
AI.operand_count = 3;
1969
AI.store_variable_number = st.value;
1970
AI.branch_label_number = -1;
1971
assemblez_instruction(&AI);
1974
void assemblez_3_branch(int internal_number,
1975
assembly_operand o1, assembly_operand o2, assembly_operand o3,
1976
int label, int flag)
1977
{ AI.internal_number = internal_number;
1978
AI.operand_count = 3;
1982
AI.store_variable_number = -1;
1983
AI.branch_label_number = label;
1984
AI.branch_flag = flag;
1985
assemblez_instruction(&AI);
1988
void assemblez_4(int internal_number,
1989
assembly_operand o1, assembly_operand o2, assembly_operand o3,
1990
assembly_operand o4)
1991
{ AI.internal_number = internal_number;
1992
AI.operand_count = 4;
1997
AI.store_variable_number = -1;
1998
AI.branch_label_number = -1;
1999
assemblez_instruction(&AI);
2002
void assemblez_5(int internal_number,
2003
assembly_operand o1, assembly_operand o2, assembly_operand o3,
2004
assembly_operand o4, assembly_operand o5)
2005
{ AI.internal_number = internal_number;
2006
AI.operand_count = 5;
2012
AI.store_variable_number = -1;
2013
AI.branch_label_number = -1;
2014
assemblez_instruction(&AI);
2017
void assemblez_6(int internal_number,
2018
assembly_operand o1, assembly_operand o2, assembly_operand o3,
2019
assembly_operand o4, assembly_operand o5, assembly_operand o6)
2020
{ AI.internal_number = internal_number;
2021
AI.operand_count = 6;
2028
AI.store_variable_number = -1;
2029
AI.branch_label_number = -1;
2030
assemblez_instruction(&AI);
2033
void assemblez_4_branch(int internal_number,
2034
assembly_operand o1, assembly_operand o2, assembly_operand o3,
2035
assembly_operand o4, int label, int flag)
2036
{ AI.internal_number = internal_number;
2037
AI.operand_count = 4;
2042
AI.store_variable_number = -1;
2043
AI.branch_label_number = label;
2044
AI.branch_flag = flag;
2045
assemblez_instruction(&AI);
2048
void assemblez_4_to(int internal_number,
2049
assembly_operand o1, assembly_operand o2, assembly_operand o3,
2050
assembly_operand o4, assembly_operand st)
2051
{ AI.internal_number = internal_number;
2052
AI.operand_count = 4;
2057
AI.store_variable_number = st.value;
2058
AI.branch_label_number = -1;
2059
assemblez_instruction(&AI);
2062
void assemblez_2_to(int internal_number,
2063
assembly_operand o1, assembly_operand o2, assembly_operand st)
2064
{ AI.internal_number = internal_number;
2065
AI.operand_count = 2;
2068
AI.store_variable_number = st.value;
2069
AI.branch_label_number = -1;
2070
assemblez_instruction(&AI);
2073
void assemblez_2_branch(int internal_number,
2074
assembly_operand o1, assembly_operand o2, int label, int flag)
2075
{ AI.internal_number = internal_number;
2076
AI.operand_count = 2;
2079
AI.branch_label_number = label;
2080
AI.store_variable_number = -1;
2081
AI.branch_flag = flag;
2082
assemblez_instruction(&AI);
2085
void assemblez_objcode(int internal_number,
2086
assembly_operand o1, assembly_operand st, int label, int flag)
2087
{ AI.internal_number = internal_number;
2088
AI.operand_count = 1;
2090
AI.branch_label_number = label;
2091
AI.store_variable_number = st.value;
2092
AI.branch_flag = flag;
2093
assemblez_instruction(&AI);
2096
extern void assemblez_inc(assembly_operand o1)
2098
if ((o1.value >= MAX_LOCAL_VARIABLES)
2099
&& (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
2101
AI.internal_number = inc_zc;
2102
AI.operand_count = 1;
2103
AI.operand[0].value = o1.value;
2104
AI.operand[0].type = SHORT_CONSTANT_OT;
2105
AI.operand[0].marker = m;
2106
AI.store_variable_number = -1;
2107
AI.branch_label_number = -1;
2108
assemblez_instruction(&AI);
2111
extern void assemblez_dec(assembly_operand o1)
2113
if ((o1.value >= MAX_LOCAL_VARIABLES)
2114
&& (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
2116
AI.internal_number = dec_zc;
2117
AI.operand_count = 1;
2118
AI.operand[0].value = o1.value;
2119
AI.operand[0].type = SHORT_CONSTANT_OT;
2120
AI.operand[0].marker = m;
2121
AI.store_variable_number = -1;
2122
AI.branch_label_number = -1;
2123
assemblez_instruction(&AI);
2126
extern void assemblez_store(assembly_operand o1, assembly_operand o2)
2128
if ((o1.value >= MAX_LOCAL_VARIABLES)
2129
&& (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
2132
if ((o2.type == VARIABLE_OT) && (o2.value == 0))
2134
/* Assemble "pull VAR" rather than "store VAR sp",
2137
AI.internal_number = pull_zc;
2138
if (instruction_set_number == 6)
2139
{ AI.operand_count = 0;
2140
AI.store_variable_number = o1.value;
2143
{ AI.operand_count = 1;
2144
AI.operand[0].value = o1.value;
2145
AI.operand[0].type = SHORT_CONSTANT_OT;
2146
AI.operand[0].marker = m;
2147
AI.store_variable_number = -1;
2149
AI.branch_label_number = -1;
2150
assemblez_instruction(&AI);
2154
if ((o1.type == VARIABLE_OT) && (o1.value == 0))
2155
{ /* Assemble "push VAR" rather than "store sp VAR",
2158
AI.internal_number = push_zc;
2159
AI.operand_count = 1;
2161
AI.store_variable_number = -1;
2162
AI.branch_label_number = -1;
2163
assemblez_instruction(&AI);
2166
AI.internal_number = store_zc;
2167
AI.operand_count = 2;
2168
AI.operand[0].value = o1.value;
2169
AI.operand[0].type = SHORT_CONSTANT_OT;
2170
AI.operand[0].marker = m;
2172
AI.store_variable_number = -1;
2173
AI.branch_label_number = -1;
2174
assemblez_instruction(&AI);
2177
void assemblez_jump(int n)
2178
{ assembly_operand AO;
2179
if (n==-4) assemblez_0(rtrue_zc);
2180
else if (n==-3) assemblez_0(rfalse_zc);
2182
{ AO.type = LONG_CONSTANT_OT; AO.value = n; AO.marker = 0;
2183
assemblez_1(jump_zc, AO);
2187
void assembleg_0(int internal_number)
2188
{ AI.internal_number = internal_number;
2189
AI.operand_count = 0;
2190
assembleg_instruction(&AI);
2193
void assembleg_1(int internal_number, assembly_operand o1)
2194
{ AI.internal_number = internal_number;
2195
AI.operand_count = 1;
2197
assembleg_instruction(&AI);
2200
void assembleg_2(int internal_number, assembly_operand o1,
2201
assembly_operand o2)
2202
{ AI.internal_number = internal_number;
2203
AI.operand_count = 2;
2206
assembleg_instruction(&AI);
2209
void assembleg_3(int internal_number, assembly_operand o1,
2210
assembly_operand o2, assembly_operand o3)
2211
{ AI.internal_number = internal_number;
2212
AI.operand_count = 3;
2216
assembleg_instruction(&AI);
2219
void assembleg_4(int internal_number, assembly_operand o1,
2220
assembly_operand o2, assembly_operand o3,
2221
assembly_operand o4)
2222
{ AI.internal_number = internal_number;
2223
AI.operand_count = 4;
2228
assembleg_instruction(&AI);
2231
void assembleg_5(int internal_number, assembly_operand o1,
2232
assembly_operand o2, assembly_operand o3,
2233
assembly_operand o4, assembly_operand o5)
2234
{ AI.internal_number = internal_number;
2235
AI.operand_count = 5;
2241
assembleg_instruction(&AI);
2244
void assembleg_0_branch(int internal_number,
2247
AI.internal_number = internal_number;
2248
AI.operand_count = 1;
2249
AI.operand[0].type = CONSTANT_OT;
2250
AI.operand[0].value = label;
2251
AI.operand[0].marker = BRANCH_MV;
2252
assembleg_instruction(&AI);
2255
void assembleg_1_branch(int internal_number,
2256
assembly_operand o1, int label)
2258
/* Some clever optimizations first. A constant is always or never equal
2260
if (o1.marker == 0 && is_constant_ot(o1.type)) {
2261
if ((internal_number == jz_gc && o1.value == 0)
2262
|| (internal_number == jnz_gc && o1.value != 0)) {
2263
assembleg_0_branch(jump_gc, label);
2264
/* We clear the "can't reach statement" flag here,
2265
so that "if (1)" doesn't produce that warning. */
2266
execution_never_reaches_here = 0;
2269
if ((internal_number == jz_gc && o1.value != 0)
2270
|| (internal_number == jnz_gc && o1.value == 0)) {
2271
/* assemble nothing at all! */
2275
AI.internal_number = internal_number;
2276
AI.operand_count = 2;
2278
AI.operand[1].type = CONSTANT_OT;
2279
AI.operand[1].value = label;
2280
AI.operand[1].marker = BRANCH_MV;
2281
assembleg_instruction(&AI);
2284
void assembleg_2_branch(int internal_number,
2285
assembly_operand o1, assembly_operand o2, int label)
2287
AI.internal_number = internal_number;
2288
AI.operand_count = 3;
2291
AI.operand[2].type = CONSTANT_OT;
2292
AI.operand[2].value = label;
2293
AI.operand[2].marker = BRANCH_MV;
2294
assembleg_instruction(&AI);
2297
void assembleg_call_1(assembly_operand oaddr, assembly_operand o1,
2298
assembly_operand odest)
2300
assembleg_3(callfi_gc, oaddr, o1, odest);
2301
/* Copy argument to stack ptr, unless it's already there.
2302
if (!(o1.type == LOCALVAR_OT && o1.value == 0 && o1.marker == 0)) {
2303
assembleg_2(copy_gc, o1, stack_pointer);
2305
assembleg_3(call_gc, oaddr, one_operand, odest); */
2308
void assembleg_call_2(assembly_operand oaddr, assembly_operand o1,
2309
assembly_operand o2, assembly_operand odest)
2311
assembleg_4(callfii_gc, oaddr, o1, o2, odest);
2312
/* Copy arguments to stack ptr, unless they're already there.
2313
if (o1.type == LOCALVAR_OT && o1.value == 0 && o1.marker == 0) {
2314
if (o2.type == LOCALVAR_OT && o2.value == 0 && o2.marker == 0) {
2317
assembleg_2(copy_gc, o2, stack_pointer);
2318
assembleg_0(stkswap_gc);
2322
if (o2.type == LOCALVAR_OT && o2.value == 0 && o2.marker == 0) {
2323
assembleg_2(copy_gc, o1, stack_pointer);
2326
assembleg_2(copy_gc, o2, stack_pointer);
2327
assembleg_2(copy_gc, o1, stack_pointer);
2330
assembleg_3(call_gc, oaddr, two_operand, odest); */
2333
void assembleg_call_3(assembly_operand oaddr, assembly_operand o1,
2334
assembly_operand o2, assembly_operand o3, assembly_operand odest)
2336
assembleg_5(callfiii_gc, oaddr, o1, o2, o3, odest);
2337
/* Copy arguments to stack ptr, unless they're already there.
2338
if (o1.type == LOCALVAR_OT && o1.value == 0 && o1.marker == 0) {
2339
if (o2.type == LOCALVAR_OT && o2.value == 0 && o2.marker == 0) {
2340
if (o3.type == LOCALVAR_OT && o3.value == 0 && o3.marker == 0) {
2341
// all already there.
2344
assembleg_2(copy_gc, o3, stack_pointer);
2345
assembleg_2(stkroll_gc, three_operand, one_operand);
2349
if (o3.type == LOCALVAR_OT && o3.value == 0 && o3.marker == 0) {
2350
assembleg_2(copy_gc, o2, stack_pointer);
2351
assembleg_0(stkswap_gc);
2354
assembleg_2(copy_gc, o3, stack_pointer);
2355
assembleg_0(stkswap_gc);
2356
assembleg_2(copy_gc, o2, stack_pointer);
2357
assembleg_0(stkswap_gc);
2362
if (o2.type == LOCALVAR_OT && o2.value == 0 && o2.marker == 0) {
2363
if (o3.type == LOCALVAR_OT && o3.value == 0 && o3.marker == 0) {
2364
assembleg_2(copy_gc, o1, stack_pointer);
2367
assembleg_2(copy_gc, o3, stack_pointer);
2368
assembleg_0(stkswap_gc);
2369
assembleg_2(copy_gc, o1, stack_pointer);
2373
if (o3.type == LOCALVAR_OT && o3.value == 0 && o3.marker == 0) {
2374
assembleg_2(copy_gc, o2, stack_pointer);
2375
assembleg_2(copy_gc, o1, stack_pointer);
2378
assembleg_2(copy_gc, o3, stack_pointer);
2379
assembleg_2(copy_gc, o2, stack_pointer);
2380
assembleg_2(copy_gc, o1, stack_pointer);
2385
assembleg_3(call_gc, oaddr, three_operand, odest); */
2388
void assembleg_inc(assembly_operand o1)
2390
AI.internal_number = add_gc;
2391
AI.operand_count = 3;
2393
AI.operand[1] = one_operand;
2395
assembleg_instruction(&AI);
2398
void assembleg_dec(assembly_operand o1)
2400
AI.internal_number = sub_gc;
2401
AI.operand_count = 3;
2403
AI.operand[1] = one_operand;
2405
assembleg_instruction(&AI);
2408
void assembleg_store(assembly_operand o1, assembly_operand o2)
2410
/* Note the order is reversed: "o1 = o2;" */
2411
assembleg_2(copy_gc, o2, o1);
2414
void assembleg_jump(int n)
2417
assembleg_1(return_gc, one_operand);
2420
assembleg_1(return_gc, zero_operand);
2423
assembleg_0_branch(jump_gc, n);
2427
/* ========================================================================= */
2428
/* Parsing and then calling the assembler for @ (assembly language) */
2430
/* ------------------------------------------------------------------------- */
2432
static assembly_operand parse_operand_z(void)
2433
{ assembly_operand AO;
2435
AO = parse_expression(ASSEMBLY_CONTEXT);
2436
if (AO.type == EXPRESSION_OT)
2437
{ ebf_error("variable or constant", "expression");
2438
AO.type = SHORT_CONSTANT_OT;
2443
static void parse_assembly_z(void)
2444
{ int n, min, max, indirect_addressed, error_flag = FALSE;
2447
AI.operand_count = 0;
2448
AI.store_variable_number = -1;
2449
AI.branch_label_number = -1;
2452
opcode_names.enabled = TRUE;
2454
opcode_names.enabled = FALSE;
2456
if (token_type == DQ_TT)
2458
AI.internal_number = -1;
2460
custom_opcode_z.name = (uchar *) token_text;
2461
custom_opcode_z.version1 = instruction_set_number;
2462
custom_opcode_z.version2 = instruction_set_number;
2463
custom_opcode_z.extension = -1;
2464
custom_opcode_z.flags = 0;
2465
custom_opcode_z.op_rules = 0;
2466
custom_opcode_z.flags2_set = 0;
2467
custom_opcode_z.no = ZERO;
2469
for (i=0; token_text[i]!=0; i++)
2470
{ if (token_text[i] == ':')
2471
{ token_text[i++] = 0;
2475
if (token_text[i] == 0)
2476
error("Opcode specification should have form \"VAR:102\"");
2479
if (strcmp(token_text, "0OP")==0) n=ZERO;
2480
if (strcmp(token_text, "1OP")==0) n=ONE;
2481
if (strcmp(token_text, "2OP")==0) n=TWO;
2482
if (strcmp(token_text, "VAR")==0) n=VAR;
2483
if (strcmp(token_text, "EXT")==0) n=EXT;
2484
if (strcmp(token_text, "VAR_LONG")==0) n=VAR_LONG;
2485
if (strcmp(token_text, "EXT_LONG")==0) n=EXT_LONG;
2487
if (i>0) token_text[i-1] = ':';
2490
{ ebf_error("Expected 0OP, 1OP, 2OP, VAR, EXT, VAR_LONG or EXT_LONG",
2494
custom_opcode_z.no = n;
2496
custom_opcode_z.code = atoi(token_text+i);
2497
while (isdigit(token_text[i])) i++;
2502
{ case ZERO: case ONE: max = 16; break;
2503
case VAR: case VAR_LONG: min = 32; max = 64; break;
2504
case EXT: case EXT_LONG: max = 256; break;
2505
case TWO: max = 32; break;
2507
if ((custom_opcode_z.code < min) || (custom_opcode_z.code >= max))
2509
sprintf(range, "%d to %d", min, max-1);
2510
error_named("For this operand type, opcode number must be in range",
2512
custom_opcode_z.code = min;
2516
while (token_text[i++] != 0)
2517
{ switch(token_text[i-1])
2518
{ case 'B': custom_opcode_z.flags |= Br; break;
2519
case 'S': custom_opcode_z.flags |= St; break;
2520
case 'T': custom_opcode_z.op_rules = TEXT; break;
2521
case 'I': custom_opcode_z.op_rules = VARIAB; break;
2522
case 'F': custom_opcode_z.flags2_set = atoi(token_text+i);
2523
while (isdigit(token_text[i])) i++; break;
2525
error("Unknown flag: options are B (branch), S (store), \
2526
T (text), I (indirect addressing), F** (set this Flags 2 bit)");
2530
O = custom_opcode_z;
2533
{ if (token_type != OPCODE_NAME_TT)
2534
{ ebf_error("an opcode name", token_text);
2535
panic_mode_error_recovery();
2538
AI.internal_number = token_value;
2539
O = internal_number_to_opcode_z(AI.internal_number);
2542
indirect_addressed = (O.op_rules == VARIAB);
2544
if (O.op_rules == TEXT)
2546
if (token_type != DQ_TT)
2547
ebf_error("literal text in double-quotes", token_text);
2548
AI.text = token_text;
2549
if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
2551
if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
2552
{ assemblez_instruction(&AI);
2555
ebf_error("semicolon ';' after print string", token_text);
2560
return_sp_as_variable = TRUE;
2564
if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
2566
if ((token_type == SEP_TT) && (token_value == ARROW_SEP))
2567
{ if (AI.store_variable_number != -1)
2568
error("Only one '->' store destination can be given");
2570
if ((token_type != SYMBOL_TT)
2571
&& (token_type != LOCAL_VARIABLE_TT))
2572
ebf_error("variable name or 'sp'", token_text);
2574
if (token_type == LOCAL_VARIABLE_TT) n = token_value;
2576
{ if (strcmp(token_text, "sp") == 0) n = 0;
2578
{ if (stypes[token_value] != GLOBAL_VARIABLE_T)
2580
"Store '->' destination not 'sp' or a variable:",
2582
else n = svals[token_value];
2585
AI.store_variable_number = n;
2589
if ((token_type == SEP_TT) &&
2590
((token_value == BRANCH_SEP) || (token_value == NBRANCH_SEP)))
2591
{ if (AI.branch_label_number != -1)
2592
error("Only one '?' branch destination can be given");
2594
AI.branch_flag = (token_value == BRANCH_SEP);
2596
opcode_names.enabled = TRUE;
2598
opcode_names.enabled = FALSE;
2601
if ((token_type == OPCODE_NAME_TT)
2602
&& (token_value == rfalse_zc)) n = -3;
2604
if ((token_type == OPCODE_NAME_TT)
2605
&& (token_value == rtrue_zc)) n = -4;
2607
{ if (token_type == SYMBOL_TT)
2612
ebf_error("label name after '?' or '?~'", token_text);
2614
AI.branch_label_number = n;
2618
if (AI.operand_count == 8)
2619
{ error("No assembly instruction may have more than 8 operands");
2620
panic_mode_error_recovery(); break;
2623
if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
2624
{ if (!indirect_addressed)
2625
error("This opcode does not use indirect addressing");
2626
if (AI.operand_count > 0)
2627
error("Indirect addressing can only be used on the first operand");
2628
AI.operand[AI.operand_count++] = parse_operand_z();
2630
if (!((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP)))
2631
{ ebf_error("']'", token_text);
2637
AI.operand[AI.operand_count++] = parse_operand_z();
2638
if ((indirect_addressed) && (AI.operand_count == 1)
2639
&& (AI.operand[AI.operand_count-1].type == VARIABLE_OT))
2640
{ AI.operand[AI.operand_count-1].type = SHORT_CONSTANT_OT;
2641
AI.operand[AI.operand_count-1].marker = VARIABLE_MV;
2647
return_sp_as_variable = FALSE;
2650
if (O.version1 == 0)
2651
{ error_named("Opcode unavailable in this Z-machine version:",
2652
opcode_names.keywords[AI.internal_number]);
2656
if (((O.flags) & Br) != 0)
2657
{ if (AI.branch_label_number == -1)
2658
{ error_flag = TRUE;
2659
AI.branch_label_number = -2;
2663
{ if (AI.branch_label_number != -1)
2664
{ error_flag = TRUE;
2665
AI.branch_label_number = -1;
2668
if (((O.flags) & St) != 0)
2669
{ if (AI.store_variable_number == -1)
2670
{ if (AI.operand_count == 0)
2671
{ error_flag = TRUE;
2672
AI.store_variable_number = 255;
2675
{ AI.store_variable_number
2676
= AI.operand[--AI.operand_count].value;
2677
if (AI.operand[AI.operand_count].type != VARIABLE_OT)
2678
error("Store destination (the last operand) is not a variable");
2683
{ if (AI.store_variable_number != -1)
2684
{ error_flag = TRUE;
2685
AI.store_variable_number = -1;
2690
{ case TWO: min = 2; max = 2;
2691
/* Exception for the V6 set_colour, which can take
2692
a third argument, thus forcing it into VAR form: */
2693
if ((version_number == 6) && (O.code == 0x1b)) max = 3;
2694
/* Also an exception for je, which can take from 1
2695
argument (useless) to 4 arguments */
2696
if (O.code == 0x01) { min = 1; max = 4; }
2698
case VAR: min = 0; max = 4; break;
2699
case VAR_LONG: min = 0; max = 8; break;
2700
case ONE: min = 1; max = 1; break;
2701
case ZERO: min = 0; max = 0; break;
2702
case EXT: min = 0; max = 4; break;
2703
case EXT_LONG: min = 0; max = 8; break;
2706
if ((AI.operand_count >= min) && (AI.operand_count <= max))
2707
assemblez_instruction(&AI);
2708
else error_flag = TRUE;
2711
{ make_opcode_syntax_z(O);
2712
error_named("Assembly mistake: syntax is",
2713
opcode_syntax_string);
2717
static assembly_operand parse_operand_g(void)
2718
{ assembly_operand AO;
2720
AO = parse_expression(ASSEMBLY_CONTEXT);
2721
if (AO.type == EXPRESSION_OT)
2722
{ ebf_error("variable or constant", "expression");
2723
AO.type = CONSTANT_OT;
2728
static void parse_assembly_g(void)
2731
assembly_operand AO;
2732
int error_flag = FALSE;
2734
AI.operand_count = 0;
2736
opcode_names.enabled = TRUE;
2738
opcode_names.enabled = FALSE;
2740
if (token_type == DQ_TT) {
2741
error("Runtime assembly definitions are not yet supported in Glulx.");
2742
panic_mode_error_recovery();
2746
if (token_type != OPCODE_NAME_TT) {
2747
ebf_error("an opcode name", token_text);
2748
panic_mode_error_recovery();
2751
AI.internal_number = token_value;
2752
O = internal_number_to_opcode_g(AI.internal_number);
2755
return_sp_as_variable = TRUE;
2760
if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
2763
if (AI.operand_count == 8) {
2764
error("No assembly instruction may have more than 8 operands");
2765
panic_mode_error_recovery();
2769
if ((O.flags & Br) && (AI.operand_count == O.no-1)) {
2770
if (!((token_type == SEP_TT) && (token_value == BRANCH_SEP))) {
2772
error("Branch opcode must have '?' label");
2775
AO.type = CONSTANT_OT;
2776
AO.value = parse_label();
2777
AO.marker = BRANCH_MV;
2781
AO = parse_operand_g();
2784
AI.operand[AI.operand_count] = AO;
2788
return_sp_as_variable = FALSE;
2790
if (O.no != AI.operand_count) {
2795
assembleg_instruction(&AI);
2798
make_opcode_syntax_g(O);
2799
error_named("Assembly mistake: syntax is",
2800
opcode_syntax_string);
2804
extern void parse_assembly(void)
2812
/* ========================================================================= */
2813
/* Data structure management routines */
2814
/* ------------------------------------------------------------------------- */
2816
extern void asm_begin_pass(void)
2817
{ no_instructions = 0;
2819
no_sequence_points = 0;
2821
next_sequence_point = 0;
2825
extern void init_asm_vars(void)
2828
for (i=0;i<16;i++) flags2_requirements[i]=0;
2830
sequence_point_follows = TRUE;
2831
label_moved_error_already_given = FALSE;
2833
initialise_memory_block(&zcode_area);
2836
extern void asm_allocate_arrays(void)
2837
{ if ((debugfile_switch) && (MAX_LABELS < 2000)) MAX_LABELS = 2000;
2839
variable_tokens = my_calloc(sizeof(int32),
2840
MAX_LOCAL_VARIABLES+MAX_GLOBAL_VARIABLES, "variable tokens");
2841
variable_usage = my_calloc(sizeof(int),
2842
MAX_LOCAL_VARIABLES+MAX_GLOBAL_VARIABLES, "variable usage");
2844
label_offsets = my_calloc(sizeof(int32), MAX_LABELS, "label offsets");
2845
label_symbols = my_calloc(sizeof(int32), MAX_LABELS, "label symbols");
2846
label_next = my_calloc(sizeof(int), MAX_LABELS, "label dll 1");
2847
label_prev = my_calloc(sizeof(int), MAX_LABELS, "label dll 1");
2848
sequence_point_labels
2849
= my_calloc(sizeof(int), MAX_LABELS, "sequence point labels");
2851
= my_calloc(sizeof(dbgl), MAX_LABELS, "sequence point refs");
2853
zcode_holding_area = my_malloc(MAX_ZCODE_SIZE,"compiled routine code area");
2854
zcode_markers = my_malloc(MAX_ZCODE_SIZE, "compiled routine code area");
2856
named_routine_symbols
2857
= my_calloc(sizeof(int32), MAX_SYMBOLS, "named routine symbols");
2860
extern void asm_free_arrays(void)
2862
my_free(&variable_tokens, "variable tokens");
2863
my_free(&variable_usage, "variable usage");
2865
my_free(&label_offsets, "label offsets");
2866
my_free(&label_symbols, "label symbols");
2867
my_free(&label_next, "label dll 1");
2868
my_free(&label_prev, "label dll 2");
2869
my_free(&sequence_point_labels, "sequence point labels");
2870
my_free(&sequence_point_refs, "sequence point refs");
2872
my_free(&zcode_holding_area, "compiled routine code area");
2873
my_free(&zcode_markers, "compiled routine code markers");
2875
my_free(&named_routine_symbols, "named routine symbols");
2876
deallocate_memory_block(&zcode_area);
2879
/* ========================================================================= */