~ubuntu-branches/ubuntu/vivid/inform/vivid

« back to all changes in this revision

Viewing changes to src/asm.c

  • Committer: Bazaar Package Importer
  • Author(s): Jan Christoph Nordholz
  • Date: 2008-05-26 22:09:44 UTC
  • mfrom: (2.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080526220944-ba7phz0d1k4vo7wx
Tags: 6.31.1+dfsg-1
* Remove a considerable number of files from the package
  due to unacceptable licensing terms.
* Repair library symlinks.

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
 
/* ========================================================================= */