~ubuntu-branches/ubuntu/gutsy/inform/gutsy

« back to all changes in this revision

Viewing changes to src/asm.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Baker
  • Date: 2004-03-29 23:52:44 UTC
  • Revision ID: james.westby@ubuntu.com-20040329235244-fox1z1yv7d6vojoo
Tags: upstream-6.30
ImportĀ upstreamĀ versionĀ 6.30

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ------------------------------------------------------------------------- */
 
2
/*   "asm" : The Inform assembler                                            */
 
3
/*                                                                           */
 
4
/*   Part of Inform 6.30                                                     */
 
5
/*   copyright (c) Graham Nelson 1993 - 2004                                 */
 
6
/*                                                                           */
 
7
/* ------------------------------------------------------------------------- */
 
8
 
 
9
#include "header.h"
 
10
 
 
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
 
14
                                      code                                   */
 
15
static int zcode_ha_size;          /* Number of bytes in holding area        */
 
16
 
 
17
memory_block zcode_area;           /* Block to hold assembled code (if
 
18
                                      temporary files are not being used)    */
 
19
 
 
20
int32 zmachine_pc;                 /* PC position of assembly (byte offset
 
21
                                      from start of Z-code area)             */
 
22
 
 
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      */
 
32
 
 
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  */
 
38
 
 
39
int  sequence_point_follows;       /* Will the next instruction assembled    */
 
40
                                   /* be at a sequence point in the routine? */
 
41
 
 
42
dbgl debug_line_ref;               /* Source code ref of current statement   */
 
43
 
 
44
 
 
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   */
 
52
 
 
53
assembly_instruction AI;           /* A structure used to hold the full
 
54
                                      specification of a single Z-code
 
55
                                      instruction: effectively this is the
 
56
                                      input to the routine
 
57
                                      assemble_instruction()                 */
 
58
 
 
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       */
 
62
 
 
63
static int routine_locals;         /* The number of local variables used by
 
64
                                      the routine currently being compiled   */
 
65
 
 
66
static int32 routine_start_pc;
 
67
 
 
68
int32 *named_routine_symbols;
 
69
 
 
70
static void transfer_routine_z(void);
 
71
static void transfer_routine_g(void);
 
72
 
 
73
/* ------------------------------------------------------------------------- */
 
74
/*   Label data                                                              */
 
75
/* ------------------------------------------------------------------------- */
 
76
 
 
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  */
 
80
             *label_prev;
 
81
static int32 *label_symbols;       /* Symbol numbers if defined in source    */
 
82
 
 
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)    */
 
86
 
 
87
static void set_label_offset(int label, int32 offset)
 
88
{
 
89
    if (label >= MAX_LABELS) memoryerror("MAX_LABELS", MAX_LABELS);
 
90
 
 
91
    label_offsets[label] = offset;
 
92
    if (last_label == -1)
 
93
    {   label_prev[label] = -1;
 
94
        first_label = label;
 
95
    }
 
96
    else
 
97
    {   label_prev[label] = last_label;
 
98
        label_next[last_label] = label;
 
99
    }
 
100
    last_label = label;
 
101
    label_next[label] = -1;
 
102
    label_symbols[label] = -1;
 
103
}
 
104
 
 
105
/* ------------------------------------------------------------------------- */
 
106
/*   Useful tool for building operands                                       */
 
107
/* ------------------------------------------------------------------------- */
 
108
 
 
109
extern void set_constant_ot(assembly_operand *AO)
 
110
{
 
111
  if (!glulx_mode) {
 
112
    if (AO->value >= 0 && AO->value <= 255)
 
113
      AO->type = SHORT_CONSTANT_OT;
 
114
    else
 
115
      AO->type = LONG_CONSTANT_OT;
 
116
  }
 
117
  else {
 
118
    if (AO->value == 0)
 
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;
 
124
    else
 
125
      AO->type = CONSTANT_OT;
 
126
  }
 
127
}
 
128
 
 
129
extern int is_constant_ot(int otval)
 
130
{
 
131
  if (!glulx_mode) {
 
132
    return ((otval == LONG_CONSTANT_OT) 
 
133
      || (otval == SHORT_CONSTANT_OT));
 
134
  }
 
135
  else {
 
136
    return ((otval == CONSTANT_OT)
 
137
      || (otval == HALFCONSTANT_OT)
 
138
      || (otval == BYTECONSTANT_OT)
 
139
      || (otval == ZEROCONSTANT_OT));
 
140
  }
 
141
}
 
142
 
 
143
extern int is_variable_ot(int otval)
 
144
{
 
145
  if (!glulx_mode) {
 
146
    return (otval == VARIABLE_OT);
 
147
  }
 
148
  else {
 
149
    return ((otval == LOCALVAR_OT)
 
150
      || (otval == GLOBALVAR_OT));
 
151
  }
 
152
}
 
153
 
 
154
/* ------------------------------------------------------------------------- */
 
155
/*   Used in printing assembly traces                                        */
 
156
/* ------------------------------------------------------------------------- */
 
157
 
 
158
extern char *variable_name(int32 i)
 
159
{
 
160
    if (i==0) return("sp");
 
161
    if (i<MAX_LOCAL_VARIABLES) return local_variable_texts[i-1];
 
162
 
 
163
    if (!glulx_mode) {
 
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");
 
171
    }
 
172
    else {
 
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";
 
185
      }
 
186
    }
 
187
 
 
188
    return ((char *) symbs[variable_tokens[i]]);
 
189
}
 
190
 
 
191
static void print_operand_z(assembly_operand o)
 
192
{   switch(o.type)
 
193
    {   case EXPRESSION_OT: printf("expr_"); break;
 
194
        case LONG_CONSTANT_OT: printf("long_"); break;
 
195
        case SHORT_CONSTANT_OT: printf("short_"); break;
 
196
        case VARIABLE_OT:
 
197
             if (o.value==0) { printf("sp"); return; }
 
198
             printf("%s", variable_name(o.value)); return;
 
199
        case OMITTED_OT: printf("<no value>"); return;
 
200
    }
 
201
    printf("%d", o.value);
 
202
}
 
203
 
 
204
static void print_operand_g(assembly_operand o)
 
205
{
 
206
  switch (o.type) {
 
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;
 
213
  case GLOBALVAR_OT: 
 
214
    printf("%s (global_%d)", variable_name(o.value), o.value); 
 
215
    return;
 
216
  case LOCALVAR_OT: 
 
217
    if (o.value == 0)
 
218
      printf("stackptr"); 
 
219
    else
 
220
      printf("%s (local_%d)", variable_name(o.value), o.value-1); 
 
221
    return;
 
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; 
 
226
  }
 
227
  printf("%d", o.value);
 
228
}
 
229
 
 
230
extern void print_operand(assembly_operand o)
 
231
{
 
232
  if (!glulx_mode)
 
233
    print_operand_z(o);
 
234
  else
 
235
    print_operand_g(o);
 
236
}
 
237
 
 
238
/* ------------------------------------------------------------------------- */
 
239
/*   Writing bytes to the code area                                          */
 
240
/* ------------------------------------------------------------------------- */
 
241
 
 
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;
 
247
    zmachine_pc++;
 
248
}
 
249
 
 
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
/* ------------------------------------------------------------------------- */
 
254
 
 
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) */
 
267
} opcodez;
 
268
 
 
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 */
 
275
} opcodeg;
 
276
 
 
277
    /* Flags which can be set */
 
278
 
 
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)) */
 
284
 
 
285
    /* Codes for any unusual operand assembly rules */
 
286
 
 
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$ */
 
294
 
 
295
    /* Codes for the number of operands */
 
296
 
 
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) */
 
304
 
 
305
static opcodez opcodes_table_z[] =
 
306
{
 
307
    /* Opcodes introduced in Version 3 */
 
308
 
 
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 },
 
378
 
 
379
    /* Opcodes introduced in Version 4 */
 
380
 
 
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,
 
386
                                                                     VAR_LONG },
 
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 },
 
396
 
 
397
    /* Opcodes introduced in Version 5 */
 
398
 
 
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,
 
404
                                                                     VAR_LONG },
 
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 },
 
418
 
 
419
    /* Opcodes introduced in Version 6 */
 
420
 
 
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 },
 
438
 
 
439
    /* Opcodes introduced in Z-Machine Specification Standard 1.0 */
 
440
 
 
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 }
 
443
};
 
444
 
 
445
    /* Subsequent forms for opcodes whose meaning changes with version */
 
446
 
 
447
static opcodez extension_table_z[] =
 
448
{
 
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 }
 
456
};
 
457
 
 
458
static opcodez invalid_opcode_z =
 
459
        { (uchar *) "invalid",         0, 0, -1, 0xff,      0,      0, 0, ZERO};
 
460
 
 
461
static opcodez custom_opcode_z;
 
462
 
 
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
 
467
   it for now.
 
468
 
 
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.
 
472
*/
 
473
 
 
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 },
 
555
};
 
556
 
 
557
static opcodeg custom_opcode_g;
 
558
 
 
559
static opcodez internal_number_to_opcode_z(int32 i)
 
560
{   opcodez x;
 
561
    ASSERT_ZCODE();
 
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;
 
567
    i = x.extension;
 
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];
 
573
}
 
574
 
 
575
static void make_opcode_syntax_z(opcodez opco)
 
576
{   char *p = "", *q = opcode_syntax_string;
 
577
    sprintf(q, "%s", opco.name);
 
578
    switch(opco.no)
 
579
    {   case ONE: p=" <operand>"; break;
 
580
        case TWO: p=" <operand1> <operand2>"; break;
 
581
        case EXT:
 
582
        case VAR: p=" <0 to 4 operands>"; break;
 
583
        case VAR_LONG: p=" <0 to 8 operands>"; break;
 
584
    }
 
585
    switch(opco.op_rules)
 
586
    {   case TEXT: sprintf(q+strlen(q), " <text>"); return;
 
587
        case LABEL: sprintf(q+strlen(q), " <label>"); return;
 
588
        case VARIAB:
 
589
            sprintf(q+strlen(q), " <variable>");
 
590
        case CALL:
 
591
            if (opco.op_rules==CALL) sprintf(q+strlen(q), " <routine>");
 
592
            switch(opco.no)
 
593
            {   case ONE: p=""; break;
 
594
                case TWO: p=" <operand>"; break;
 
595
                case EXT:
 
596
                case VAR: p=" <1 to 4 operands>"; break;
 
597
                case VAR_LONG: p=" <1 to 8 operands>"; break;
 
598
            }
 
599
            break;
 
600
    }
 
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>");
 
604
}
 
605
 
 
606
static opcodeg internal_number_to_opcode_g(int32 i)
 
607
{   
 
608
    opcodeg x;
 
609
    if (i == -1) return custom_opcode_g;
 
610
    x = opcodes_table_g[i];
 
611
    return x;
 
612
}
 
613
 
 
614
static void make_opcode_syntax_g(opcodeg opco)
 
615
{
 
616
    int ix;
 
617
    char *cx;
 
618
    char *q = opcode_syntax_string;
 
619
 
 
620
    sprintf(q, "%s", opco.name);
 
621
    sprintf(q+strlen(q), " <%d operand%s", opco.no,
 
622
        ((opco.no==1) ? "" : "s"));
 
623
    if (opco.no) {
 
624
        cx = q+strlen(q);
 
625
        strcpy(cx, ": ");
 
626
        cx += strlen(cx);
 
627
        for (ix=0; ix<opco.no; ix++) {
 
628
            if (ix) {
 
629
                *cx = ' ';
 
630
                cx++;
 
631
            }
 
632
            if (ix == opco.no-1) {
 
633
                if (opco.flags & Br) {
 
634
                    strcpy(cx, "Lb");
 
635
                }
 
636
                else if (opco.flags & St) {
 
637
                    strcpy(cx, "S");
 
638
                }
 
639
                else {
 
640
                    strcpy(cx, "L");
 
641
                }
 
642
            }
 
643
            else if (ix == opco.no-2 && (opco.flags & Br) && (opco.flags & St)) {
 
644
                strcpy(cx, "S");
 
645
            }
 
646
            else if (ix == opco.no-2 && (opco.flags & St2)) {
 
647
                strcpy(cx, "S");
 
648
            }
 
649
            else {
 
650
                strcpy(cx, "L");
 
651
            }
 
652
            cx += strlen(cx);
 
653
            sprintf(cx, "%d", ix+1);
 
654
            cx += strlen(cx);
 
655
        }
 
656
    }
 
657
    sprintf(q+strlen(q), ">");
 
658
}
 
659
 
 
660
 
 
661
/* ========================================================================= */
 
662
/*   The assembler itself does four things:                                  */
 
663
/*                                                                           */
 
664
/*       assembles instructions                                              */
 
665
/*       sets label N to the current code position                           */
 
666
/*       assembles routine headers                                           */
 
667
/*       assembles routine ends                                              */
 
668
/* ------------------------------------------------------------------------- */
 
669
 
 
670
/* This is for Z-code only. */
 
671
static void write_operand(assembly_operand op)
 
672
{   int32 j;
 
673
    if (module_switch && (op.marker != 0))
 
674
    {   if ((op.marker != VARIABLE_MV) && (op.type == SHORT_CONSTANT_OT))
 
675
            op.type = LONG_CONSTANT_OT;
 
676
    }
 
677
    j=op.value;
 
678
    switch(op.type)
 
679
    {   case LONG_CONSTANT_OT:
 
680
            byteout(j/256, op.marker); byteout(j%256, 0); return;
 
681
        case SHORT_CONSTANT_OT:
 
682
            if (op.marker == 0)
 
683
            byteout(j, 0);
 
684
            else byteout(j, 0x80 + op.marker); return;
 
685
        case VARIABLE_OT:
 
686
            byteout(j, (module_switch)?(0x80 + op.marker):0); return;
 
687
        case CONSTANT_OT:
 
688
        case HALFCONSTANT_OT:
 
689
        case BYTECONSTANT_OT:
 
690
        case ZEROCONSTANT_OT:
 
691
        case SYSFUN_OT:
 
692
        case DEREFERENCE_OT:
 
693
        case LOCALVAR_OT:
 
694
        case GLOBALVAR_OT:
 
695
            compiler_error("Glulx OT in Z-code assembly operand.");
 
696
            return;
 
697
    }
 
698
}
 
699
 
 
700
extern void assemblez_instruction(assembly_instruction *AI)
 
701
{
 
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;
 
706
    opcodez opco;
 
707
 
 
708
    ASSERT_ZCODE();
 
709
 
 
710
    offset = zmachine_pc;
 
711
 
 
712
    no_instructions++;
 
713
 
 
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);
 
721
        }
 
722
        next_sequence_point++;
 
723
    }
 
724
 
 
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]);
 
729
        return;
 
730
    }
 
731
 
 
732
    if (execution_never_reaches_here)
 
733
        warning("This statement can never be reached");
 
734
 
 
735
    operand_rules = opco.op_rules;
 
736
    execution_never_reaches_here = ((opco.flags & Rf) != 0);
 
737
 
 
738
    if (opco.flags2_set != 0) flags2_requirements[opco.flags2_set] = 1;
 
739
 
 
740
    no_operands_given = AI->operand_count;
 
741
 
 
742
    if ((opco.no == TWO) && ((no_operands_given==3)||(no_operands_given==4)))
 
743
        opco.no = VAR;
 
744
 
 
745
    /* 1. Write the opcode byte(s) */
 
746
 
 
747
    start_pc = zcode_holding_area + zcode_ha_size;
 
748
 
 
749
    switch(opco.no)
 
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;
 
759
    }
 
760
    byteout(opco.code + topbits, 0);
 
761
 
 
762
    operands_pc = zcode_holding_area + zcode_ha_size;
 
763
 
 
764
    /* 2. Dispose of the special rules LABEL and TEXT */
 
765
 
 
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;
 
770
    }
 
771
 
 
772
    if (operand_rules==TEXT)
 
773
    {   int32 i;
 
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;
 
778
        zmachine_pc += j;
 
779
        goto Instruction_Done;
 
780
    }
 
781
 
 
782
    /* 3. Sort out the operands */
 
783
 
 
784
    if ((no_operands_given < min) || (no_operands_given > max))
 
785
        goto OpcodeSyntaxError;
 
786
 
 
787
    switch(opco.no)
 
788
    {   case VAR:
 
789
        case VAR_LONG:
 
790
            byteout(0, 0);
 
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++)
 
794
            {   int multi, mask;
 
795
                switch(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;
 
800
                }
 
801
                o1 = AI->operand[j];
 
802
                write_operand(o1);
 
803
                if (j<4)
 
804
                    types_byte1 = (types_byte1 & (~mask)) + o1.type*multi;
 
805
                else
 
806
                    types_byte2 = (types_byte2 & (~mask)) + o1.type*multi;
 
807
            }
 
808
            *operands_pc=types_byte1;
 
809
            if (opco.no == VAR_LONG) *(operands_pc+1)=types_byte2;
 
810
            break;
 
811
 
 
812
        case ONE:
 
813
            o1 = AI->operand[0];
 
814
            *start_pc=(*start_pc) + o1.type*0x10;
 
815
            write_operand(o1);
 
816
            break;
 
817
 
 
818
        case TWO:
 
819
            o1 = AI->operand[0];
 
820
            o2 = AI->operand[1];
 
821
 
 
822
            /* Transfer to VAR form if either operand is a long constant */
 
823
 
 
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);
 
827
            }
 
828
            else
 
829
            {   if (o1.type==VARIABLE_OT) *start_pc=(*start_pc) + 0x40;
 
830
                if (o2.type==VARIABLE_OT) *start_pc=(*start_pc) + 0x20;
 
831
            }
 
832
            write_operand(o1);
 
833
            write_operand(o2);
 
834
            break;
 
835
    }
 
836
 
 
837
    /* 4. Assemble a Store destination, if needed */
 
838
 
 
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;
 
843
        o1.marker = 0;
 
844
 
 
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  */
 
848
 
 
849
        if ((o1.value >= MAX_LOCAL_VARIABLES) && (o1.value < 249))
 
850
            o1.marker = VARIABLE_MV;
 
851
        write_operand(o1);
 
852
    }
 
853
 
 
854
    /* 5. Assemble a branch, if needed */
 
855
 
 
856
    if (AI->branch_label_number != -1)
 
857
    {   int32 addr, long_form;
 
858
        int branch_on_true = (AI->branch_flag)?1:0;
 
859
 
 
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 */
 
865
            default:
 
866
                long_form = 1; addr = AI->branch_label_number;
 
867
                break;
 
868
        }
 
869
        if (addr > 0x7fff) fatalerror("Too many branch points in routine.");
 
870
        if (long_form==1)
 
871
        {   byteout(branch_on_true*0x80 + addr/256, BRANCH_MV);
 
872
            byteout(addr%256, 0);
 
873
        }
 
874
        else
 
875
            byteout(branch_on_true*0x80+ 0x40 + (addr&0x3f), 0);
 
876
    }
 
877
 
 
878
    Instruction_Done:
 
879
 
 
880
    if ((asm_trace_level > 0) && (veneer_mode == FALSE))
 
881
    {   int i;
 
882
        printf("%5d  +%05lx %3s %-12s ", ErrorReport.line_number,
 
883
            ((long int) offset),
 
884
            (at_seq_point)?"<*>":"   ", opco.name);
 
885
 
 
886
        if ((AI->internal_number == print_zc)
 
887
            || (AI->internal_number == print_ret_zc))
 
888
        {   printf("\"");
 
889
            for (i=0;(AI->text)[i]!=0 && i<35; i++) printf("%c",(AI->text)[i]);
 
890
            if (i == 35) printf("...");
 
891
            printf("\"");
 
892
        }
 
893
 
 
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]); }
 
898
                else
 
899
                    printf("%s", variable_name((AI->operand[0]).value));
 
900
            }
 
901
            else
 
902
            if ((i==0) && (opco.op_rules == LABEL))
 
903
            {   printf("L%d", AI->operand[0].value);
 
904
            }
 
905
            else print_operand_z(AI->operand[i]);
 
906
            printf(" ");
 
907
        }
 
908
        if (AI->store_variable_number != -1)
 
909
        {   assembly_operand AO;
 
910
            printf("-> ");
 
911
            AO.type = VARIABLE_OT; AO.value = AI->store_variable_number;
 
912
            print_operand_z(AO); printf(" ");
 
913
        }
 
914
 
 
915
        switch(AI->branch_label_number)
 
916
        {   case -4: printf("rtrue if %s", (AI->branch_flag)?"TRUE":"FALSE");
 
917
                break;
 
918
            case -3: printf("rfalse if %s", (AI->branch_flag)?"TRUE":"FALSE");
 
919
                break;
 
920
            case -2: printf("(no branch)"); break;
 
921
            case -1: break;
 
922
            default:
 
923
                printf("to L%d if %s", AI->branch_label_number,
 
924
                   (AI->branch_flag)?"TRUE":"FALSE"); break;
 
925
        }
 
926
 
 
927
        if (asm_trace_level>=2)
 
928
        {   for (j=0;start_pc<zcode_holding_area + zcode_ha_size;
 
929
                 j++, start_pc++)
 
930
            {   if (j%16==0) printf("\n                               ");
 
931
                printf("%02x ", *start_pc);
 
932
            }
 
933
        }
 
934
        printf("\n");
 
935
    }
 
936
 
 
937
    if (module_switch) flush_link_data();
 
938
 
 
939
    return;
 
940
 
 
941
    OpcodeSyntaxError:
 
942
 
 
943
    make_opcode_syntax_z(opco);
 
944
    error_named("Assembly mistake: syntax is", opcode_syntax_string);
 
945
}
 
946
 
 
947
extern void assembleg_instruction(assembly_instruction *AI)
 
948
{
 
949
    uchar *start_pc, *opmodes_pc;
 
950
    int32 offset, j;
 
951
    int no_operands_given, at_seq_point = FALSE;
 
952
    int ix, k;
 
953
    opcodeg opco;
 
954
 
 
955
    ASSERT_GLULX();
 
956
 
 
957
    offset = zmachine_pc;
 
958
 
 
959
    no_instructions++;
 
960
 
 
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);
 
968
        }
 
969
        next_sequence_point++;
 
970
    }
 
971
 
 
972
    opco = internal_number_to_opcode_g(AI->internal_number);
 
973
 
 
974
    if (execution_never_reaches_here)
 
975
        warning("This statement can never be reached");
 
976
 
 
977
    execution_never_reaches_here = ((opco.flags & Rf) != 0);
 
978
 
 
979
    no_operands_given = AI->operand_count;
 
980
 
 
981
    /* 1. Write the opcode byte(s) */
 
982
 
 
983
    start_pc = zcode_holding_area + zcode_ha_size; 
 
984
 
 
985
    if (opco.code < 0x80) {
 
986
      byteout(opco.code, 0);
 
987
    }
 
988
    else if (opco.code < 0x4000) {
 
989
      byteout(((opco.code >> 8) & 0xFF) | 0x80, 0);
 
990
      byteout((opco.code & 0xFF), 0);
 
991
    }
 
992
    else {
 
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);
 
997
    }
 
998
 
 
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. */
 
1002
 
 
1003
    opmodes_pc = zcode_holding_area + zcode_ha_size;
 
1004
 
 
1005
    for (ix=0; ix<opco.no; ix+=2) {
 
1006
      byteout(0, 0);
 
1007
    }
 
1008
 
 
1009
    /* 2. Dispose of the special rules */
 
1010
    /* There aren't any in Glulx. */
 
1011
 
 
1012
    /* 3. Sort out the operands */
 
1013
 
 
1014
    if (no_operands_given != opco.no) {
 
1015
      goto OpcodeSyntaxError;
 
1016
    }
 
1017
 
 
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;
 
1022
 
 
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; 
 
1027
            }
 
1028
            if (k == -2) {
 
1029
                k = 2; /* branch no-op */
 
1030
                type = BYTECONSTANT_OT;
 
1031
                marker = 0;
 
1032
            }
 
1033
            else if (k == -3) {
 
1034
                k = 0; /* branch return 0 */
 
1035
                type = ZEROCONSTANT_OT;
 
1036
                marker = 0;
 
1037
            }
 
1038
            else if (k == -4) {
 
1039
                k = 1; /* branch return 1 */
 
1040
                type = BYTECONSTANT_OT;
 
1041
                marker = 0;
 
1042
            }
 
1043
            else {
 
1044
                /* branch to label k */
 
1045
                j = subtract_pointers((zcode_holding_area + zcode_ha_size), 
 
1046
                    opmodes_pc);
 
1047
                j = 2*j - ix;
 
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; 
 
1052
                }
 
1053
            }
 
1054
        }
 
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; 
 
1062
        }
 
1063
    }
 
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; 
 
1070
        }
 
1071
    }
 
1072
 
 
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. */
 
1079
        }
 
1080
 
 
1081
      switch (type) {
 
1082
      case LONG_CONSTANT_OT:
 
1083
      case SHORT_CONSTANT_OT:
 
1084
      case VARIABLE_OT:
 
1085
        j = 0;
 
1086
        compiler_error("Z-code OT in Glulx assembly operand.");
 
1087
        break;
 
1088
      case CONSTANT_OT:
 
1089
        j = 3;
 
1090
        byteout((k >> 24) & 0xFF, marker);
 
1091
        byteout((k >> 16) & 0xFF, 0);
 
1092
        byteout((k >> 8) & 0xFF, 0);
 
1093
        byteout((k & 0xFF), 0);
 
1094
        break;
 
1095
      case HALFCONSTANT_OT:
 
1096
        j = 2;
 
1097
        byteout((k >> 8) & 0xFF, marker);
 
1098
        byteout((k & 0xFF), 0);
 
1099
        break;
 
1100
      case BYTECONSTANT_OT:
 
1101
        j = 1;
 
1102
        byteout((k & 0xFF), marker);
 
1103
        break;
 
1104
      case ZEROCONSTANT_OT:
 
1105
        j = 0;
 
1106
        break;
 
1107
      case DEREFERENCE_OT:
 
1108
        j = 7;
 
1109
        byteout((k >> 24) & 0xFF, marker);
 
1110
        byteout((k >> 16) & 0xFF, 0);
 
1111
        byteout((k >> 8) & 0xFF, 0);
 
1112
        byteout((k & 0xFF), 0);
 
1113
        break;
 
1114
      case GLOBALVAR_OT:
 
1115
        /* Global variable -- a constant address. */
 
1116
        k -= MAX_LOCAL_VARIABLES;
 
1117
        if (0) {
 
1118
            /* We could write the value as a marker and patch it later... */
 
1119
            j = 7;
 
1120
            byteout(((k) >> 24) & 0xFF, VARIABLE_MV);
 
1121
            byteout(((k) >> 16) & 0xFF, 0);
 
1122
            byteout(((k) >> 8) & 0xFF, 0);
 
1123
            byteout(((k) & 0xFF), 0);
 
1124
        }
 
1125
        else {
 
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 */
 
1130
            if (k <= 255) {
 
1131
                j = 13;
 
1132
                byteout(((k) & 0xFF), 0);
 
1133
            }
 
1134
            else if (k <= 65535) {
 
1135
                j = 14;
 
1136
                byteout(((k) >> 8) & 0xFF, 0);
 
1137
                byteout(((k) & 0xFF), 0);
 
1138
            }
 
1139
            else {
 
1140
                j = 15;
 
1141
                byteout(((k) >> 24) & 0xFF, 0);
 
1142
                byteout(((k) >> 16) & 0xFF, 0);
 
1143
                byteout(((k) >> 8) & 0xFF, 0);
 
1144
                byteout(((k) & 0xFF), 0);       
 
1145
            }
 
1146
        }
 
1147
        break;
 
1148
      case LOCALVAR_OT:
 
1149
        if (k == 0) {
 
1150
            /* Stack-pointer magic variable */
 
1151
            j = 8; 
 
1152
        }
 
1153
        else {
 
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. */
 
1157
            if ((k-1) < 64) {
 
1158
                j = 9;
 
1159
                byteout((k-1)*4, 0);
 
1160
            }
 
1161
            else {
 
1162
                j = 10;
 
1163
                byteout((((k-1)*4) >> 8) & 0xFF, 0);
 
1164
                byteout(((k-1)*4) & 0xFF, 0);
 
1165
            }
 
1166
        }
 
1167
        break;
 
1168
      default:
 
1169
        j = 0;
 
1170
        break;
 
1171
      }
 
1172
 
 
1173
      if (ix & 1)
 
1174
          j = (j << 4);
 
1175
      opmodes_pc[ix/2] |= j;
 
1176
    }
 
1177
 
 
1178
    /* Print assembly trace. */
 
1179
    if ((asm_trace_level > 0) && (veneer_mode == FALSE)) {
 
1180
      int i;
 
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)
 
1187
                printf("to rtrue");
 
1188
            else if (AI->operand[i].value == -3)
 
1189
                printf("to rfalse");
 
1190
            else
 
1191
                printf("to L%d", AI->operand[i].value);
 
1192
            }
 
1193
          else {
 
1194
            print_operand_g(AI->operand[i]);
 
1195
          }
 
1196
          printf(" ");
 
1197
      }
 
1198
 
 
1199
      if (asm_trace_level>=2) {
 
1200
        for (j=0;
 
1201
            start_pc<zcode_holding_area + zcode_ha_size;
 
1202
            j++, start_pc++) {
 
1203
            if (j%16==0) printf("\n                               ");
 
1204
            if (0) {
 
1205
                printf("%02x ", *start_pc);
 
1206
            }
 
1207
            else {
 
1208
                printf("%02x", *start_pc);
 
1209
                if (zcode_markers[start_pc-zcode_holding_area])
 
1210
                    printf("{%02x}", zcode_markers[start_pc-zcode_holding_area]);
 
1211
                printf(" ");
 
1212
            }
 
1213
        }
 
1214
      }
 
1215
      printf("\n");
 
1216
    }
 
1217
 
 
1218
    if (module_switch) flush_link_data();
 
1219
 
 
1220
    return;
 
1221
 
 
1222
    OpcodeSyntaxError:
 
1223
 
 
1224
    make_opcode_syntax_g(opco);
 
1225
    error_named("Assembly mistake: syntax is", opcode_syntax_string);
 
1226
}
 
1227
 
 
1228
extern void assemble_label_no(int n)
 
1229
{
 
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;
 
1235
}
 
1236
 
 
1237
extern void define_symbol_label(int symbol)
 
1238
{   label_symbols[svals[symbol]] = symbol;
 
1239
}
 
1240
 
 
1241
extern int32 assemble_routine_header(int no_locals,
 
1242
    int routine_asterisked, char *name, dbgl *line_ref, int embedded_flag,
 
1243
    int the_symbol)
 
1244
{   int i, rv;
 
1245
    int stackargs = FALSE;
 
1246
 
 
1247
    execution_never_reaches_here = FALSE;
 
1248
 
 
1249
    routine_locals = no_locals;
 
1250
    for (i=0; i<MAX_LOCAL_VARIABLES; i++) variable_usage[i] = FALSE;
 
1251
 
 
1252
    if (no_locals >= 1 
 
1253
      && !strcmp(local_variables.keywords[0], "_vararg_count")) {
 
1254
      stackargs = TRUE;
 
1255
    }
 
1256
 
 
1257
    if (veneer_mode) routine_starts_line = -1;
 
1258
    else routine_starts_line = ErrorReport.line_number
 
1259
             + 0x10000*ErrorReport.file_number;
 
1260
 
 
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));
 
1265
        printf("\n\n");
 
1266
    }
 
1267
 
 
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);
 
1275
 
 
1276
        for (i=1; i<=no_locals; i++) write_debug_string(variable_name(i));
 
1277
 
 
1278
        write_debug_byte(0);
 
1279
 
 
1280
        routine_start_pc = zmachine_pc;
 
1281
    }
 
1282
 
 
1283
    /*  Update the routine counter                                           */
 
1284
 
 
1285
    no_routines++;
 
1286
 
 
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.)                                */
 
1291
 
 
1292
    if (!glulx_mode) {
 
1293
 
 
1294
      if (stackargs) 
 
1295
        warning("Z-code does not support stack-argument function definitions.");
 
1296
 
 
1297
      byteout(no_locals, 0);
 
1298
 
 
1299
      /*  Not the packed address, but the scaled offset from code area start:  */
 
1300
 
 
1301
      rv = zmachine_pc/scale_factor;
 
1302
 
 
1303
      if (instruction_set_number<5)
 
1304
          for (i=0; i<no_locals; i++) { byteout(0,0); byteout(0,0); }
 
1305
 
 
1306
      next_label = 0; next_sequence_point = 0; last_label = -1;
 
1307
 
 
1308
      /*  Compile code to print out text like "a=3, b=4, c=5" when the       */
 
1309
      /*  function is called, if it's required.                              */
 
1310
 
 
1311
      if ((routine_asterisked) || (define_INFIX_switch))
 
1312
      {   char fnt[80]; assembly_operand PV, RFA, CON, STP, SLF; int ln, ln2;
 
1313
 
 
1314
          ln = next_label++;
 
1315
          ln2 = next_label++;
 
1316
 
 
1317
          if (define_INFIX_switch)
 
1318
          {
 
1319
                if (embedded_flag)
 
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);
 
1323
            }
 
1324
            else
 
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);
 
1335
            }
 
1336
        }
 
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);
 
1344
            }
 
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);
 
1349
        }
 
1350
        assemble_label_no(ln);
 
1351
        sprintf(fnt, ") ]^"); AI.text = fnt;
 
1352
        assemblez_0(print_zc);
 
1353
        assemble_label_no(ln2);
 
1354
      }
 
1355
 
 
1356
    }
 
1357
    else {
 
1358
      rv = zmachine_pc;
 
1359
 
 
1360
      if (stackargs)
 
1361
        byteout(0xC0, 0); /* Glulx type byte for function */
 
1362
      else
 
1363
        byteout(0xC1, 0); /* Glulx type byte for function */
 
1364
 
 
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. */
 
1368
      i = no_locals;
 
1369
      while (i) {
 
1370
        int j = i;
 
1371
        if (j > 255)
 
1372
          j = 255;
 
1373
        byteout(4, 0); 
 
1374
        byteout(j, 0);
 
1375
        i -= j;
 
1376
      }
 
1377
      /* Terminate the list with a (0, 0) pair. */
 
1378
      byteout(0, 0);
 
1379
      byteout(0, 0);
 
1380
 
 
1381
      if (stackargs) {
 
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);
 
1386
      }
 
1387
 
 
1388
      next_label = 0; next_sequence_point = 0; last_label = -1; 
 
1389
 
 
1390
      if (define_INFIX_switch) {
 
1391
        if (embedded_flag) {
 
1392
        }
 
1393
        else {
 
1394
            i = no_named_routines++;
 
1395
            named_routine_symbols[i] = the_symbol;
 
1396
        }
 
1397
      }
 
1398
    }
 
1399
 
 
1400
    return rv;
 
1401
}
 
1402
 
 
1403
void assemble_routine_end(int embedded_flag, dbgl *line_ref)
 
1404
{   int32 i;
 
1405
 
 
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"            */
 
1411
    /* properties).                                                          */
 
1412
 
 
1413
    if (!execution_never_reaches_here)
 
1414
    {   
 
1415
      if (!glulx_mode) {
 
1416
        if (embedded_flag) assemblez_0(rfalse_zc);
 
1417
                      else assemblez_0(rtrue_zc);
 
1418
      }
 
1419
      else {
 
1420
        assembly_operand AO;
 
1421
        if (embedded_flag) 
 
1422
            AO = zero_operand;
 
1423
        else 
 
1424
            AO = one_operand;
 
1425
        assembleg_1(return_gc, AO);
 
1426
      }
 
1427
    }
 
1428
 
 
1429
    /* Dump the contents of the current routine into longer-term Z-code
 
1430
       storage                                                               */
 
1431
 
 
1432
    if (!glulx_mode)
 
1433
      transfer_routine_z();
 
1434
    else
 
1435
      transfer_routine_g();
 
1436
 
 
1437
    /* Tell the debugging file about the routine just ended.                 */
 
1438
 
 
1439
    if (debugfile_switch)
 
1440
    {
 
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);
 
1446
 
 
1447
        for (i=0; i<next_sequence_point; i++)
 
1448
        {   int32 j = label_offsets[sequence_point_labels[i]]
 
1449
                - routine_start_pc;
 
1450
 
 
1451
            write_dbgl(sequence_point_refs[i]);
 
1452
            write_debug_byte(j / 256);
 
1453
            write_debug_byte(j % 256);
 
1454
        }
 
1455
 
 
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);
 
1461
    }
 
1462
 
 
1463
    /* Issue warnings about any local variables not used in the routine. */
 
1464
 
 
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);
 
1469
 
 
1470
    for (i=0; i<next_label; i++)
 
1471
    {   int j = label_symbols[i];
 
1472
        if (j != -1)
 
1473
        {   if (sflags[j] & CHANGE_SFLAG)
 
1474
                error_named_at("Routine contains no such label as",
 
1475
                    (char *) symbs[j], slines[j]);
 
1476
            else
 
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;
 
1481
        }
 
1482
    }
 
1483
    no_sequence_points += next_sequence_point;
 
1484
    next_label = 0; next_sequence_point = 0;
 
1485
}
 
1486
 
 
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
/* ------------------------------------------------------------------------- */
 
1498
 
 
1499
static int32 adjusted_pc;
 
1500
 
 
1501
static void transfer_to_temp_file(uchar *c)
 
1502
{   fputc(*c,Temp2_fp);
 
1503
    adjusted_pc++;
 
1504
}
 
1505
 
 
1506
static void transfer_to_zcode_area(uchar *c)
 
1507
{   write_byte_to_memory_block(&zcode_area, adjusted_pc++, *c);
 
1508
}
 
1509
 
 
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 *);
 
1514
 
 
1515
    adjusted_pc = zmachine_pc - zcode_ha_size; rstart_pc = adjusted_pc;
 
1516
 
 
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);
 
1520
    }
 
1521
 
 
1522
    transfer_byte =
 
1523
        (temporary_files_switch)?transfer_to_temp_file:transfer_to_zcode_area;
 
1524
 
 
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.                                     */
 
1528
 
 
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;
 
1540
            }
 
1541
        }
 
1542
    }
 
1543
 
 
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. */
 
1551
 
 
1552
    if (next_label > 0)
 
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]);
 
1558
        }
 
1559
 
 
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];
 
1568
            }
 
1569
           if (zcode_markers[i] != DELETED_MV) new_pc++;
 
1570
        }
 
1571
    }
 
1572
 
 
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.          */
 
1576
 
 
1577
    for (i=0, new_pc=adjusted_pc; i<zcode_ha_size; i++)
 
1578
    {   switch(zcode_markers[i])
 
1579
        { case BRANCH_MV:
 
1580
            long_form = 1; if (zcode_markers[i+1] == DELETED_MV) long_form = 0;
 
1581
 
 
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;
 
1585
 
 
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;
 
1590
 
 
1591
            addr=addr&0x3fff;
 
1592
            if (long_form==1)
 
1593
            {   zcode_holding_area[i] = branch_on_true + addr/256;
 
1594
                zcode_holding_area[i+1] = addr%256;
 
1595
            }
 
1596
            else
 
1597
            {   if (addr >= 64)
 
1598
                {   compiler_error("Label out of range for branch");
 
1599
                    printf("Addr is %04x\n", addr);
 
1600
                }
 
1601
                zcode_holding_area[i] = branch_on_true + 0x40 + (addr&0x3f);
 
1602
            }
 
1603
            transfer_byte(zcode_holding_area + i); new_pc++;
 
1604
            break;
 
1605
 
 
1606
          case LABEL_MV:
 
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++;
 
1615
            break;
 
1616
 
 
1617
          case DELETED_MV:
 
1618
            break;
 
1619
 
 
1620
          default:
 
1621
            switch(zcode_markers[i] & 0x7f)
 
1622
            {   case NULL_MV: break;
 
1623
                case VARIABLE_MV:
 
1624
                case OBJECT_MV:
 
1625
                case ACTION_MV:
 
1626
                case IDENT_MV:
 
1627
                    if (!module_switch) break;
 
1628
                default:
 
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);
 
1633
                        break;
 
1634
                    }
 
1635
 
 
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);
 
1643
                    break;
 
1644
            }
 
1645
            transfer_byte(zcode_holding_area + i); new_pc++;
 
1646
            break;
 
1647
        }
 
1648
    }
 
1649
 
 
1650
    if (asm_trace_level >= 3)
 
1651
    {   printf("After branch optimisation, routine length is %d bytes\n",
 
1652
             new_pc - rstart_pc);
 
1653
    }
 
1654
 
 
1655
    /*  Insert null bytes if necessary to ensure the next routine address is */
 
1656
    /*  expressible as a packed address                                      */
 
1657
 
 
1658
    {   uchar zero[1];
 
1659
        zero[0] = 0;
 
1660
        if (oddeven_packing_switch)
 
1661
            while ((adjusted_pc%(scale_factor*2))!=0) transfer_byte(zero);
 
1662
        else
 
1663
            while ((adjusted_pc%scale_factor)!=0) transfer_byte(zero);
 
1664
    }
 
1665
 
 
1666
    zmachine_pc = adjusted_pc;
 
1667
    zcode_ha_size = 0;
 
1668
}
 
1669
 
 
1670
static void transfer_routine_g(void)
 
1671
{   int32 i, j, pc, new_pc, label, form_len, offset_of_next, addr,
 
1672
          rstart_pc;
 
1673
    void (* transfer_byte)(uchar *);
 
1674
 
 
1675
    adjusted_pc = zmachine_pc - zcode_ha_size; rstart_pc = adjusted_pc;
 
1676
 
 
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);
 
1680
    }
 
1681
 
 
1682
    transfer_byte =
 
1683
        (temporary_files_switch)?transfer_to_temp_file:transfer_to_zcode_area;
 
1684
 
 
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.                                     */
 
1688
 
 
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);
 
1692
        int32 opmodebyte;
 
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;
 
1713
            else
 
1714
                zcode_holding_area[opmodebyte] = 
 
1715
                    (zcode_holding_area[opmodebyte] & 0x0F) | 0x10;
 
1716
        }
 
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;
 
1725
            else
 
1726
                zcode_holding_area[opmodebyte] = 
 
1727
                    (zcode_holding_area[opmodebyte] & 0x0F) | 0x20;
 
1728
        }
 
1729
      }
 
1730
    }
 
1731
 
 
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]);
 
1745
      }
 
1746
 
 
1747
      for (i=0, pc=adjusted_pc, new_pc=adjusted_pc, label = first_label;
 
1748
        i<zcode_ha_size; 
 
1749
        i++, pc++) {
 
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];
 
1756
        }
 
1757
        if (zcode_markers[i] != DELETED_MV) new_pc++;
 
1758
      }
 
1759
    }
 
1760
 
 
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.          */
 
1764
 
 
1765
    for (i=0, new_pc=adjusted_pc; i<zcode_ha_size; i++) {
 
1766
 
 
1767
      if (zcode_markers[i] >= BRANCH_MV && zcode_markers[i] < BRANCHMAX_MV) {
 
1768
        form_len = 4;
 
1769
        if (zcode_markers[i+1] == DELETED_MV) {
 
1770
            form_len = 1;
 
1771
        }
 
1772
        else {
 
1773
            if (zcode_markers[i+2] == DELETED_MV)
 
1774
                form_len = 2;
 
1775
        }
 
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]));
 
1780
 
 
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
 
1783
           after it. */
 
1784
        offset_of_next = new_pc + form_len;
 
1785
 
 
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")));
 
1791
        }
 
1792
        if (form_len == 1) {
 
1793
            if (addr < -0x80 && addr >= 0x80) {
 
1794
                error("*** Label out of range for byte branch ***");
 
1795
            }
 
1796
        zcode_holding_area[i] = (addr) & 0xFF;
 
1797
        }
 
1798
        else if (form_len == 2) {
 
1799
            if (addr < -0x8000 && addr >= 0x8000) {
 
1800
                error("*** Label out of range for short branch ***");
 
1801
            }
 
1802
            zcode_holding_area[i] = (addr >> 8) & 0xFF;
 
1803
            zcode_holding_area[i+1] = (addr) & 0xFF;
 
1804
        }
 
1805
        else {
 
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;
 
1810
        }
 
1811
        transfer_byte(zcode_holding_area + i); new_pc++;
 
1812
      }
 
1813
      else if (zcode_markers[i] == LABEL_MV) {
 
1814
          error("*** No LABEL opcodes in Glulx ***");
 
1815
      }
 
1816
      else if (zcode_markers[i] == DELETED_MV) {
 
1817
        /* skip it */
 
1818
      }
 
1819
      else {
 
1820
        switch(zcode_markers[i] & 0x7f) {
 
1821
        case NULL_MV: 
 
1822
            break;
 
1823
        case ACTION_MV:
 
1824
        case IDENT_MV:
 
1825
            if (!module_switch) break;
 
1826
        case OBJECT_MV:
 
1827
        case VARIABLE_MV:
 
1828
        default:
 
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);
 
1833
                break;
 
1834
            }
 
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).
 
1839
          */
 
1840
          write_byte_to_memory_block(&zcode_backpatch_table,
 
1841
            zcode_backpatch_size++,
 
1842
            zcode_markers[i]);
 
1843
          write_byte_to_memory_block(&zcode_backpatch_table,
 
1844
            zcode_backpatch_size++,
 
1845
            4);
 
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));
 
1854
          break;
 
1855
        }
 
1856
        transfer_byte(zcode_holding_area + i); new_pc++;
 
1857
      }
 
1858
    }
 
1859
 
 
1860
    if (asm_trace_level >= 3)
 
1861
    {   printf("After branch optimisation, routine length is %d bytes\n",
 
1862
             new_pc - rstart_pc);
 
1863
    }
 
1864
 
 
1865
    zmachine_pc = adjusted_pc;
 
1866
    zcode_ha_size = 0;
 
1867
}
 
1868
 
 
1869
 
 
1870
/* ========================================================================= */
 
1871
/*   Front ends for the instruction assembler: convenient shorthand forms    */
 
1872
/*   used in various code generation routines all over Inform.               */
 
1873
/* ------------------------------------------------------------------------- */
 
1874
 
 
1875
void assemble_jump(int n)
 
1876
{
 
1877
    if (!glulx_mode)
 
1878
        assemblez_jump(n);
 
1879
    else
 
1880
        assembleg_jump(n);
 
1881
}
 
1882
 
 
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);
 
1889
}
 
1890
 
 
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);
 
1897
}
 
1898
 
 
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);
 
1906
}
 
1907
 
 
1908
void assemblez_1(int internal_number, assembly_operand o1)
 
1909
{   AI.internal_number = internal_number;
 
1910
    AI.operand_count = 1;
 
1911
    AI.operand[0] = o1;
 
1912
    AI.store_variable_number = -1;
 
1913
    AI.branch_label_number = -1;
 
1914
    assemblez_instruction(&AI);
 
1915
}
 
1916
 
 
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;
 
1921
    AI.operand[0] = o1;
 
1922
    AI.store_variable_number = st.value;
 
1923
    AI.branch_label_number = -1;
 
1924
    assemblez_instruction(&AI);
 
1925
}
 
1926
 
 
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;
 
1931
    AI.operand[0] = o1;
 
1932
    AI.branch_label_number = label;
 
1933
    AI.store_variable_number = -1;
 
1934
    AI.branch_flag = flag;
 
1935
    assemblez_instruction(&AI);
 
1936
}
 
1937
 
 
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;
 
1942
    AI.operand[0] = o1;
 
1943
    AI.operand[1] = o2;
 
1944
    AI.store_variable_number = -1;
 
1945
    AI.branch_label_number = -1;
 
1946
    assemblez_instruction(&AI);
 
1947
}
 
1948
 
 
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;
 
1953
    AI.operand[0] = o1;
 
1954
    AI.operand[1] = o2;
 
1955
    AI.operand[2] = o3;
 
1956
    AI.store_variable_number = -1;
 
1957
    AI.branch_label_number = -1;
 
1958
    assemblez_instruction(&AI);
 
1959
}
 
1960
 
 
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;
 
1966
    AI.operand[0] = o1;
 
1967
    AI.operand[1] = o2;
 
1968
    AI.operand[2] = o3;
 
1969
    AI.store_variable_number = st.value;
 
1970
    AI.branch_label_number = -1;
 
1971
    assemblez_instruction(&AI);
 
1972
}
 
1973
 
 
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;
 
1979
    AI.operand[0] = o1;
 
1980
    AI.operand[1] = o2;
 
1981
    AI.operand[2] = o3;
 
1982
    AI.store_variable_number = -1;
 
1983
    AI.branch_label_number = label;
 
1984
    AI.branch_flag = flag;
 
1985
    assemblez_instruction(&AI);
 
1986
}
 
1987
 
 
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;
 
1993
    AI.operand[0] = o1;
 
1994
    AI.operand[1] = o2;
 
1995
    AI.operand[2] = o3;
 
1996
    AI.operand[3] = o4;
 
1997
    AI.store_variable_number = -1;
 
1998
    AI.branch_label_number = -1;
 
1999
    assemblez_instruction(&AI);
 
2000
}
 
2001
 
 
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;
 
2007
    AI.operand[0] = o1;
 
2008
    AI.operand[1] = o2;
 
2009
    AI.operand[2] = o3;
 
2010
    AI.operand[3] = o4;
 
2011
    AI.operand[4] = o5;
 
2012
    AI.store_variable_number = -1;
 
2013
    AI.branch_label_number = -1;
 
2014
    assemblez_instruction(&AI);
 
2015
}
 
2016
 
 
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;
 
2022
    AI.operand[0] = o1;
 
2023
    AI.operand[1] = o2;
 
2024
    AI.operand[2] = o3;
 
2025
    AI.operand[3] = o4;
 
2026
    AI.operand[4] = o5;
 
2027
    AI.operand[5] = o6;
 
2028
    AI.store_variable_number = -1;
 
2029
    AI.branch_label_number = -1;
 
2030
    assemblez_instruction(&AI);
 
2031
}
 
2032
 
 
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;
 
2038
    AI.operand[0] = o1;
 
2039
    AI.operand[1] = o2;
 
2040
    AI.operand[2] = o3;
 
2041
    AI.operand[3] = o4;
 
2042
    AI.store_variable_number = -1;
 
2043
    AI.branch_label_number = label;
 
2044
    AI.branch_flag = flag;
 
2045
    assemblez_instruction(&AI);
 
2046
}
 
2047
 
 
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;
 
2053
    AI.operand[0] = o1;
 
2054
    AI.operand[1] = o2;
 
2055
    AI.operand[2] = o3;
 
2056
    AI.operand[3] = o4;
 
2057
    AI.store_variable_number = st.value;
 
2058
    AI.branch_label_number = -1;
 
2059
    assemblez_instruction(&AI);
 
2060
}
 
2061
 
 
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;
 
2066
    AI.operand[0] = o1;
 
2067
    AI.operand[1] = o2;
 
2068
    AI.store_variable_number = st.value;
 
2069
    AI.branch_label_number = -1;
 
2070
    assemblez_instruction(&AI);
 
2071
}
 
2072
 
 
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;
 
2077
    AI.operand[0] = o1;
 
2078
    AI.operand[1] = o2;
 
2079
    AI.branch_label_number = label;
 
2080
    AI.store_variable_number = -1;
 
2081
    AI.branch_flag = flag;
 
2082
    assemblez_instruction(&AI);
 
2083
}
 
2084
 
 
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;
 
2089
    AI.operand[0] = o1;
 
2090
    AI.branch_label_number = label;
 
2091
    AI.store_variable_number = st.value;
 
2092
    AI.branch_flag = flag;
 
2093
    assemblez_instruction(&AI);
 
2094
}
 
2095
 
 
2096
extern void assemblez_inc(assembly_operand o1)
 
2097
{   int m = 0;
 
2098
    if ((o1.value >= MAX_LOCAL_VARIABLES) 
 
2099
        && (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
 
2100
            m = VARIABLE_MV;
 
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);
 
2109
}
 
2110
 
 
2111
extern void assemblez_dec(assembly_operand o1)
 
2112
{   int m = 0;
 
2113
    if ((o1.value >= MAX_LOCAL_VARIABLES) 
 
2114
        && (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
 
2115
            m = VARIABLE_MV;
 
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);
 
2124
}
 
2125
 
 
2126
extern void assemblez_store(assembly_operand o1, assembly_operand o2)
 
2127
{   int m = 0;
 
2128
    if ((o1.value >= MAX_LOCAL_VARIABLES)
 
2129
        && (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
 
2130
            m = VARIABLE_MV;
 
2131
 
 
2132
    if ((o2.type == VARIABLE_OT) && (o2.value == 0))
 
2133
    {
 
2134
        /*  Assemble "pull VAR" rather than "store VAR sp",
 
2135
            saving 1 byte  */
 
2136
 
 
2137
        AI.internal_number = pull_zc;
 
2138
        if (instruction_set_number == 6)
 
2139
        {   AI.operand_count = 0;
 
2140
            AI.store_variable_number = o1.value;
 
2141
        }
 
2142
        else
 
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;
 
2148
        }
 
2149
        AI.branch_label_number = -1;
 
2150
        assemblez_instruction(&AI);
 
2151
        return;
 
2152
    }
 
2153
 
 
2154
    if ((o1.type == VARIABLE_OT) && (o1.value == 0))
 
2155
    {   /*  Assemble "push VAR" rather than "store sp VAR",
 
2156
            saving 1 byte  */
 
2157
 
 
2158
        AI.internal_number = push_zc;
 
2159
        AI.operand_count = 1;
 
2160
        AI.operand[0] = o2;
 
2161
        AI.store_variable_number = -1;
 
2162
        AI.branch_label_number = -1;
 
2163
        assemblez_instruction(&AI);
 
2164
        return;
 
2165
    }
 
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;
 
2171
    AI.operand[1] = o2;
 
2172
    AI.store_variable_number = -1;
 
2173
    AI.branch_label_number = -1;
 
2174
    assemblez_instruction(&AI);
 
2175
}
 
2176
 
 
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);
 
2181
    else
 
2182
    {   AO.type = LONG_CONSTANT_OT; AO.value = n; AO.marker = 0;
 
2183
        assemblez_1(jump_zc, AO);
 
2184
    }
 
2185
}
 
2186
 
 
2187
void assembleg_0(int internal_number)
 
2188
{   AI.internal_number = internal_number;
 
2189
    AI.operand_count = 0;
 
2190
    assembleg_instruction(&AI);
 
2191
}
 
2192
 
 
2193
void assembleg_1(int internal_number, assembly_operand o1)
 
2194
{   AI.internal_number = internal_number;
 
2195
    AI.operand_count = 1;
 
2196
    AI.operand[0] = o1;
 
2197
    assembleg_instruction(&AI);
 
2198
}
 
2199
 
 
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;
 
2204
    AI.operand[0] = o1;
 
2205
    AI.operand[1] = o2;
 
2206
    assembleg_instruction(&AI);
 
2207
}
 
2208
 
 
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;
 
2213
    AI.operand[0] = o1;
 
2214
    AI.operand[1] = o2;
 
2215
    AI.operand[2] = o3;
 
2216
    assembleg_instruction(&AI);
 
2217
}
 
2218
 
 
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;
 
2224
    AI.operand[0] = o1;
 
2225
    AI.operand[1] = o2;
 
2226
    AI.operand[2] = o3;
 
2227
    AI.operand[3] = o4;
 
2228
    assembleg_instruction(&AI);
 
2229
}
 
2230
 
 
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;
 
2236
    AI.operand[0] = o1;
 
2237
    AI.operand[1] = o2;
 
2238
    AI.operand[2] = o3;
 
2239
    AI.operand[3] = o4;
 
2240
    AI.operand[4] = o5;
 
2241
    assembleg_instruction(&AI);
 
2242
}
 
2243
 
 
2244
void assembleg_0_branch(int internal_number,
 
2245
    int label)
 
2246
{
 
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);
 
2253
}
 
2254
 
 
2255
void assembleg_1_branch(int internal_number,
 
2256
    assembly_operand o1, int label)
 
2257
{
 
2258
    /* Some clever optimizations first. A constant is always or never equal
 
2259
       to zero. */
 
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;
 
2267
            return;
 
2268
        }
 
2269
        if ((internal_number == jz_gc && o1.value != 0)
 
2270
          || (internal_number == jnz_gc && o1.value == 0)) {
 
2271
            /* assemble nothing at all! */
 
2272
            return;
 
2273
        }
 
2274
    }
 
2275
    AI.internal_number = internal_number;
 
2276
    AI.operand_count = 2;
 
2277
    AI.operand[0] = o1;
 
2278
    AI.operand[1].type = CONSTANT_OT;
 
2279
    AI.operand[1].value = label;
 
2280
    AI.operand[1].marker = BRANCH_MV;
 
2281
    assembleg_instruction(&AI);
 
2282
}
 
2283
 
 
2284
void assembleg_2_branch(int internal_number,
 
2285
    assembly_operand o1, assembly_operand o2, int label)
 
2286
{
 
2287
    AI.internal_number = internal_number;
 
2288
    AI.operand_count = 3;
 
2289
    AI.operand[0] = o1;
 
2290
    AI.operand[1] = o2;
 
2291
    AI.operand[2].type = CONSTANT_OT;
 
2292
    AI.operand[2].value = label;
 
2293
    AI.operand[2].marker = BRANCH_MV;
 
2294
    assembleg_instruction(&AI);
 
2295
}
 
2296
 
 
2297
void assembleg_call_1(assembly_operand oaddr, assembly_operand o1, 
 
2298
  assembly_operand odest)
 
2299
{
 
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);
 
2304
  }
 
2305
  assembleg_3(call_gc, oaddr, one_operand, odest); */
 
2306
}
 
2307
 
 
2308
void assembleg_call_2(assembly_operand oaddr, assembly_operand o1, 
 
2309
  assembly_operand o2, assembly_operand odest)
 
2310
{
 
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) {
 
2315
    }
 
2316
    else {
 
2317
      assembleg_2(copy_gc, o2, stack_pointer);
 
2318
      assembleg_0(stkswap_gc);
 
2319
    }
 
2320
  }
 
2321
  else {
 
2322
    if (o2.type == LOCALVAR_OT && o2.value == 0 && o2.marker == 0) {
 
2323
      assembleg_2(copy_gc, o1, stack_pointer);
 
2324
    }
 
2325
    else {
 
2326
      assembleg_2(copy_gc, o2, stack_pointer);
 
2327
      assembleg_2(copy_gc, o1, stack_pointer);
 
2328
    }
 
2329
  }
 
2330
  assembleg_3(call_gc, oaddr, two_operand, odest); */
 
2331
}
 
2332
 
 
2333
void assembleg_call_3(assembly_operand oaddr, assembly_operand o1, 
 
2334
  assembly_operand o2, assembly_operand o3, assembly_operand odest)
 
2335
{
 
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. 
 
2342
      }
 
2343
      else {
 
2344
    assembleg_2(copy_gc, o3, stack_pointer);
 
2345
    assembleg_2(stkroll_gc, three_operand, one_operand);
 
2346
      }
 
2347
    }
 
2348
    else {
 
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);
 
2352
      }
 
2353
      else {
 
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);
 
2358
      }
 
2359
    }
 
2360
  }
 
2361
  else {
 
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);
 
2365
      }
 
2366
      else {
 
2367
    assembleg_2(copy_gc, o3, stack_pointer);
 
2368
        assembleg_0(stkswap_gc);
 
2369
    assembleg_2(copy_gc, o1, stack_pointer);
 
2370
      }
 
2371
    }
 
2372
    else {
 
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);
 
2376
      }
 
2377
      else {
 
2378
    assembleg_2(copy_gc, o3, stack_pointer);
 
2379
    assembleg_2(copy_gc, o2, stack_pointer);
 
2380
    assembleg_2(copy_gc, o1, stack_pointer);
 
2381
      }
 
2382
    }
 
2383
  }
 
2384
 
 
2385
  assembleg_3(call_gc, oaddr, three_operand, odest); */
 
2386
}
 
2387
 
 
2388
void assembleg_inc(assembly_operand o1)
 
2389
{
 
2390
  AI.internal_number = add_gc;
 
2391
  AI.operand_count = 3;
 
2392
  AI.operand[0] = o1;
 
2393
  AI.operand[1] = one_operand;
 
2394
  AI.operand[2] = o1;
 
2395
  assembleg_instruction(&AI);
 
2396
}
 
2397
 
 
2398
void assembleg_dec(assembly_operand o1)
 
2399
{
 
2400
  AI.internal_number = sub_gc;
 
2401
  AI.operand_count = 3;
 
2402
  AI.operand[0] = o1;
 
2403
  AI.operand[1] = one_operand;
 
2404
  AI.operand[2] = o1;
 
2405
  assembleg_instruction(&AI);
 
2406
}
 
2407
 
 
2408
void assembleg_store(assembly_operand o1, assembly_operand o2)
 
2409
{
 
2410
    /* Note the order is reversed: "o1 = o2;" */
 
2411
    assembleg_2(copy_gc, o2, o1);
 
2412
}
 
2413
 
 
2414
void assembleg_jump(int n)
 
2415
{
 
2416
  if (n==-4) {
 
2417
      assembleg_1(return_gc, one_operand);
 
2418
  }
 
2419
  else if (n==-3) {
 
2420
      assembleg_1(return_gc, zero_operand); 
 
2421
  }
 
2422
  else {
 
2423
      assembleg_0_branch(jump_gc, n);
 
2424
  }
 
2425
}
 
2426
 
 
2427
/* ========================================================================= */
 
2428
/*   Parsing and then calling the assembler for @ (assembly language)        */
 
2429
/*   statements                                                              */
 
2430
/* ------------------------------------------------------------------------- */
 
2431
 
 
2432
static assembly_operand parse_operand_z(void)
 
2433
{   assembly_operand AO;
 
2434
 
 
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;
 
2439
    }
 
2440
    return(AO);
 
2441
}
 
2442
 
 
2443
static void parse_assembly_z(void)
 
2444
{   int n, min, max, indirect_addressed, error_flag = FALSE;
 
2445
    opcodez O;
 
2446
 
 
2447
    AI.operand_count = 0;
 
2448
    AI.store_variable_number = -1;
 
2449
    AI.branch_label_number = -1;
 
2450
    AI.text = NULL;
 
2451
 
 
2452
    opcode_names.enabled = TRUE;
 
2453
    get_next_token();
 
2454
    opcode_names.enabled = FALSE;
 
2455
 
 
2456
    if (token_type == DQ_TT)
 
2457
    {   int i;
 
2458
        AI.internal_number = -1;
 
2459
 
 
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;
 
2468
 
 
2469
        for (i=0; token_text[i]!=0; i++)
 
2470
        {   if (token_text[i] == ':')
 
2471
            {   token_text[i++] = 0;
 
2472
                break;
 
2473
            }
 
2474
        }
 
2475
        if (token_text[i] == 0)
 
2476
            error("Opcode specification should have form \"VAR:102\"");
 
2477
 
 
2478
        n = -1;
 
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;
 
2486
 
 
2487
        if (i>0) token_text[i-1] = ':';
 
2488
 
 
2489
        if (n==-1)
 
2490
        {   ebf_error("Expected 0OP, 1OP, 2OP, VAR, EXT, VAR_LONG or EXT_LONG",
 
2491
                token_text);
 
2492
            n = EXT;
 
2493
        }
 
2494
        custom_opcode_z.no = n;
 
2495
 
 
2496
        custom_opcode_z.code = atoi(token_text+i);
 
2497
        while (isdigit(token_text[i])) i++;
 
2498
 
 
2499
        {   int max, min;
 
2500
            min = 0;
 
2501
            switch(n)
 
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;
 
2506
            }
 
2507
            if ((custom_opcode_z.code < min) || (custom_opcode_z.code >= max))
 
2508
            {   char range[32];
 
2509
                sprintf(range, "%d to %d", min, max-1);
 
2510
            error_named("For this operand type, opcode number must be in range",
 
2511
                    range);
 
2512
                custom_opcode_z.code = min;
 
2513
            }
 
2514
        }
 
2515
 
 
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;
 
2524
                default:
 
2525
                    error("Unknown flag: options are B (branch), S (store), \
 
2526
T (text), I (indirect addressing), F** (set this Flags 2 bit)");
 
2527
                    break;
 
2528
            }
 
2529
        }
 
2530
        O = custom_opcode_z;
 
2531
    }
 
2532
    else
 
2533
    {   if (token_type != OPCODE_NAME_TT)
 
2534
        {   ebf_error("an opcode name", token_text);
 
2535
            panic_mode_error_recovery();
 
2536
            return;
 
2537
        }
 
2538
        AI.internal_number = token_value;
 
2539
        O = internal_number_to_opcode_z(AI.internal_number);
 
2540
    }
 
2541
 
 
2542
    indirect_addressed = (O.op_rules == VARIAB);
 
2543
 
 
2544
    if (O.op_rules == TEXT)
 
2545
    {   get_next_token();
 
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;
 
2550
        get_next_token();
 
2551
        if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
 
2552
        {   assemblez_instruction(&AI);
 
2553
            return;
 
2554
        }
 
2555
        ebf_error("semicolon ';' after print string", token_text);
 
2556
        put_token_back();
 
2557
        return;
 
2558
    }
 
2559
 
 
2560
    return_sp_as_variable = TRUE;
 
2561
    do
 
2562
    {   get_next_token();
 
2563
 
 
2564
        if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
 
2565
 
 
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");
 
2569
            get_next_token();
 
2570
            if ((token_type != SYMBOL_TT)
 
2571
                && (token_type != LOCAL_VARIABLE_TT))
 
2572
                ebf_error("variable name or 'sp'", token_text);
 
2573
            n = 255;
 
2574
            if (token_type == LOCAL_VARIABLE_TT) n = token_value;
 
2575
            else
 
2576
            {   if (strcmp(token_text, "sp") == 0) n = 0;
 
2577
                else
 
2578
                {   if (stypes[token_value] != GLOBAL_VARIABLE_T)
 
2579
                        error_named(
 
2580
                            "Store '->' destination not 'sp' or a variable:",
 
2581
                            token_text);
 
2582
                    else n = svals[token_value];
 
2583
                }
 
2584
            }
 
2585
            AI.store_variable_number = n;
 
2586
            continue;
 
2587
        }
 
2588
 
 
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");
 
2593
 
 
2594
            AI.branch_flag = (token_value == BRANCH_SEP);
 
2595
 
 
2596
            opcode_names.enabled = TRUE;
 
2597
            get_next_token();
 
2598
            opcode_names.enabled = FALSE;
 
2599
 
 
2600
            n = -2;
 
2601
            if ((token_type == OPCODE_NAME_TT)
 
2602
                && (token_value == rfalse_zc)) n = -3;
 
2603
            else
 
2604
            if ((token_type == OPCODE_NAME_TT)
 
2605
                && (token_value == rtrue_zc)) n = -4;
 
2606
            else
 
2607
            {   if (token_type == SYMBOL_TT)
 
2608
                {   put_token_back();
 
2609
                    n = parse_label();
 
2610
                }
 
2611
                else
 
2612
                    ebf_error("label name after '?' or '?~'", token_text);
 
2613
            }
 
2614
            AI.branch_label_number = n;
 
2615
            continue;
 
2616
        }
 
2617
 
 
2618
        if (AI.operand_count == 8)
 
2619
        {   error("No assembly instruction may have more than 8 operands");
 
2620
            panic_mode_error_recovery(); break;
 
2621
        }
 
2622
 
 
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();
 
2629
            get_next_token();
 
2630
            if (!((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP)))
 
2631
            {   ebf_error("']'", token_text);
 
2632
                put_token_back();
 
2633
            }
 
2634
        }
 
2635
        else
 
2636
        {   put_token_back();
 
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;
 
2642
            }
 
2643
        }
 
2644
 
 
2645
    } while (TRUE);
 
2646
 
 
2647
    return_sp_as_variable = FALSE;
 
2648
 
 
2649
 
 
2650
    if (O.version1 == 0)
 
2651
    {   error_named("Opcode unavailable in this Z-machine version:",
 
2652
            opcode_names.keywords[AI.internal_number]);
 
2653
        return;
 
2654
    }
 
2655
 
 
2656
    if (((O.flags) & Br) != 0)
 
2657
    {   if (AI.branch_label_number == -1)
 
2658
        {   error_flag = TRUE;
 
2659
            AI.branch_label_number = -2;
 
2660
        }
 
2661
    }
 
2662
    else
 
2663
    {   if (AI.branch_label_number != -1)
 
2664
        {   error_flag = TRUE;
 
2665
            AI.branch_label_number = -1;
 
2666
        }
 
2667
    }
 
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;
 
2673
            }
 
2674
            else
 
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");
 
2679
            }
 
2680
        }
 
2681
    }
 
2682
    else
 
2683
    {   if (AI.store_variable_number != -1)
 
2684
        {   error_flag = TRUE;
 
2685
            AI.store_variable_number = -1;
 
2686
        }
 
2687
    }
 
2688
 
 
2689
    switch(O.no)
 
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; }
 
2697
                       break;
 
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;
 
2704
    }
 
2705
 
 
2706
    if ((AI.operand_count >= min) && (AI.operand_count <= max))
 
2707
        assemblez_instruction(&AI);
 
2708
    else error_flag = TRUE;
 
2709
 
 
2710
    if (error_flag)
 
2711
    {   make_opcode_syntax_z(O);
 
2712
        error_named("Assembly mistake: syntax is",
 
2713
            opcode_syntax_string);
 
2714
    }
 
2715
}
 
2716
 
 
2717
static assembly_operand parse_operand_g(void)
 
2718
{   assembly_operand AO;
 
2719
 
 
2720
    AO = parse_expression(ASSEMBLY_CONTEXT);
 
2721
    if (AO.type == EXPRESSION_OT)
 
2722
    {   ebf_error("variable or constant", "expression");
 
2723
        AO.type = CONSTANT_OT;
 
2724
    }
 
2725
    return(AO);
 
2726
}
 
2727
 
 
2728
static void parse_assembly_g(void)
 
2729
{
 
2730
  opcodeg O;
 
2731
  assembly_operand AO;
 
2732
  int error_flag = FALSE;
 
2733
 
 
2734
  AI.operand_count = 0;
 
2735
 
 
2736
  opcode_names.enabled = TRUE;
 
2737
  get_next_token();
 
2738
  opcode_names.enabled = FALSE;
 
2739
 
 
2740
  if (token_type == DQ_TT) {
 
2741
    error("Runtime assembly definitions are not yet supported in Glulx.");
 
2742
    panic_mode_error_recovery();
 
2743
    return;
 
2744
  }
 
2745
  else {
 
2746
    if (token_type != OPCODE_NAME_TT) {
 
2747
      ebf_error("an opcode name", token_text);
 
2748
      panic_mode_error_recovery();
 
2749
      return;
 
2750
    }
 
2751
    AI.internal_number = token_value;
 
2752
    O = internal_number_to_opcode_g(AI.internal_number);
 
2753
  }
 
2754
  
 
2755
  return_sp_as_variable = TRUE;
 
2756
 
 
2757
  while (1) {
 
2758
    get_next_token();
 
2759
    
 
2760
    if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) 
 
2761
      break;
 
2762
 
 
2763
    if (AI.operand_count == 8) {
 
2764
      error("No assembly instruction may have more than 8 operands");
 
2765
      panic_mode_error_recovery(); 
 
2766
      break;
 
2767
    }
 
2768
 
 
2769
    if ((O.flags & Br) && (AI.operand_count == O.no-1)) {
 
2770
      if (!((token_type == SEP_TT) && (token_value == BRANCH_SEP))) {
 
2771
        error_flag = TRUE;
 
2772
        error("Branch opcode must have '?' label");
 
2773
        put_token_back();
 
2774
      }
 
2775
      AO.type = CONSTANT_OT;
 
2776
      AO.value = parse_label();
 
2777
      AO.marker = BRANCH_MV;
 
2778
    }
 
2779
    else {
 
2780
      put_token_back();
 
2781
      AO = parse_operand_g();
 
2782
    }
 
2783
 
 
2784
    AI.operand[AI.operand_count] = AO;
 
2785
    AI.operand_count++;
 
2786
  }
 
2787
 
 
2788
  return_sp_as_variable = FALSE;
 
2789
 
 
2790
  if (O.no != AI.operand_count) {
 
2791
    error_flag = TRUE;
 
2792
  }
 
2793
 
 
2794
  if (!error_flag)
 
2795
    assembleg_instruction(&AI);
 
2796
 
 
2797
  if (error_flag) {
 
2798
    make_opcode_syntax_g(O);
 
2799
    error_named("Assembly mistake: syntax is",
 
2800
      opcode_syntax_string);
 
2801
  }
 
2802
}
 
2803
 
 
2804
extern void parse_assembly(void)
 
2805
{
 
2806
  if (!glulx_mode)
 
2807
    parse_assembly_z();
 
2808
  else
 
2809
    parse_assembly_g();
 
2810
}
 
2811
 
 
2812
/* ========================================================================= */
 
2813
/*   Data structure management routines                                      */
 
2814
/* ------------------------------------------------------------------------- */
 
2815
 
 
2816
extern void asm_begin_pass(void)
 
2817
{   no_instructions = 0;
 
2818
    zmachine_pc = 0;
 
2819
    no_sequence_points = 0;
 
2820
    next_label = 0;
 
2821
    next_sequence_point = 0;
 
2822
    zcode_ha_size = 0;
 
2823
}
 
2824
 
 
2825
extern void init_asm_vars(void)
 
2826
{   int i;
 
2827
 
 
2828
    for (i=0;i<16;i++) flags2_requirements[i]=0;
 
2829
 
 
2830
    sequence_point_follows = TRUE;
 
2831
    label_moved_error_already_given = FALSE;
 
2832
 
 
2833
    initialise_memory_block(&zcode_area);
 
2834
}
 
2835
 
 
2836
extern void asm_allocate_arrays(void)
 
2837
{   if ((debugfile_switch) && (MAX_LABELS < 2000)) MAX_LABELS = 2000;
 
2838
 
 
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");
 
2843
 
 
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");
 
2850
    sequence_point_refs
 
2851
        = my_calloc(sizeof(dbgl), MAX_LABELS, "sequence point refs");
 
2852
 
 
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");
 
2855
 
 
2856
    named_routine_symbols
 
2857
        = my_calloc(sizeof(int32), MAX_SYMBOLS, "named routine symbols");
 
2858
}
 
2859
 
 
2860
extern void asm_free_arrays(void)
 
2861
{
 
2862
    my_free(&variable_tokens, "variable tokens");
 
2863
    my_free(&variable_usage, "variable usage");
 
2864
 
 
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");
 
2871
 
 
2872
    my_free(&zcode_holding_area, "compiled routine code area");
 
2873
    my_free(&zcode_markers, "compiled routine code markers");
 
2874
 
 
2875
    my_free(&named_routine_symbols, "named routine symbols");
 
2876
    deallocate_memory_block(&zcode_area);
 
2877
}
 
2878
 
 
2879
/* ========================================================================= */