annotate keiko/linker.c @ 0:bfdcc3820b32

Basis
author Mike Spivey <mike@cs.ox.ac.uk>
date Thu, 05 Oct 2017 08:04:15 +0100
parents
children
rev   line source
0
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
1 /*
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
2 * linker.c
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
3 *
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
4 * This file is part of the Oxford Oberon-2 compiler
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
5 * Copyright (c) 2006--2016 J. M. Spivey
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
6 * All rights reserved
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
7 *
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
8 * Redistribution and use in source and binary forms, with or without
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
9 * modification, are permitted provided that the following conditions are met:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
10 *
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
11 * 1. Redistributions of source code must retain the above copyright notice,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
12 * this list of conditions and the following disclaimer.
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
14 * this list of conditions and the following disclaimer in the documentation
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
15 * and/or other materials provided with the distribution.
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
16 * 3. The name of the author may not be used to endorse or promote products
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
17 * derived from this software without specific prior written permission.
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
18 *
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
29 */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
30
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
31 #include <ctype.h>
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
32 #include "oblink.h"
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
33 #include "keiko.h"
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
34
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
35 static FILE *binfp; /* File for code output */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
36
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
37 /* binwrite -- output code */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
38 static void binwrite(void *buf, int size) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
39 int UNUSED nwritten = fwrite(buf, 1, size, binfp);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
40 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
41
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
42 /* hexchar -- convert character from two-digit hex */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
43 static char hexchar(char *s) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
44 char buf[3];
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
45
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
46 buf[0] = s[0]; buf[1] = s[1]; buf[2] = '\0';
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
47 return (char) strtoul(buf, NULL, 16);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
48 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
49
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
50 static int iloc = 0, bloc = 0; /* Sizes of code, bss segments */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
51 static int nmods = 0, nprocs = 0; /* Number of modules and procedures */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
52 static symbol this_module; /* Current module */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
53 static symbol this_proc; /* Current procedure */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
54 static int proc_start; /* Start of procedure in dbuf */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
55 static int code_size; /* Size of bytecode for procedure */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
56
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
57 /* Instructions are stored as 'phrases' in abuf, a doubly-linked list.
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
58 Each phrase has a tentative assignment of a template, which describes
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
59 at least what arguments there should be; before the code is output, the
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
60 template may be replaced by one with bigger fields in order to make the
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
61 arguments fit. The code for a procedure is built up in abuf and output
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
62 at the end of the procedure. */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
63
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
64 struct _phrase { /* An instruction in the assembler */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
65 const char *q_name; /* Instruction name */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
66 template q_templ; /* Best estimate of template */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
67 int q_arg[MAXARGS]; /* Arguments */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
68 int q_addr; /* Estimated address from start of proc */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
69 symbol q_sym; /* Symbol for this address */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
70 phrase q_target; /* Branch target */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
71 phrase q_prev, q_next; /* Links in the list */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
72 };
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
73
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
74 phrase abuf;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
75
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
76 #define for_phrases(q) \
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
77 for (phrase q = abuf->q_next; q != abuf; q = q->q_next)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
78
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
79 mempool pool;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
80
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
81 static phrase alloc_phrase(void) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
82 return (phrase) pool_alloc(&pool, sizeof(struct _phrase));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
83 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
84
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
85 static void init_abuf(void) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
86 pool_reset(&pool);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
87 abuf = alloc_phrase();
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
88 abuf->q_name = (char *) "*dummy*";
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
89 abuf->q_templ = NULL;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
90 abuf->q_addr = 0;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
91 abuf->q_sym = NULL;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
92 abuf->q_target = NULL;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
93 abuf->q_prev = abuf->q_next = abuf;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
94 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
95
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
96 static growdecl(dbuf);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
97 #define dbuf growbuf(dbuf, uchar)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
98 #define dloc growsize(dbuf)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
99
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
100 static growdecl(rbuf);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
101 #define rbuf growbuf(rbuf, unsigned)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
102 #define rloc growsize(rbuf)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
103
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
104 static growdecl(prims);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
105 #define prims growbuf(prims, int)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
106 #define nprims growsize(prims)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
107
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
108 /* relocate -- record relocation bits */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
109 void relocate(int loc, int bits) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
110 /* Each byte of relocation info covers CODES_PER_BYTE words */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
111 int index = loc/(WORD_SIZE * CODES_PER_WORD);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
112 int shift = loc/WORD_SIZE % CODES_PER_WORD * BITS_PER_CODE;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
113
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
114 if (rloc < index+1) rloc = index+1;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
115 buf_grow(rbuf);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
116 rbuf[index] = (rbuf[index] & ~(CODE_MASK << shift)) | (bits << shift);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
117 #ifdef DEBUG
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
118 if (dflag) printf("Reloc %d %d %#08x\n", loc, bits, rbuf[index]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
119 #endif
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
120 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
121
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
122 static void put_value(int addr, int value, int reloc) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
123 /* We carefully store all 4-byte values in dbuf in
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
124 machine-independent byte order: little-endian even if the host
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
125 is a big-endian machine. The value reloc determines how the
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
126 value should be relocated when the program is loaded by obx. */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
127 put4(&dbuf[addr], value);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
128 relocate(addr, reloc);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
129 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
130
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
131 static int const_value(char *s) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
132 /* We must allow both signed and unsigned (especially hex)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
133 constants, so negative numbers must be treated separately.
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
134 Note that strtol is specified to truncate to MAXINT on
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
135 overflow, not to operate mod 2^32. */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
136
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
137 if (s == NULL)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
138 return 0;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
139 else if (s[0] == '-')
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
140 return strtol(s, NULL, 0);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
141 else
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
142 return strtoul(s, NULL, 0);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
143 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
144
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
145 static void data_value(int value, int reloc) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
146 buf_grow(dbuf);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
147 put_value(dloc, value, reloc);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
148 dloc += 4;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
149 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
150
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
151 static void data_word(char *s) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
152 buf_grow(dbuf);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
153 if (s == NULL || isdigit((int) s[0]) || s[0] == '-')
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
154 put_value(dloc, const_value(s), R_WORD);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
155 else
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
156 use_global(find_symbol(s), dbuf, dloc);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
157 dloc += 4;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
158 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
159
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
160 static void put_string(char *str) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
161 char *s = str;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
162 do {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
163 buf_grow(dbuf);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
164 dbuf[dloc++] = *s;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
165 } while (*s++ != '\0');
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
166 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
167
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
168
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
169 /* Constant pool */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
170
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
171 static growdecl(const_sym);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
172 #define const_sym growbuf(const_sym, symbol)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
173 #define nconsts growsize(const_sym)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
174
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
175 #define get_const(n) get4(dbuf + proc_start + 4 * (CP_CONST+(n)))
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
176
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
177 static int find_const(int value, symbol sym) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
178 int i;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
179
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
180 for (i = 0; i < nconsts; i++) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
181 if (sym == NULL
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
182 ? (const_sym[i] == NULL && get_const(i) == value)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
183 : const_sym[i] == sym)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
184 return i;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
185 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
186
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
187 i = nconsts++;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
188 buf_grow(const_sym);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
189 const_sym[i] = sym;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
190 buf_grow(dbuf);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
191
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
192 if (sym == NULL)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
193 put_value(dloc, value, R_WORD);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
194 else
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
195 use_global(sym, dbuf, dloc);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
196
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
197 dloc += 4;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
198 return i;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
199 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
200
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
201 static int find_dconst(int val0, int val1) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
202 int i;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
203
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
204 for (i = 0; i < nconsts-1; i++) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
205 if (const_sym[i] == NULL && const_sym[i+1] == NULL
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
206 && get_const(i) == val0 && get_const(i+1) == val1)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
207 return i;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
208 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
209
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
210 i = nconsts; nconsts += 2;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
211 buf_grow(const_sym);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
212 const_sym[i] = const_sym[i+1] = NULL;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
213 data_value(val0, R_WORD);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
214 data_value(val1, R_WORD);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
215
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
216 return i;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
217 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
218
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
219 static int make_const(char *s) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
220 if (isdigit((int) s[0]) || s[0] == '-')
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
221 return find_const(const_value(s), NULL);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
222 else
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
223 return find_const(0, find_symbol(s));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
224 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
225
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
226
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
227 /* Instruction templates */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
228
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
229 /* find_template -- find first template for instruction */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
230 static template find_template(const char *name) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
231 const char *s = name;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
232 int q = 0;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
233 char ch;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
234
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
235 /* The templates are organised in a trie */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
236
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
237 do {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
238 ch = *s++ & 0x7f;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
239
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
240 if (templ_check[q+ch] != ch)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
241 panic("*no template found for %s", name);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
242
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
243 q = templ_trie[q+ch];
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
244 } while (ch != '\0');
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
245
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
246 return &templates[q];
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
247 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
248
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
249 /* fits -- test if an integer fits in a certain number of bits */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
250 static mybool fits(int x, int n) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
251 int max = 1 << (n-1);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
252 return (-max <= x && x < max);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
253 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
254
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
255 /* fix_labels -- compute target for jump */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
256 static void fix_labels(phrase q) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
257 const char *p = q->q_templ->t_pattern;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
258
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
259 for (int j = 0; p[j] != '\0'; j++)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
260 if (p[j] == 'R' || p[j] == 'S')
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
261 q->q_target = find_label(q->q_arg[j]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
262 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
263
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
264 /* displacement -- calculate branch displacement */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
265 static int displacement(phrase q) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
266 /* Phrase |q| is a branch instruction. The signed displacement
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
267 is the distance from the opcode to the target. */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
268 return (q->q_target->q_addr - q->q_addr);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
269 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
270
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
271 /* match -- test whether a template matches its arguments */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
272 static mybool match(phrase q, template t) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
273 /* Just check the last operand */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
274 int n = strlen(t->t_pattern);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
275 const char *p = t->t_pattern;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
276 int *a = q->q_arg;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
277
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
278 if (n == 0) return TRUE;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
279
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
280 switch (p[n-1]) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
281 case 'N':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
282 { int val = a[n-1];
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
283 return (val >= t->t_lo && val <= t->t_hi
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
284 && (val - t->t_lo) % t->t_step == 0); }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
285 case '1':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
286 case 'K':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
287 return fits(a[n-1], 8);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
288 case '2':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
289 case 'L':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
290 return fits(a[n-1], 16);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
291 case 'R':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
292 return fits(displacement(q), 16);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
293 case 'S':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
294 return fits(displacement(q), 8);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
295 default:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
296 return TRUE;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
297 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
298 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
299
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
300 #ifdef DEBUG
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
301 static void print_args(phrase q) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
302 const char *patt = q->q_templ->t_pattern;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
303
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
304 for (int j = 0; patt[j] != '\0'; j++) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
305 switch (patt[j]) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
306 case '1':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
307 case '2':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
308 case 'N':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
309 case 'K':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
310 case 'L':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
311 printf(" %d", q->q_arg[j]); break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
312 case 'R':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
313 case 'S':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
314 printf(" %+d", displacement(q)); break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
315 default:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
316 printf(" ???");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
317 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
318 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
319 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
320 #endif
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
321
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
322 static int get_arg(char tmpl, char *rand, template t, int cxt[]) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
323 if (rand[0] == '$' && cxt != NULL)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
324 return cxt[rand[1] - 'a'];
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
325
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
326 switch (tmpl) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
327 case '1':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
328 case '2':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
329 case 'N':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
330 if (isdigit((int) rand[0]) || rand[0] == '-')
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
331 return const_value(rand);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
332 else
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
333 return sym_value(find_symbol(rand));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
334
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
335 case 'R':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
336 case 'S':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
337 return make_label(find_symbol(rand));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
338
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
339 case 'K':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
340 case 'L':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
341 return make_const(rand);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
342
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
343 default:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
344 panic("*bad template %c for %s", tmpl, t->t_name);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
345 return 0;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
346 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
347 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
348
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
349 /* do_template -- enter an instruction */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
350 static phrase do_template(template t, char *rands[], phrase rgt, int cxt[]) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
351 /* Template t determines the number and kinds of operands for the
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
352 instruction; depending on the values of the operands, it may or
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
353 may not end up actually matching the instruction. */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
354
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
355 phrase q = alloc_phrase();
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
356 phrase lft = rgt->q_prev;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
357 const char *patt = t->t_pattern;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
358
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
359 q->q_name = t->t_name;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
360 q->q_templ = t;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
361 for (int i = 0; patt[i] != '\0'; i++)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
362 q->q_arg[i] = get_arg(patt[i], rands[i], t, cxt);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
363 q->q_addr = 0;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
364 q->q_sym = NULL;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
365 q->q_target = NULL;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
366 q->q_prev = lft; q->q_next = rgt;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
367 lft->q_next = rgt->q_prev = q;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
368 return q;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
369 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
370
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
371 /* expand -- replace macro by its expansion */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
372 static phrase expand(phrase q) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
373 static char buf[128];
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
374 char *words[10];
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
375 template t = q->q_templ;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
376 phrase r = q->q_prev, q1;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
377
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
378 for (int i = 0; t->t_macro[i] != NULL; i++) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
379 strcpy(buf, t->t_macro[i]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
380 int n = split_line(buf, words);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
381 template t1 = find_template(words[0]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
382 if (strlen(t1->t_pattern) != n-1 || t->t_size < 0)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
383 panic("*macro expansion failed");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
384
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
385 /* Insert expansion before original phrase */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
386 q1 = do_template(t1, &words[1], q, q->q_arg);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
387 fix_labels(q1);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
388 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
389
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
390 /* Delete the original */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
391 q->q_prev->q_next = q->q_next;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
392 q->q_next->q_prev = q->q_prev;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
393
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
394 return r->q_next;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
395 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
396
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
397 /* check_matches -- revise choice of templates, return TRUE if ok already */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
398 static mybool check_matches(void) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
399 mybool ok = TRUE;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
400
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
401 for (phrase q = abuf->q_next; q != abuf; ) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
402 template t = q->q_templ;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
403
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
404 if (t->t_macro[0] != NULL) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
405 /* A macro instruction: expand it */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
406 q = expand(q);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
407 ok = FALSE;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
408 } else if (! match(q, t)) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
409 t++;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
410
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
411 if (t >= &templates[NTEMPLATES] || t->t_name != NULL) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
412 panic("*no template fits %s", q->q_name);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
413 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
414
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
415 q->q_templ = t;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
416 ok = FALSE;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
417 } else {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
418 q = q->q_next;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
419 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
420 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
421
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
422 return ok;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
423 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
424
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
425 /* assemble -- assemble instructions */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
426 static void assemble(void) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
427 mybool ok;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
428 int trial = 0;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
429
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
430 for_phrases (q) fix_labels(q);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
431
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
432 /* A tentative assignment of templates has already been computed,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
433 but the arguments may not fit in the field sizes assigned. So
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
434 now we repeatedly revise the assignment until all arguments fit.
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
435 Changing the assignment will increase the size of some instructions,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
436 perhaps making branches longer so that they no longer fit either
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
437 -- that's why iteration is necessary.
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
438
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
439 The invariant is that there is no feasible choice of templates that
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
440 makes any instruction smaller than it is in the current assignment.
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
441 The variant is the total number of templates that remain to be tried.
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
442 Correctness of the algorithm follows from the fact that making one
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
443 instruction larger cannot allow another to be smaller. */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
444
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
445 do {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
446 int a = 0;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
447 trial++;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
448 #ifdef DEBUG
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
449 if (dflag > 0)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
450 printf("Checking templates (pass %d)\n", trial);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
451 #endif
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
452
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
453 /* Calculate address of each instruction */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
454 for_phrases (q) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
455 q->q_addr = a;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
456 a += q->q_templ->t_size;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
457 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
458
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
459 code_size = a;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
460 ok = check_matches(); /* Revise template choices */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
461 } while (!ok);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
462 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
463
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
464 /* make_binary -- output binary code */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
465 static void make_binary(void) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
466 for_phrases (q) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
467 template t = q->q_templ;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
468 const char *p = t->t_pattern;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
469 int *a = q->q_arg;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
470
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
471 #ifdef DEBUG
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
472 if (dflag > 0) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
473 printf("%d: %s(%s)", q->q_addr, q->q_name, p);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
474 print_args(q);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
475 printf("\n");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
476 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
477 #endif
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
478
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
479 if (q->q_sym != NULL)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
480 def_global(q->q_sym, CODE, iloc + q->q_addr, X_LINE);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
481
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
482 if (p[0] == 'N')
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
483 write_int(1, t->t_op + (a[0] - t->t_lo)/t->t_step);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
484 else if (t->t_oplen > 0)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
485 binwrite(&t->t_op, t->t_oplen);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
486
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
487 for (int j = 0; p[j] != '\0'; j++) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
488 switch (p[j]) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
489 case 'N':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
490 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
491 case '1':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
492 case 'K':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
493 write_int(1, a[j]); break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
494 case '2':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
495 case 'L':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
496 write_int(2, a[j]); break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
497 case 'R':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
498 write_int(2, displacement(q)); break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
499 case 'S':
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
500 write_int(1, displacement(q)); break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
501 default:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
502 panic("*bad template %c", p[j]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
503 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
504 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
505 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
506 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
507
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
508 /* MARK pseudo-instructions generate no code, and are used to place labels,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
509 line numbers, etc. */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
510 struct _template mark = {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
511 "*MARK*", "", 0, 0, 0, 0, 0, 0, { NULL }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
512 };
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
513
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
514 static phrase put_mark(symbol s) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
515 phrase q = do_template(&mark, NULL, abuf, NULL);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
516 q->q_sym = s;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
517 return q;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
518 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
519
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
520 /* const_head -- start of constant pool */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
521 static void const_head(int prim, int code, int reloc,
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
522 int frame, int stack, char *map) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
523 data_value(prim, R_SUBR); /* Primitive */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
524 data_value(code, reloc); /* Entry point */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
525 data_value(0, R_WORD); /* Code size */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
526 data_value(frame, R_WORD); /* Frame size in words */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
527 data_value(stack, R_WORD); /* Stack size in words */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
528 data_word(map); /* Frame map */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
529 data_value(0, R_WORD); /* Stack map table */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
530 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
531
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
532 typedef struct {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
533 phrase sm_addr; /* Pointer to the JPROC instruction */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
534 char *sm_text; /* Symbol or numeric value */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
535 } stackmap;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
536
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
537 static growdecl(smbuf);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
538 #define smbuf growbuf(smbuf, stackmap)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
539 #define smp growsize(smbuf)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
540
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
541 /* fix_stackmaps -- fix up the stack maps for the current procedure */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
542 static void fix_stackmaps(void) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
543 if (smp == 0) return;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
544
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
545 /* Fill in the address of the table in the constant pool */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
546 put_value(proc_start + 4*CP_STKMAP, dloc, R_DATA);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
547
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
548 /* Create the table itself */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
549 for (int i = 0; i < smp; i++) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
550 stackmap *sm = &smbuf[i];
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
551
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
552 /* The return address for the call: '+1' to allow for the space
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
553 occupied by the JPROC instruction */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
554 data_value(iloc + sm->sm_addr->q_addr + 1, R_CODE);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
555
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
556 /* The stack map */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
557 data_word(sm->sm_text);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
558 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
559
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
560 data_value(0, R_WORD);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
561 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
562
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
563 typedef struct {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
564 int h_begin, h_end; /* Scope of handler */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
565 symbol h_excep; /* Exception */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
566 phrase h_body; /* Handler code */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
567 } handler;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
568
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
569 /* check_inproc -- panic if not in a procedure */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
570 static void check_inproc(const char *opcode) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
571 if (this_proc == NULL)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
572 panic("*%s occurs outside any procedure", opcode);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
573 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
574
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
575 /* do_directive -- process a directive */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
576 static void do_directive(const char *dir, int n, char *rands[], int nrands) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
577 union { int n; float f; } fcvt;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
578 dblbuf dcvt;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
579 int v;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
580
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
581 switch (n) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
582 case D_LABEL:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
583 check_inproc(dir);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
584 /* Each label is defined as the |abuf| index of its target */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
585 def_label(find_symbol(rands[0]), put_mark(NULL));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
586 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
587
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
588 case D_STRING:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
589 for (int i = 0; rands[0][2*i] != '\0'; i++) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
590 buf_grow(dbuf);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
591 dbuf[dloc++] = hexchar(&rands[0][2*i]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
592 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
593 dloc = align(dloc, 4);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
594 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
595
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
596 case D_CONST:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
597 check_inproc(dir);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
598 if ((isdigit((int) rands[0][0]) || rands[0][0] == '-')
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
599 && fits(v = const_value(rands[0]), 16))
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
600 gen_inst("PUSH %d", v);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
601 else
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
602 gen_inst("LDKW %d", make_const(rands[0]));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
603 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
604
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
605 case D_GLOBAL:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
606 check_inproc(dir);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
607 gen_inst("LDKW %d", make_const(rands[0]));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
608 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
609
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
610 case D_FCONST:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
611 check_inproc(dir);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
612 fcvt.f = atof(rands[0]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
613 gen_inst("LDKF %d", find_const(fcvt.n, NULL));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
614 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
615
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
616 case D_DCONST:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
617 check_inproc(dir);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
618 dcvt.d = atof(rands[0]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
619 gen_inst("LDKD %d", find_dconst(dcvt.n.lo, dcvt.n.hi));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
620 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
621
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
622 case D_QCONST:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
623 check_inproc(dir);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
624 dcvt.q = strtoll(rands[0], NULL, 0);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
625 gen_inst("LDKQ %d", find_dconst(dcvt.n.lo, dcvt.n.hi));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
626 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
627
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
628 case D_WORD:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
629 data_word(rands[0]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
630 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
631
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
632 case D_GLOVAR:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
633 def_global(find_symbol(rands[0]), BSS, bloc, X_DATA);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
634 bloc = align(bloc + strtoul(rands[1], NULL, 0), 4);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
635 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
636
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
637 case D_MODULE:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
638 nmods++;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
639 this_module = find_symbol(rands[0]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
640 def_global(this_module, DATA, dloc, X_MODULE);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
641 module_data(this_module, strtoul(rands[1], NULL, 0),
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
642 strtol(rands[2], NULL, 0));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
643 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
644
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
645 case D_PRIMDEF:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
646 nprocs++;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
647 dloc = align(dloc, 8);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
648 buf_grow(prims);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
649 prims[nprims++] = dloc;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
650 def_global(find_symbol(rands[0]), DATA, dloc, X_PROC);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
651 const_head(DLTRAP, dloc + 4*CP_CONST + 4, R_DATA, 0, 0, NULL);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
652 data_value(0, R_WORD); // Pointer to access block
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
653 put_string(rands[2]); // Type descriptor
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
654 put_string(rands[1]); // Symbol name
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
655 dloc = align(dloc, 4);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
656 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
657
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
658 case D_PROC:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
659 nprocs++;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
660 dloc = align(dloc, 8);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
661 this_proc = find_symbol(rands[0]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
662 proc_start = dloc;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
663 def_global(this_proc, DATA, proc_start, X_PROC);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
664 const_head(INTERP, iloc, R_CODE, atoi(rands[1]),
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
665 atoi(rands[2]), rands[3]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
666
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
667 init_abuf();
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
668 init_labels();
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
669 nconsts = 0;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
670 smp = 0;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
671 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
672
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
673 case D_STKMAP:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
674 /* Stack map for a procedure call */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
675 check_inproc(dir);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
676 buf_grow(smbuf);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
677 smbuf[smp].sm_addr = put_mark(NULL);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
678 smbuf[smp].sm_text = must_strdup(rands[0]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
679 smp++;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
680 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
681
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
682 case D_END:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
683 /* End of procedure body */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
684 check_inproc(dir);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
685 assemble(); /* Finally choose templates */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
686 fix_stackmaps(); /* Compile the stack maps */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
687 make_binary(); /* Output the code */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
688 put_value(proc_start + 4*CP_SIZE, code_size, R_WORD);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
689 iloc += code_size;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
690 this_proc = NULL;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
691 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
692
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
693 case D_IMPORT:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
694 case D_ENDHDR:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
695 /* Ignore directives that appear in the file header */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
696 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
697
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
698 case D_DEFINE:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
699 def_global(find_symbol(rands[0]), DATA, dloc, X_DATA);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
700 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
701
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
702 case D_LINE:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
703 check_inproc(dir);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
704
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
705 if (gflag) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
706 char buf[64];
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
707 sprintf(buf, "%s.%s", sym_name(this_module), rands[0]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
708 put_mark(make_symbol(buf));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
709 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
710
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
711 if (linecount)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
712 put_inst("LNUM", rands, nrands);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
713
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
714 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
715
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
716 #ifdef SPECIALS
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
717 case D_PCALL:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
718 check_inproc(dir);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
719 gen_inst("CALL %d", atoi(rands[0])+1);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
720 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
721
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
722 case D_PCALLW:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
723 check_inproc(dir);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
724 gen_inst("CALLW %d", atoi(rands[0])+1);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
725 break;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
726 #endif
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
727
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
728 default:
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
729 panic("*unknown directive %s (%d)", dir, n);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
730 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
731 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
732
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
733 /* put_inst -- process one instruction or directive */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
734 void put_inst(const char *name, char *rands[], unsigned nrands) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
735 template t = find_template(name);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
736
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
737 if (nrands != strlen(t->t_pattern)) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
738 fprintf(stderr, "Instruction: %s", name);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
739 for (int i = 0; i < nrands; i++)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
740 fprintf(stderr, " %s", rands[i]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
741 fprintf(stderr, ", File: %s\n", err_file);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
742 panic("*%s needs %d operands, got %d",
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
743 name, strlen(t->t_pattern), nrands);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
744 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
745
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
746 if (t->t_size < 0)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
747 do_directive(t->t_name, t->t_op, rands, nrands);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
748 else {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
749 check_inproc(name);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
750 do_template(t, rands, abuf, NULL);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
751 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
752 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
753
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
754 /* gen_inst -- generate an instruction from text */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
755 void gen_inst(const char *fmt, ...) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
756 char line[80];
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
757 char *words[10];
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
758 int nwords;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
759
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
760 va_list ap;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
761
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
762 va_start(ap, fmt);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
763 vsprintf(line, fmt, ap);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
764 strcat(line, "\n");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
765 va_end(ap);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
766
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
767 nwords = split_line(line, words);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
768 put_inst(words[0], &words[1], nwords-1);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
769 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
770
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
771 /* save_string -- save a string in the data segment */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
772 void save_string(const char *label, char *str) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
773 def_global(find_symbol(label), DATA, dloc, X_DATA);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
774 put_string(str);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
775 dloc = align(dloc, 4);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
776 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
777
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
778
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
779 /* Object file output */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
780
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
781 static int start; /* Starting offset of binary */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
782
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
783 void init_linker(char *outname, char *interp) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
784 buf_init(dbuf, INIT_XMEM, 4, uchar, "data");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
785 buf_init(rbuf, INIT_XMEM/(WORD_SIZE * CODES_PER_WORD),
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
786 1, unsigned, "relocation");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
787 buf_init(smbuf, 16, 1, stackmap, "stack maps");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
788 buf_init(const_sym, 256, 1, symbol, "constant pool");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
789 buf_init(prims, 256, 1, int, "primitives");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
790
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
791 binfp = fopen(outname, "wb");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
792 if (binfp == NULL) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
793 perror(outname);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
794 exit(2);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
795 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
796
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
797 if (interp != NULL)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
798 fprintf(binfp, "#!%s\n", interp);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
799
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
800 start = ftell(binfp);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
801 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
802
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
803 /* end_linking -- write later parts of object file */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
804 void end_linking(void) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
805 trailer t;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
806 int fsize, csize, symcount = 0, nwritten;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
807 const char *magic = MAGIC;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
808
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
809 csize = ftell(binfp) - start;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
810 if (csize != iloc) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
811 fprintf(stderr, "csize = %d, iloc = %d\n", csize, iloc);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
812 panic("*Wrong code size");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
813 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
814
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
815 fix_data(dbuf, dloc);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
816 rloc = (dloc/WORD_SIZE+CODES_PER_WORD-1)/CODES_PER_WORD;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
817 buf_grow(rbuf);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
818
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
819 binwrite(dbuf, dloc);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
820 binwrite(rbuf, rloc * sizeof(unsigned));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
821 if (!sflag) symcount = write_symtab();
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
822
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
823 fsize = ftell(binfp) + sizeof(trailer);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
824
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
825 #define sym_val(x) (known(x) ? sym_value(find_symbol(x)) : 0)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
826
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
827 /* Trailer */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
828 strncpy((char *) t.magic, magic, 4);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
829 put4(t.sig, SIG);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
830 put4(t.primsig, 0);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
831 put4(t.start, start - fsize);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
832 put4(t.entry, sym_val("MAIN"));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
833 put4(t.gcmap, sym_val("GCMAP"));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
834 put4(t.libdir, sym_val("LIBDIR"));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
835 put4(t.segment[S_CODE], iloc);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
836 put4(t.segment[S_DATA], dloc);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
837 put4(t.segment[S_BSS], bloc);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
838 put4(t.segment[S_STACK], stack_size);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
839 put4(t.nprocs, (sflag ? 0 : nprocs));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
840 put4(t.nmods, (sflag ? 0 : nmods));
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
841 put4(t.nsyms, symcount);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
842 nwritten = fwrite(&t, sizeof(trailer), 1, binfp);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
843 if (nwritten < 1)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
844 panic("Couldn't write trailer");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
845
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
846 fclose(binfp);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
847 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
848
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
849
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
850 /* Routines for writing values in machine-independent byte order */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
851
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
852 void put_int(int n, uchar *buf, int x) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
853 for (int i = 0; i < n; i++)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
854 buf[i] = (x >> (8*i)) & 0xff;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
855 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
856
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
857 int get4(uchar *buf) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
858 return buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
859 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
860
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
861 void write_string(const char *s) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
862 binwrite((void *) s, strlen(s)+1);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
863 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
864
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
865 void write_int(int n, int x) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
866 uchar buf[4];
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
867 put_int(n, buf, x);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
868 binwrite(buf, n);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
869 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
870
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
871
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
872 /* Primitive table */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
873
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
874 void dump_prims(void) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
875 printf("/* Generated by oblink */\n\n");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
876 printf("#include \"primtab.h\"\n\n");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
877 printf("#define PRIMS(direct, indirect, wrapper)");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
878
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
879 for (int i = 0; i < nprims; i++) {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
880 char *tstring = (char *) &dbuf[prims[i]] + 4*CP_CONST + 4;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
881 char *name = tstring + strlen(tstring) + 1;
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
882
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
883 printf(" \\\n");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
884 if (tstring[0] == '*')
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
885 /* Declare a direct primitive */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
886 printf(" direct(%s)", name);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
887 else {
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
888 /* Build a wrapper */
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
889 char *mac = (isupper(name[0]) ? "indirect" : "wrapper");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
890 printf(" %s(%s", mac, name);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
891 for (int i = 0; tstring[i] != '\0'; i++)
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
892 printf(", %c", tstring[i]);
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
893 printf(")");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
894 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
895 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
896
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
897 printf("\n\n");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
898 printf("PRIMTAB(PRIMS)");
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
899 }
Mike Spivey <mike@cs.ox.ac.uk>
parents:
diff changeset
900