diff options
author | Mike Pall <mike> | 2011-12-16 21:33:40 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2011-12-16 21:33:40 +0100 |
commit | ba4917b71bba55e61f4ce644100cdb4e114ccfc5 (patch) | |
tree | 0d01ba2a34eeb138004cf7c7e3a8df86f4813eb3 /dynasm | |
parent | b330b468b3f37bd0b11765524548dbdbb1dd1a95 (diff) | |
download | luajit-ba4917b71bba55e61f4ce644100cdb4e114ccfc5.tar.gz luajit-ba4917b71bba55e61f4ce644100cdb4e114ccfc5.tar.bz2 luajit-ba4917b71bba55e61f4ce644100cdb4e114ccfc5.zip |
MIPS: Add DynASM MIPS module and encoding engine.
Diffstat (limited to 'dynasm')
-rw-r--r-- | dynasm/dasm_mips.h | 415 | ||||
-rw-r--r-- | dynasm/dasm_mips.lua | 948 |
2 files changed, 1363 insertions, 0 deletions
diff --git a/dynasm/dasm_mips.h b/dynasm/dasm_mips.h new file mode 100644 index 00000000..832f9f2e --- /dev/null +++ b/dynasm/dasm_mips.h | |||
@@ -0,0 +1,415 @@ | |||
1 | /* | ||
2 | ** DynASM MIPS encoding engine. | ||
3 | ** Copyright (C) 2005-2011 Mike Pall. All rights reserved. | ||
4 | ** Released under the MIT license. See dynasm.lua for full copyright notice. | ||
5 | */ | ||
6 | |||
7 | #include <stddef.h> | ||
8 | #include <stdarg.h> | ||
9 | #include <string.h> | ||
10 | #include <stdlib.h> | ||
11 | |||
12 | #define DASM_ARCH "mips" | ||
13 | |||
14 | #ifndef DASM_EXTERN | ||
15 | #define DASM_EXTERN(a,b,c,d) 0 | ||
16 | #endif | ||
17 | |||
18 | /* Action definitions. */ | ||
19 | enum { | ||
20 | DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, | ||
21 | /* The following actions need a buffer position. */ | ||
22 | DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, | ||
23 | /* The following actions also have an argument. */ | ||
24 | DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, | ||
25 | DASM__MAX | ||
26 | }; | ||
27 | |||
28 | /* Maximum number of section buffer positions for a single dasm_put() call. */ | ||
29 | #define DASM_MAXSECPOS 25 | ||
30 | |||
31 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */ | ||
32 | #define DASM_S_OK 0x00000000 | ||
33 | #define DASM_S_NOMEM 0x01000000 | ||
34 | #define DASM_S_PHASE 0x02000000 | ||
35 | #define DASM_S_MATCH_SEC 0x03000000 | ||
36 | #define DASM_S_RANGE_I 0x11000000 | ||
37 | #define DASM_S_RANGE_SEC 0x12000000 | ||
38 | #define DASM_S_RANGE_LG 0x13000000 | ||
39 | #define DASM_S_RANGE_PC 0x14000000 | ||
40 | #define DASM_S_RANGE_REL 0x15000000 | ||
41 | #define DASM_S_UNDEF_LG 0x21000000 | ||
42 | #define DASM_S_UNDEF_PC 0x22000000 | ||
43 | |||
44 | /* Macros to convert positions (8 bit section + 24 bit index). */ | ||
45 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff) | ||
46 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000) | ||
47 | #define DASM_SEC2POS(sec) ((sec)<<24) | ||
48 | #define DASM_POS2SEC(pos) ((pos)>>24) | ||
49 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) | ||
50 | |||
51 | /* Action list type. */ | ||
52 | typedef const unsigned int *dasm_ActList; | ||
53 | |||
54 | /* Per-section structure. */ | ||
55 | typedef struct dasm_Section { | ||
56 | int *rbuf; /* Biased buffer pointer (negative section bias). */ | ||
57 | int *buf; /* True buffer pointer. */ | ||
58 | size_t bsize; /* Buffer size in bytes. */ | ||
59 | int pos; /* Biased buffer position. */ | ||
60 | int epos; /* End of biased buffer position - max single put. */ | ||
61 | int ofs; /* Byte offset into section. */ | ||
62 | } dasm_Section; | ||
63 | |||
64 | /* Core structure holding the DynASM encoding state. */ | ||
65 | struct dasm_State { | ||
66 | size_t psize; /* Allocated size of this structure. */ | ||
67 | dasm_ActList actionlist; /* Current actionlist pointer. */ | ||
68 | int *lglabels; /* Local/global chain/pos ptrs. */ | ||
69 | size_t lgsize; | ||
70 | int *pclabels; /* PC label chains/pos ptrs. */ | ||
71 | size_t pcsize; | ||
72 | void **globals; /* Array of globals (bias -10). */ | ||
73 | dasm_Section *section; /* Pointer to active section. */ | ||
74 | size_t codesize; /* Total size of all code sections. */ | ||
75 | int maxsection; /* 0 <= sectionidx < maxsection. */ | ||
76 | int status; /* Status code. */ | ||
77 | dasm_Section sections[1]; /* All sections. Alloc-extended. */ | ||
78 | }; | ||
79 | |||
80 | /* The size of the core structure depends on the max. number of sections. */ | ||
81 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) | ||
82 | |||
83 | |||
84 | /* Initialize DynASM state. */ | ||
85 | void dasm_init(Dst_DECL, int maxsection) | ||
86 | { | ||
87 | dasm_State *D; | ||
88 | size_t psz = 0; | ||
89 | int i; | ||
90 | Dst_REF = NULL; | ||
91 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); | ||
92 | D = Dst_REF; | ||
93 | D->psize = psz; | ||
94 | D->lglabels = NULL; | ||
95 | D->lgsize = 0; | ||
96 | D->pclabels = NULL; | ||
97 | D->pcsize = 0; | ||
98 | D->globals = NULL; | ||
99 | D->maxsection = maxsection; | ||
100 | for (i = 0; i < maxsection; i++) { | ||
101 | D->sections[i].buf = NULL; /* Need this for pass3. */ | ||
102 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); | ||
103 | D->sections[i].bsize = 0; | ||
104 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ | ||
105 | } | ||
106 | } | ||
107 | |||
108 | /* Free DynASM state. */ | ||
109 | void dasm_free(Dst_DECL) | ||
110 | { | ||
111 | dasm_State *D = Dst_REF; | ||
112 | int i; | ||
113 | for (i = 0; i < D->maxsection; i++) | ||
114 | if (D->sections[i].buf) | ||
115 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); | ||
116 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); | ||
117 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); | ||
118 | DASM_M_FREE(Dst, D, D->psize); | ||
119 | } | ||
120 | |||
121 | /* Setup global label array. Must be called before dasm_setup(). */ | ||
122 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) | ||
123 | { | ||
124 | dasm_State *D = Dst_REF; | ||
125 | D->globals = gl - 10; /* Negative bias to compensate for locals. */ | ||
126 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); | ||
127 | } | ||
128 | |||
129 | /* Grow PC label array. Can be called after dasm_setup(), too. */ | ||
130 | void dasm_growpc(Dst_DECL, unsigned int maxpc) | ||
131 | { | ||
132 | dasm_State *D = Dst_REF; | ||
133 | size_t osz = D->pcsize; | ||
134 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); | ||
135 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); | ||
136 | } | ||
137 | |||
138 | /* Setup encoder. */ | ||
139 | void dasm_setup(Dst_DECL, const void *actionlist) | ||
140 | { | ||
141 | dasm_State *D = Dst_REF; | ||
142 | int i; | ||
143 | D->actionlist = (dasm_ActList)actionlist; | ||
144 | D->status = DASM_S_OK; | ||
145 | D->section = &D->sections[0]; | ||
146 | memset((void *)D->lglabels, 0, D->lgsize); | ||
147 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); | ||
148 | for (i = 0; i < D->maxsection; i++) { | ||
149 | D->sections[i].pos = DASM_SEC2POS(i); | ||
150 | D->sections[i].ofs = 0; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | |||
155 | #ifdef DASM_CHECKS | ||
156 | #define CK(x, st) \ | ||
157 | do { if (!(x)) { \ | ||
158 | D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) | ||
159 | #define CKPL(kind, st) \ | ||
160 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ | ||
161 | D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) | ||
162 | #else | ||
163 | #define CK(x, st) ((void)0) | ||
164 | #define CKPL(kind, st) ((void)0) | ||
165 | #endif | ||
166 | |||
167 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ | ||
168 | void dasm_put(Dst_DECL, int start, ...) | ||
169 | { | ||
170 | va_list ap; | ||
171 | dasm_State *D = Dst_REF; | ||
172 | dasm_ActList p = D->actionlist + start; | ||
173 | dasm_Section *sec = D->section; | ||
174 | int pos = sec->pos, ofs = sec->ofs; | ||
175 | int *b; | ||
176 | |||
177 | if (pos >= sec->epos) { | ||
178 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize, | ||
179 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); | ||
180 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos); | ||
181 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); | ||
182 | } | ||
183 | |||
184 | b = sec->rbuf; | ||
185 | b[pos++] = start; | ||
186 | |||
187 | va_start(ap, start); | ||
188 | while (1) { | ||
189 | unsigned int ins = *p++; | ||
190 | unsigned int action = (ins >> 16) - 0xff00; | ||
191 | if (action >= DASM__MAX) { | ||
192 | ofs += 4; | ||
193 | } else { | ||
194 | int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; | ||
195 | switch (action) { | ||
196 | case DASM_STOP: goto stop; | ||
197 | case DASM_SECTION: | ||
198 | n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); | ||
199 | D->section = &D->sections[n]; goto stop; | ||
200 | case DASM_ESC: p++; ofs += 4; break; | ||
201 | case DASM_REL_EXT: break; | ||
202 | case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; | ||
203 | case DASM_REL_LG: | ||
204 | n = (ins & 2047) - 10; pl = D->lglabels + n; | ||
205 | if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ | ||
206 | pl += 10; n = *pl; | ||
207 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ | ||
208 | goto linkrel; | ||
209 | case DASM_REL_PC: | ||
210 | pl = D->pclabels + n; CKPL(pc, PC); | ||
211 | putrel: | ||
212 | n = *pl; | ||
213 | if (n < 0) { /* Label exists. Get label pos and store it. */ | ||
214 | b[pos] = -n; | ||
215 | } else { | ||
216 | linkrel: | ||
217 | b[pos] = n; /* Else link to rel chain, anchored at label. */ | ||
218 | *pl = pos; | ||
219 | } | ||
220 | pos++; | ||
221 | break; | ||
222 | case DASM_LABEL_LG: | ||
223 | pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; | ||
224 | case DASM_LABEL_PC: | ||
225 | pl = D->pclabels + n; CKPL(pc, PC); | ||
226 | putlabel: | ||
227 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ | ||
228 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; | ||
229 | } | ||
230 | *pl = -pos; /* Label exists now. */ | ||
231 | b[pos++] = ofs; /* Store pass1 offset estimate. */ | ||
232 | break; | ||
233 | case DASM_IMM: | ||
234 | #ifdef DASM_CHECKS | ||
235 | CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); | ||
236 | #endif | ||
237 | n >>= ((ins>>10)&31); | ||
238 | #ifdef DASM_CHECKS | ||
239 | if (ins & 0x8000) | ||
240 | CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); | ||
241 | else | ||
242 | CK((n>>((ins>>5)&31)) == 0, RANGE_I); | ||
243 | #endif | ||
244 | b[pos++] = n; | ||
245 | break; | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | stop: | ||
250 | va_end(ap); | ||
251 | sec->pos = pos; | ||
252 | sec->ofs = ofs; | ||
253 | } | ||
254 | #undef CK | ||
255 | |||
256 | /* Pass 2: Link sections, shrink aligns, fix label offsets. */ | ||
257 | int dasm_link(Dst_DECL, size_t *szp) | ||
258 | { | ||
259 | dasm_State *D = Dst_REF; | ||
260 | int secnum; | ||
261 | int ofs = 0; | ||
262 | |||
263 | #ifdef DASM_CHECKS | ||
264 | *szp = 0; | ||
265 | if (D->status != DASM_S_OK) return D->status; | ||
266 | { | ||
267 | int pc; | ||
268 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) | ||
269 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; | ||
270 | } | ||
271 | #endif | ||
272 | |||
273 | { /* Handle globals not defined in this translation unit. */ | ||
274 | int idx; | ||
275 | for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { | ||
276 | int n = D->lglabels[idx]; | ||
277 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */ | ||
278 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } | ||
279 | } | ||
280 | } | ||
281 | |||
282 | /* Combine all code sections. No support for data sections (yet). */ | ||
283 | for (secnum = 0; secnum < D->maxsection; secnum++) { | ||
284 | dasm_Section *sec = D->sections + secnum; | ||
285 | int *b = sec->rbuf; | ||
286 | int pos = DASM_SEC2POS(secnum); | ||
287 | int lastpos = sec->pos; | ||
288 | |||
289 | while (pos != lastpos) { | ||
290 | dasm_ActList p = D->actionlist + b[pos++]; | ||
291 | while (1) { | ||
292 | unsigned int ins = *p++; | ||
293 | unsigned int action = (ins >> 16) - 0xff00; | ||
294 | switch (action) { | ||
295 | case DASM_STOP: case DASM_SECTION: goto stop; | ||
296 | case DASM_ESC: p++; break; | ||
297 | case DASM_REL_EXT: break; | ||
298 | case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; | ||
299 | case DASM_REL_LG: case DASM_REL_PC: pos++; break; | ||
300 | case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; | ||
301 | case DASM_IMM: pos++; break; | ||
302 | } | ||
303 | } | ||
304 | stop: (void)0; | ||
305 | } | ||
306 | ofs += sec->ofs; /* Next section starts right after current section. */ | ||
307 | } | ||
308 | |||
309 | D->codesize = ofs; /* Total size of all code sections */ | ||
310 | *szp = ofs; | ||
311 | return DASM_S_OK; | ||
312 | } | ||
313 | |||
314 | #ifdef DASM_CHECKS | ||
315 | #define CK(x, st) \ | ||
316 | do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) | ||
317 | #else | ||
318 | #define CK(x, st) ((void)0) | ||
319 | #endif | ||
320 | |||
321 | /* Pass 3: Encode sections. */ | ||
322 | int dasm_encode(Dst_DECL, void *buffer) | ||
323 | { | ||
324 | dasm_State *D = Dst_REF; | ||
325 | char *base = (char *)buffer; | ||
326 | unsigned int *cp = (unsigned int *)buffer; | ||
327 | int secnum; | ||
328 | |||
329 | /* Encode all code sections. No support for data sections (yet). */ | ||
330 | for (secnum = 0; secnum < D->maxsection; secnum++) { | ||
331 | dasm_Section *sec = D->sections + secnum; | ||
332 | int *b = sec->buf; | ||
333 | int *endb = sec->rbuf + sec->pos; | ||
334 | |||
335 | while (b != endb) { | ||
336 | dasm_ActList p = D->actionlist + *b++; | ||
337 | while (1) { | ||
338 | unsigned int ins = *p++; | ||
339 | unsigned int action = (ins >> 16) - 0xff00; | ||
340 | int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; | ||
341 | switch (action) { | ||
342 | case DASM_STOP: case DASM_SECTION: goto stop; | ||
343 | case DASM_ESC: *cp++ = *p++; break; | ||
344 | case DASM_REL_EXT: | ||
345 | n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1); | ||
346 | goto patchrel; | ||
347 | case DASM_ALIGN: | ||
348 | ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; | ||
349 | break; | ||
350 | case DASM_REL_LG: | ||
351 | CK(n >= 0, UNDEF_LG); | ||
352 | case DASM_REL_PC: | ||
353 | CK(n >= 0, UNDEF_PC); | ||
354 | n = *DASM_POS2PTR(D, n); | ||
355 | if (ins & 2048) | ||
356 | n = n - (int)((char *)cp - base); | ||
357 | else | ||
358 | n = (n + (int)base) & 0x0fffffff; | ||
359 | patchrel: | ||
360 | CK((n & 3) == 0 && | ||
361 | ((n + ((ins & 2048) ? 0x00020000 : 0)) >> | ||
362 | ((ins & 2048) ? 18 : 28)) == 0, RANGE_REL); | ||
363 | cp[-1] |= ((n>>2) & ((ins & 2048) ? 0x0000ffff: 0x03ffffff)); | ||
364 | break; | ||
365 | case DASM_LABEL_LG: | ||
366 | ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); | ||
367 | break; | ||
368 | case DASM_LABEL_PC: break; | ||
369 | case DASM_IMM: | ||
370 | cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); | ||
371 | break; | ||
372 | default: *cp++ = ins; break; | ||
373 | } | ||
374 | } | ||
375 | stop: (void)0; | ||
376 | } | ||
377 | } | ||
378 | |||
379 | if (base + D->codesize != (char *)cp) /* Check for phase errors. */ | ||
380 | return DASM_S_PHASE; | ||
381 | return DASM_S_OK; | ||
382 | } | ||
383 | #undef CK | ||
384 | |||
385 | /* Get PC label offset. */ | ||
386 | int dasm_getpclabel(Dst_DECL, unsigned int pc) | ||
387 | { | ||
388 | dasm_State *D = Dst_REF; | ||
389 | if (pc*sizeof(int) < D->pcsize) { | ||
390 | int pos = D->pclabels[pc]; | ||
391 | if (pos < 0) return *DASM_POS2PTR(D, -pos); | ||
392 | if (pos > 0) return -1; /* Undefined. */ | ||
393 | } | ||
394 | return -2; /* Unused or out of range. */ | ||
395 | } | ||
396 | |||
397 | #ifdef DASM_CHECKS | ||
398 | /* Optional sanity checker to call between isolated encoding steps. */ | ||
399 | int dasm_checkstep(Dst_DECL, int secmatch) | ||
400 | { | ||
401 | dasm_State *D = Dst_REF; | ||
402 | if (D->status == DASM_S_OK) { | ||
403 | int i; | ||
404 | for (i = 1; i <= 9; i++) { | ||
405 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } | ||
406 | D->lglabels[i] = 0; | ||
407 | } | ||
408 | } | ||
409 | if (D->status == DASM_S_OK && secmatch >= 0 && | ||
410 | D->section != &D->sections[secmatch]) | ||
411 | D->status = DASM_S_MATCH_SEC|(D->section-D->sections); | ||
412 | return D->status; | ||
413 | } | ||
414 | #endif | ||
415 | |||
diff --git a/dynasm/dasm_mips.lua b/dynasm/dasm_mips.lua new file mode 100644 index 00000000..5cbae8ba --- /dev/null +++ b/dynasm/dasm_mips.lua | |||
@@ -0,0 +1,948 @@ | |||
1 | ------------------------------------------------------------------------------ | ||
2 | -- DynASM MIPS module. | ||
3 | -- | ||
4 | -- Copyright (C) 2005-2011 Mike Pall. All rights reserved. | ||
5 | -- See dynasm.lua for full copyright notice. | ||
6 | ------------------------------------------------------------------------------ | ||
7 | |||
8 | -- Module information: | ||
9 | local _info = { | ||
10 | arch = "mips", | ||
11 | description = "DynASM MIPS module", | ||
12 | version = "1.3.0", | ||
13 | vernum = 10300, | ||
14 | release = "2011-12-16", | ||
15 | author = "Mike Pall", | ||
16 | license = "MIT", | ||
17 | } | ||
18 | |||
19 | -- Exported glue functions for the arch-specific module. | ||
20 | local _M = { _info = _info } | ||
21 | |||
22 | -- Cache library functions. | ||
23 | local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs | ||
24 | local assert, setmetatable = assert, setmetatable | ||
25 | local _s = string | ||
26 | local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char | ||
27 | local match, gmatch = _s.match, _s.gmatch | ||
28 | local concat, sort = table.concat, table.sort | ||
29 | |||
30 | -- Inherited tables and callbacks. | ||
31 | local g_opt, g_arch | ||
32 | local wline, werror, wfatal, wwarn | ||
33 | |||
34 | -- Action name list. | ||
35 | -- CHECK: Keep this in sync with the C code! | ||
36 | local action_names = { | ||
37 | "STOP", "SECTION", "ESC", "REL_EXT", | ||
38 | "ALIGN", "REL_LG", "LABEL_LG", | ||
39 | "REL_PC", "LABEL_PC", "IMM", | ||
40 | } | ||
41 | |||
42 | -- Maximum number of section buffer positions for dasm_put(). | ||
43 | -- CHECK: Keep this in sync with the C code! | ||
44 | local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. | ||
45 | |||
46 | -- Action name -> action number. | ||
47 | local map_action = {} | ||
48 | for n,name in ipairs(action_names) do | ||
49 | map_action[name] = n-1 | ||
50 | end | ||
51 | |||
52 | -- Action list buffer. | ||
53 | local actlist = {} | ||
54 | |||
55 | -- Argument list for next dasm_put(). Start with offset 0 into action list. | ||
56 | local actargs = { 0 } | ||
57 | |||
58 | -- Current number of section buffer positions for dasm_put(). | ||
59 | local secpos = 1 | ||
60 | |||
61 | ------------------------------------------------------------------------------ | ||
62 | |||
63 | -- Return 8 digit hex number. | ||
64 | local function tohex(x) | ||
65 | return sub(format("%08x", x), -8) -- Avoid 64 bit portability problem in Lua. | ||
66 | end | ||
67 | |||
68 | -- Dump action names and numbers. | ||
69 | local function dumpactions(out) | ||
70 | out:write("DynASM encoding engine action codes:\n") | ||
71 | for n,name in ipairs(action_names) do | ||
72 | local num = map_action[name] | ||
73 | out:write(format(" %-10s %02X %d\n", name, num, num)) | ||
74 | end | ||
75 | out:write("\n") | ||
76 | end | ||
77 | |||
78 | -- Write action list buffer as a huge static C array. | ||
79 | local function writeactions(out, name) | ||
80 | local nn = #actlist | ||
81 | if nn == 0 then nn = 1; actlist[0] = map_action.STOP end | ||
82 | out:write("static const unsigned int ", name, "[", nn, "] = {\n") | ||
83 | for i = 1,nn-1 do | ||
84 | assert(out:write("0x", tohex(actlist[i]), ",\n")) | ||
85 | end | ||
86 | assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) | ||
87 | end | ||
88 | |||
89 | ------------------------------------------------------------------------------ | ||
90 | |||
91 | -- Add word to action list. | ||
92 | local function wputxw(n) | ||
93 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") | ||
94 | actlist[#actlist+1] = n | ||
95 | end | ||
96 | |||
97 | -- Add action to list with optional arg. Advance buffer pos, too. | ||
98 | local function waction(action, val, a, num) | ||
99 | local w = assert(map_action[action], "bad action name `"..action.."'") | ||
100 | wputxw(0xff000000 + w * 0x10000 + (val or 0)) | ||
101 | if a then actargs[#actargs+1] = a end | ||
102 | if a or num then secpos = secpos + (num or 1) end | ||
103 | end | ||
104 | |||
105 | -- Flush action list (intervening C code or buffer pos overflow). | ||
106 | local function wflush(term) | ||
107 | if #actlist == actargs[1] then return end -- Nothing to flush. | ||
108 | if not term then waction("STOP") end -- Terminate action list. | ||
109 | wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) | ||
110 | actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). | ||
111 | secpos = 1 -- The actionlist offset occupies a buffer position, too. | ||
112 | end | ||
113 | |||
114 | -- Put escaped word. | ||
115 | local function wputw(n) | ||
116 | if n >= 0xff000000 then waction("ESC") end | ||
117 | wputxw(n) | ||
118 | end | ||
119 | |||
120 | -- Reserve position for word. | ||
121 | local function wpos() | ||
122 | local pos = #actlist+1 | ||
123 | actlist[pos] = "" | ||
124 | return pos | ||
125 | end | ||
126 | |||
127 | -- Store word to reserved position. | ||
128 | local function wputpos(pos, n) | ||
129 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") | ||
130 | actlist[pos] = n | ||
131 | end | ||
132 | |||
133 | ------------------------------------------------------------------------------ | ||
134 | |||
135 | -- Global label name -> global label number. With auto assignment on 1st use. | ||
136 | local next_global = 20 | ||
137 | local map_global = setmetatable({}, { __index = function(t, name) | ||
138 | if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end | ||
139 | local n = next_global | ||
140 | if n > 2047 then werror("too many global labels") end | ||
141 | next_global = n + 1 | ||
142 | t[name] = n | ||
143 | return n | ||
144 | end}) | ||
145 | |||
146 | -- Dump global labels. | ||
147 | local function dumpglobals(out, lvl) | ||
148 | local t = {} | ||
149 | for name, n in pairs(map_global) do t[n] = name end | ||
150 | out:write("Global labels:\n") | ||
151 | for i=20,next_global-1 do | ||
152 | out:write(format(" %s\n", t[i])) | ||
153 | end | ||
154 | out:write("\n") | ||
155 | end | ||
156 | |||
157 | -- Write global label enum. | ||
158 | local function writeglobals(out, prefix) | ||
159 | local t = {} | ||
160 | for name, n in pairs(map_global) do t[n] = name end | ||
161 | out:write("enum {\n") | ||
162 | for i=20,next_global-1 do | ||
163 | out:write(" ", prefix, t[i], ",\n") | ||
164 | end | ||
165 | out:write(" ", prefix, "_MAX\n};\n") | ||
166 | end | ||
167 | |||
168 | -- Write global label names. | ||
169 | local function writeglobalnames(out, name) | ||
170 | local t = {} | ||
171 | for name, n in pairs(map_global) do t[n] = name end | ||
172 | out:write("static const char *const ", name, "[] = {\n") | ||
173 | for i=20,next_global-1 do | ||
174 | out:write(" \"", t[i], "\",\n") | ||
175 | end | ||
176 | out:write(" (const char *)0\n};\n") | ||
177 | end | ||
178 | |||
179 | ------------------------------------------------------------------------------ | ||
180 | |||
181 | -- Extern label name -> extern label number. With auto assignment on 1st use. | ||
182 | local next_extern = 0 | ||
183 | local map_extern_ = {} | ||
184 | local map_extern = setmetatable({}, { __index = function(t, name) | ||
185 | -- No restrictions on the name for now. | ||
186 | local n = next_extern | ||
187 | if n > 2047 then werror("too many extern labels") end | ||
188 | next_extern = n + 1 | ||
189 | t[name] = n | ||
190 | map_extern_[n] = name | ||
191 | return n | ||
192 | end}) | ||
193 | |||
194 | -- Dump extern labels. | ||
195 | local function dumpexterns(out, lvl) | ||
196 | out:write("Extern labels:\n") | ||
197 | for i=0,next_extern-1 do | ||
198 | out:write(format(" %s\n", map_extern_[i])) | ||
199 | end | ||
200 | out:write("\n") | ||
201 | end | ||
202 | |||
203 | -- Write extern label names. | ||
204 | local function writeexternnames(out, name) | ||
205 | out:write("static const char *const ", name, "[] = {\n") | ||
206 | for i=0,next_extern-1 do | ||
207 | out:write(" \"", map_extern_[i], "\",\n") | ||
208 | end | ||
209 | out:write(" (const char *)0\n};\n") | ||
210 | end | ||
211 | |||
212 | ------------------------------------------------------------------------------ | ||
213 | |||
214 | -- Arch-specific maps. | ||
215 | local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name. | ||
216 | |||
217 | local map_type = {} -- Type name -> { ctype, reg } | ||
218 | local ctypenum = 0 -- Type number (for Dt... macros). | ||
219 | |||
220 | -- Reverse defines for registers. | ||
221 | function _M.revdef(s) | ||
222 | if s == "r29" then return "sp" | ||
223 | elseif s == "r31" then return "ra" end | ||
224 | return s | ||
225 | end | ||
226 | |||
227 | ------------------------------------------------------------------------------ | ||
228 | |||
229 | -- Template strings for MIPS instructions. | ||
230 | local map_op = { | ||
231 | -- First-level opcodes. | ||
232 | j_1 = "08000000J", | ||
233 | jal_1 = "0c000000J", | ||
234 | b_1 = "10000000B", | ||
235 | beqz_2 = "10000000SB", | ||
236 | beq_3 = "10000000STB", | ||
237 | bnez_2 = "14000000SB", | ||
238 | bne_3 = "14000000STB", | ||
239 | blez_2 = "18000000SB", | ||
240 | bgtz_2 = "1c000000SB", | ||
241 | addi_3 = "20000000TSI", | ||
242 | li_2 = "24000000TI", | ||
243 | addiu_3 = "24000000TSI", | ||
244 | slti_3 = "28000000TSI", | ||
245 | sltiu_3 = "2c000000TSI", | ||
246 | andi_3 = "30000000TSU", | ||
247 | lu_2 = "34000000TU", | ||
248 | ori_3 = "34000000TSU", | ||
249 | xori_3 = "38000000TSU", | ||
250 | lui_2 = "3c000000TU", | ||
251 | beqzl_2 = "50000000SB", | ||
252 | beql_3 = "50000000STB", | ||
253 | bnezl_2 = "54000000SB", | ||
254 | bnel_3 = "54000000STB", | ||
255 | blezl_2 = "58000000SB", | ||
256 | bgtzl_2 = "5c000000SB", | ||
257 | lb_2 = "80000000TO", | ||
258 | lh_2 = "84000000TO", | ||
259 | lwl_2 = "88000000TO", | ||
260 | lw_2 = "8c000000TO", | ||
261 | lbu_2 = "90000000TO", | ||
262 | lhu_2 = "94000000TO", | ||
263 | lwr_2 = "98000000TO", | ||
264 | sb_2 = "a0000000TO", | ||
265 | sh_2 = "a4000000TO", | ||
266 | swl_2 = "a8000000TO", | ||
267 | sw_2 = "ac000000TO", | ||
268 | swr_2 = "b8000000TO", | ||
269 | cache_2 = "bc000000NO", | ||
270 | ll_2 = "c0000000TO", | ||
271 | lwc1_2 = "c4000000HO", | ||
272 | pref_2 = "cc000000NO", | ||
273 | ldc1_2 = "d4000000HO", | ||
274 | sc_2 = "e0000000TO", | ||
275 | swc1_2 = "e4000000HO", | ||
276 | sdc1_2 = "f4000000HO", | ||
277 | |||
278 | -- Opcode SPECIAL. | ||
279 | nop_0 = "00000000", | ||
280 | sll_3 = "00000000DTA", | ||
281 | movf_3 = "00000001DSC", | ||
282 | movt_3 = "00010001DSC", | ||
283 | srl_3 = "00000002DTA", | ||
284 | rotr_3 = "00200002DTA", | ||
285 | sra_3 = "00000003DTA", | ||
286 | sllv_3 = "00000004DTS", | ||
287 | srlv_3 = "00000006DTS", | ||
288 | rotrv_3 = "00000046DTS", | ||
289 | srav_3 = "00000007DTS", | ||
290 | jr_1 = "00000008S", | ||
291 | jalr_1 = "0000f809S", | ||
292 | jalr_2 = "00000009DS", | ||
293 | movz_3 = "0000000aDST", | ||
294 | movn_3 = "0000000bDST", | ||
295 | syscall_0 = "0000000c", | ||
296 | syscall_1 = "0000000cY", | ||
297 | break_0 = "0000000d", | ||
298 | break_1 = "0000000dY", | ||
299 | sync_0 = "0000000f", | ||
300 | mfhi_1 = "00000010D", | ||
301 | mthi_1 = "00000011S", | ||
302 | mflo_1 = "00000012D", | ||
303 | mtlo_1 = "00000013S", | ||
304 | mult_2 = "00000018ST", | ||
305 | multu_2 = "00000019ST", | ||
306 | div_2 = "0000001aST", | ||
307 | divu_2 = "0000001bST", | ||
308 | add_3 = "00000020DST", | ||
309 | move_2 = "00000021DS", | ||
310 | addu_3 = "00000021DST", | ||
311 | sub_3 = "00000022DST", | ||
312 | subu_3 = "00000023DST", | ||
313 | and_3 = "00000024DST", | ||
314 | or_3 = "00000025DST", | ||
315 | xor_3 = "00000026DST", | ||
316 | nor_3 = "00000027DST", | ||
317 | slt_3 = "0000002aDST", | ||
318 | sltu_3 = "0000002bDST", | ||
319 | tge_2 = "00000030ST", | ||
320 | tge_3 = "00000030STZ", | ||
321 | tgeu_2 = "00000031ST", | ||
322 | tgeu_3 = "00000031STZ", | ||
323 | tlt_2 = "00000032ST", | ||
324 | tlt_3 = "00000032STZ", | ||
325 | tltu_2 = "00000033ST", | ||
326 | tltu_3 = "00000033STZ", | ||
327 | teq_2 = "00000034ST", | ||
328 | teq_3 = "00000034STZ", | ||
329 | tne_2 = "00000036ST", | ||
330 | tne_3 = "00000036STZ", | ||
331 | |||
332 | -- Opcode REGIMM. | ||
333 | bltz_2 = "04000000SB", | ||
334 | bgez_2 = "04010000SB", | ||
335 | bltzl_2 = "04020000SB", | ||
336 | bgezl_2 = "04030000SB", | ||
337 | tgei_2 = "04080000SI", | ||
338 | tgeiu_2 = "04090000SI", | ||
339 | tlti_2 = "040a0000SI", | ||
340 | tltiu_2 = "040b0000SI", | ||
341 | teqi_2 = "040c0000SI", | ||
342 | tnei_2 = "040e0000SI", | ||
343 | bltzal_2 = "04100000SB", | ||
344 | bgezal_2 = "04110000SB", | ||
345 | bltzall_2 = "04120000SB", | ||
346 | bgezall_2 = "04130000SB", | ||
347 | synci_1 = "041f0000O", | ||
348 | |||
349 | -- Opcode SPECIAL2. | ||
350 | madd_2 = "70000000ST", | ||
351 | maddu_2 = "70000001ST", | ||
352 | mul_3 = "70000002DST", | ||
353 | msub_2 = "70000004ST", | ||
354 | msubu_2 = "70000005ST", | ||
355 | clz_2 = "70000020DS=", | ||
356 | clo_2 = "70000021DS=", | ||
357 | sdbbp_0 = "7000003f", | ||
358 | sdbbp_1 = "7000003fY", | ||
359 | |||
360 | -- Opcode SPECIAL3. | ||
361 | ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1 | ||
362 | ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1 | ||
363 | wsbh_2 = "7c0000a0DT", | ||
364 | seb_2 = "7c000420DT", | ||
365 | seh_2 = "7c000620DT", | ||
366 | rdhwr_2 = "7c00003bTD", | ||
367 | |||
368 | -- Opcode COP0. | ||
369 | mfc0_2 = "40000000TD", | ||
370 | mfc0_3 = "40000000TDW", | ||
371 | mtc0_2 = "40800000TD", | ||
372 | mtc0_3 = "40800000TDW", | ||
373 | rdpgpr_2 = "41400000DT", | ||
374 | di_0 = "41606000", | ||
375 | di_1 = "41606000T", | ||
376 | ei_0 = "41606020", | ||
377 | ei_1 = "41606020T", | ||
378 | wrpgpr_2 = "41c00000DT", | ||
379 | tlbr_0 = "42000001", | ||
380 | tlbwi_0 = "42000002", | ||
381 | tlbwr_0 = "42000006", | ||
382 | tlbp_0 = "42000008", | ||
383 | eret_0 = "42000018", | ||
384 | deret_0 = "4200001f", | ||
385 | wait_0 = "42000020", | ||
386 | |||
387 | -- Opcode COP1. | ||
388 | mfc1_2 = "44000000TG", | ||
389 | cfc1_2 = "44400000TG", | ||
390 | mfhc1_2 = "44600000TG", | ||
391 | mtc1_2 = "44800000TG", | ||
392 | ctc1_2 = "44c00000TG", | ||
393 | mthc1_2 = "44e00000TG", | ||
394 | |||
395 | bc1f_1 = "45000000B", | ||
396 | bc1f_2 = "45000000CB", | ||
397 | bc1t_1 = "45010000B", | ||
398 | bc1t_2 = "45010000CB", | ||
399 | bc1fl_1 = "45020000B", | ||
400 | bc1fl_2 = "45020000CB", | ||
401 | bc1tl_1 = "45030000B", | ||
402 | bc1tl_2 = "45030000CB", | ||
403 | |||
404 | ["add.s_3"] = "46000000FGH", | ||
405 | ["sub.s_3"] = "46000001FGH", | ||
406 | ["mul.s_3"] = "46000002FGH", | ||
407 | ["div.s_3"] = "46000003FGH", | ||
408 | ["sqrt.s_2"] = "46000004FG", | ||
409 | ["abs.s_2"] = "46000005FG", | ||
410 | ["mov.s_2"] = "46000006FG", | ||
411 | ["neg.s_2"] = "46000007FG", | ||
412 | ["round.l.s_2"] = "46000008FG", | ||
413 | ["trunc.l.s_2"] = "46000009FG", | ||
414 | ["ceil.l.s_2"] = "4600000aFG", | ||
415 | ["floor.l.s_2"] = "4600000bFG", | ||
416 | ["round.w.s_2"] = "4600000cFG", | ||
417 | ["trunc.w.s_2"] = "4600000dFG", | ||
418 | ["ceil.w.s_2"] = "4600000eFG", | ||
419 | ["floor.w.s_2"] = "4600000fFG", | ||
420 | ["movf.s_2"] = "46000011FG", | ||
421 | ["movf.s_3"] = "46000011FGC", | ||
422 | ["movt.s_2"] = "46010011FG", | ||
423 | ["movt.s_3"] = "46010011FGC", | ||
424 | ["movz.s_3"] = "46000012FGT", | ||
425 | ["movn.s_3"] = "46000013FGT", | ||
426 | ["recip.s_2"] = "46000015FG", | ||
427 | ["rsqrt.s_2"] = "46000016FG", | ||
428 | ["cvt.d.s_2"] = "46000021FG", | ||
429 | ["cvt.w.s_2"] = "46000024FG", | ||
430 | ["cvt.l.s_2"] = "46000025FG", | ||
431 | ["cvt.ps.s_3"] = "46000026FGH", | ||
432 | ["c.f.s_2"] = "46000030GH", | ||
433 | ["c.f.s_3"] = "46000030VGH", | ||
434 | ["c.un.s_2"] = "46000031GH", | ||
435 | ["c.un.s_3"] = "46000031VGH", | ||
436 | ["c.eq.s_2"] = "46000032GH", | ||
437 | ["c.eq.s_3"] = "46000032VGH", | ||
438 | ["c.ueq.s_2"] = "46000033GH", | ||
439 | ["c.ueq.s_3"] = "46000033VGH", | ||
440 | ["c.olt.s_2"] = "46000034GH", | ||
441 | ["c.olt.s_3"] = "46000034VGH", | ||
442 | ["c.ult.s_2"] = "46000035GH", | ||
443 | ["c.ult.s_3"] = "46000035VGH", | ||
444 | ["c.ole.s_2"] = "46000036GH", | ||
445 | ["c.ole.s_3"] = "46000036VGH", | ||
446 | ["c.ule.s_2"] = "46000037GH", | ||
447 | ["c.ule.s_3"] = "46000037VGH", | ||
448 | ["c.sf.s_2"] = "46000038GH", | ||
449 | ["c.sf.s_3"] = "46000038VGH", | ||
450 | ["c.ngle.s_2"] = "46000039GH", | ||
451 | ["c.ngle.s_3"] = "46000039VGH", | ||
452 | ["c.seq.s_2"] = "4600003aGH", | ||
453 | ["c.seq.s_3"] = "4600003aVGH", | ||
454 | ["c.ngl.s_2"] = "4600003bGH", | ||
455 | ["c.ngl.s_3"] = "4600003bVGH", | ||
456 | ["c.lt.s_2"] = "4600003cGH", | ||
457 | ["c.lt.s_3"] = "4600003cVGH", | ||
458 | ["c.nge.s_2"] = "4600003dGH", | ||
459 | ["c.nge.s_3"] = "4600003dVGH", | ||
460 | ["c.le.s_2"] = "4600003eGH", | ||
461 | ["c.le.s_3"] = "4600003eVGH", | ||
462 | ["c.ngt.s_2"] = "4600003fGH", | ||
463 | ["c.ngt.s_3"] = "4600003fVGH", | ||
464 | |||
465 | ["add.d_3"] = "46200000FGH", | ||
466 | ["sub.d_3"] = "46200001FGH", | ||
467 | ["mul.d_3"] = "46200002FGH", | ||
468 | ["div.d_3"] = "46200003FGH", | ||
469 | ["sqrt.d_2"] = "46200004FG", | ||
470 | ["abs.d_2"] = "46200005FG", | ||
471 | ["mov.d_2"] = "46200006FG", | ||
472 | ["neg.d_2"] = "46200007FG", | ||
473 | ["round.l.d_2"] = "46200008FG", | ||
474 | ["trunc.l.d_2"] = "46200009FG", | ||
475 | ["ceil.l.d_2"] = "4620000aFG", | ||
476 | ["floor.l.d_2"] = "4620000bFG", | ||
477 | ["round.w.d_2"] = "4620000cFG", | ||
478 | ["trunc.w.d_2"] = "4620000dFG", | ||
479 | ["ceil.w.d_2"] = "4620000eFG", | ||
480 | ["floor.w.d_2"] = "4620000fFG", | ||
481 | ["movf.d_2"] = "46200011FG", | ||
482 | ["movf.d_3"] = "46200011FGC", | ||
483 | ["movt.d_2"] = "46210011FG", | ||
484 | ["movt.d_3"] = "46210011FGC", | ||
485 | ["movz.d_3"] = "46200012FGT", | ||
486 | ["movn.d_3"] = "46200013FGT", | ||
487 | ["recip.d_2"] = "46200015FG", | ||
488 | ["rsqrt.d_2"] = "46200016FG", | ||
489 | ["cvt.s.d_2"] = "46200020FG", | ||
490 | ["cvt.w.d_2"] = "46200024FG", | ||
491 | ["cvt.l.d_2"] = "46200025FG", | ||
492 | ["c.f.d_2"] = "46200030GH", | ||
493 | ["c.f.d_3"] = "46200030VGH", | ||
494 | ["c.un.d_2"] = "46200031GH", | ||
495 | ["c.un.d_3"] = "46200031VGH", | ||
496 | ["c.eq.d_2"] = "46200032GH", | ||
497 | ["c.eq.d_3"] = "46200032VGH", | ||
498 | ["c.ueq.d_2"] = "46200033GH", | ||
499 | ["c.ueq.d_3"] = "46200033VGH", | ||
500 | ["c.olt.d_2"] = "46200034GH", | ||
501 | ["c.olt.d_3"] = "46200034VGH", | ||
502 | ["c.ult.d_2"] = "46200035GH", | ||
503 | ["c.ult.d_3"] = "46200035VGH", | ||
504 | ["c.ole.d_2"] = "46200036GH", | ||
505 | ["c.ole.d_3"] = "46200036VGH", | ||
506 | ["c.ule.d_2"] = "46200037GH", | ||
507 | ["c.ule.d_3"] = "46200037VGH", | ||
508 | ["c.sf.d_2"] = "46200038GH", | ||
509 | ["c.sf.d_3"] = "46200038VGH", | ||
510 | ["c.ngle.d_2"] = "46200039GH", | ||
511 | ["c.ngle.d_3"] = "46200039VGH", | ||
512 | ["c.seq.d_2"] = "4620003aGH", | ||
513 | ["c.seq.d_3"] = "4620003aVGH", | ||
514 | ["c.ngl.d_2"] = "4620003bGH", | ||
515 | ["c.ngl.d_3"] = "4620003bVGH", | ||
516 | ["c.lt.d_2"] = "4620003cGH", | ||
517 | ["c.lt.d_3"] = "4620003cVGH", | ||
518 | ["c.nge.d_2"] = "4620003dGH", | ||
519 | ["c.nge.d_3"] = "4620003dVGH", | ||
520 | ["c.le.d_2"] = "4620003eGH", | ||
521 | ["c.le.d_3"] = "4620003eVGH", | ||
522 | ["c.ngt.d_2"] = "4620003fGH", | ||
523 | ["c.ngt.d_3"] = "4620003fVGH", | ||
524 | |||
525 | ["add.ps_3"] = "46c00000FGH", | ||
526 | ["sub.ps_3"] = "46c00001FGH", | ||
527 | ["mul.ps_3"] = "46c00002FGH", | ||
528 | ["abs.ps_2"] = "46c00005FG", | ||
529 | ["mov.ps_2"] = "46c00006FG", | ||
530 | ["neg.ps_2"] = "46c00007FG", | ||
531 | ["movf.ps_2"] = "46c00011FG", | ||
532 | ["movf.ps_3"] = "46c00011FGC", | ||
533 | ["movt.ps_2"] = "46c10011FG", | ||
534 | ["movt.ps_3"] = "46c10011FGC", | ||
535 | ["movz.ps_3"] = "46c00012FGT", | ||
536 | ["movn.ps_3"] = "46c00013FGT", | ||
537 | ["cvt.s.pu_2"] = "46c00020FG", | ||
538 | ["cvt.s.pl_2"] = "46c00028FG", | ||
539 | ["pll.ps_3"] = "46c0002cFGH", | ||
540 | ["plu.ps_3"] = "46c0002dFGH", | ||
541 | ["pul.ps_3"] = "46c0002eFGH", | ||
542 | ["puu.ps_3"] = "46c0002fFGH", | ||
543 | ["c.f.ps_2"] = "46c00030GH", | ||
544 | ["c.f.ps_3"] = "46c00030VGH", | ||
545 | ["c.un.ps_2"] = "46c00031GH", | ||
546 | ["c.un.ps_3"] = "46c00031VGH", | ||
547 | ["c.eq.ps_2"] = "46c00032GH", | ||
548 | ["c.eq.ps_3"] = "46c00032VGH", | ||
549 | ["c.ueq.ps_2"] = "46c00033GH", | ||
550 | ["c.ueq.ps_3"] = "46c00033VGH", | ||
551 | ["c.olt.ps_2"] = "46c00034GH", | ||
552 | ["c.olt.ps_3"] = "46c00034VGH", | ||
553 | ["c.ult.ps_2"] = "46c00035GH", | ||
554 | ["c.ult.ps_3"] = "46c00035VGH", | ||
555 | ["c.ole.ps_2"] = "46c00036GH", | ||
556 | ["c.ole.ps_3"] = "46c00036VGH", | ||
557 | ["c.ule.ps_2"] = "46c00037GH", | ||
558 | ["c.ule.ps_3"] = "46c00037VGH", | ||
559 | ["c.sf.ps_2"] = "46c00038GH", | ||
560 | ["c.sf.ps_3"] = "46c00038VGH", | ||
561 | ["c.ngle.ps_2"] = "46c00039GH", | ||
562 | ["c.ngle.ps_3"] = "46c00039VGH", | ||
563 | ["c.seq.ps_2"] = "46c0003aGH", | ||
564 | ["c.seq.ps_3"] = "46c0003aVGH", | ||
565 | ["c.ngl.ps_2"] = "46c0003bGH", | ||
566 | ["c.ngl.ps_3"] = "46c0003bVGH", | ||
567 | ["c.lt.ps_2"] = "46c0003cGH", | ||
568 | ["c.lt.ps_3"] = "46c0003cVGH", | ||
569 | ["c.nge.ps_2"] = "46c0003dGH", | ||
570 | ["c.nge.ps_3"] = "46c0003dVGH", | ||
571 | ["c.le.ps_2"] = "46c0003eGH", | ||
572 | ["c.le.ps_3"] = "46c0003eVGH", | ||
573 | ["c.ngt.ps_2"] = "46c0003fGH", | ||
574 | ["c.ngt.ps_3"] = "46c0003fVGH", | ||
575 | |||
576 | ["cvt.s.w_2"] = "46800020FG", | ||
577 | ["cvt.d.w_2"] = "46800021FG", | ||
578 | |||
579 | ["cvt.s.l_2"] = "46a00020FG", | ||
580 | ["cvt.d.l_2"] = "46a00021FG", | ||
581 | |||
582 | -- Opcode COP1X. | ||
583 | lwxc1_2 = "4c000000FX", | ||
584 | ldxc1_2 = "4c000001FX", | ||
585 | luxc1_2 = "4c000005FX", | ||
586 | swxc1_2 = "4c000008FX", | ||
587 | sdxc1_2 = "4c000009FX", | ||
588 | suxc1_2 = "4c00000dFX", | ||
589 | prefx_2 = "4c00000fMX", | ||
590 | ["alnv.ps_4"] = "4c00001eFGHS", | ||
591 | ["madd.s_4"] = "4c000020FRGH", | ||
592 | ["madd.d_4"] = "4c000021FRGH", | ||
593 | ["madd.ps_4"] = "4c000026FRGH", | ||
594 | ["msub.s_4"] = "4c000028FRGH", | ||
595 | ["msub.d_4"] = "4c000029FRGH", | ||
596 | ["msub.ps_4"] = "4c00002eFRGH", | ||
597 | ["nmadd.s_4"] = "4c000030FRGH", | ||
598 | ["nmadd.d_4"] = "4c000031FRGH", | ||
599 | ["nmadd.ps_4"] = "4c000036FRGH", | ||
600 | ["nmsub.s_4"] = "4c000038FRGH", | ||
601 | ["nmsub.d_4"] = "4c000039FRGH", | ||
602 | ["nmsub.ps_4"] = "4c00003eFRGH", | ||
603 | } | ||
604 | |||
605 | ------------------------------------------------------------------------------ | ||
606 | |||
607 | local function parse_gpr(expr) | ||
608 | local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$") | ||
609 | local tp = map_type[tname or expr] | ||
610 | if tp then | ||
611 | local reg = ovreg or tp.reg | ||
612 | if not reg then | ||
613 | werror("type `"..(tname or expr).."' needs a register override") | ||
614 | end | ||
615 | expr = reg | ||
616 | end | ||
617 | local r = match(expr, "^r([1-3]?[0-9])$") | ||
618 | if r then | ||
619 | r = tonumber(r) | ||
620 | if r <= 31 then return r, tp end | ||
621 | end | ||
622 | werror("bad register name `"..expr.."'") | ||
623 | end | ||
624 | |||
625 | local function parse_fpr(expr) | ||
626 | local r = match(expr, "^f([1-3]?[0-9])$") | ||
627 | if r then | ||
628 | r = tonumber(r) | ||
629 | if r <= 31 then return r end | ||
630 | end | ||
631 | werror("bad register name `"..expr.."'") | ||
632 | end | ||
633 | |||
634 | local function parse_imm(imm, bits, shift, scale, signed) | ||
635 | local n = tonumber(imm) | ||
636 | if n then | ||
637 | if n % 2^scale == 0 then | ||
638 | n = n / 2^scale | ||
639 | if signed then | ||
640 | if n >= 0 then | ||
641 | if n < 2^(bits-1) then return n*2^shift end | ||
642 | else | ||
643 | if n >= -(2^(bits-1))-1 then return (n+2^bits)*2^shift end | ||
644 | end | ||
645 | else | ||
646 | if n >= 0 and n <= 2^bits-1 then return n*2^shift end | ||
647 | end | ||
648 | end | ||
649 | werror("out of range immediate `"..imm.."'") | ||
650 | elseif match(imm, "^[rf]([1-3]?[0-9])$") or | ||
651 | match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then | ||
652 | werror("expected immediate operand, got register") | ||
653 | else | ||
654 | waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) | ||
655 | return 0 | ||
656 | end | ||
657 | end | ||
658 | |||
659 | local function parse_disp(disp) | ||
660 | local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") | ||
661 | if imm then | ||
662 | local r = parse_gpr(reg) | ||
663 | return r*2^21 + parse_imm(imm, 16, 0, 0, true) | ||
664 | end | ||
665 | local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") | ||
666 | if reg and tailr ~= "" then | ||
667 | local r, tp = parse_gpr(reg) | ||
668 | if tp then | ||
669 | waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) | ||
670 | return r*2^21 | ||
671 | end | ||
672 | end | ||
673 | werror("bad displacement `"..disp.."'") | ||
674 | end | ||
675 | |||
676 | local function parse_index(idx) | ||
677 | local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$") | ||
678 | if rt then | ||
679 | rt = parse_gpr(rt) | ||
680 | rs = parse_gpr(rs) | ||
681 | return rt*2^16 + rs*2^21 | ||
682 | end | ||
683 | werror("bad index `"..idx.."'") | ||
684 | end | ||
685 | |||
686 | local function parse_label(label, def) | ||
687 | local prefix = sub(label, 1, 2) | ||
688 | -- =>label (pc label reference) | ||
689 | if prefix == "=>" then | ||
690 | return "PC", 0, sub(label, 3) | ||
691 | end | ||
692 | -- ->name (global label reference) | ||
693 | if prefix == "->" then | ||
694 | return "LG", map_global[sub(label, 3)] | ||
695 | end | ||
696 | if def then | ||
697 | -- [1-9] (local label definition) | ||
698 | if match(label, "^[1-9]$") then | ||
699 | return "LG", 10+tonumber(label) | ||
700 | end | ||
701 | else | ||
702 | -- [<>][1-9] (local label reference) | ||
703 | local dir, lnum = match(label, "^([<>])([1-9])$") | ||
704 | if dir then -- Fwd: 1-9, Bkwd: 11-19. | ||
705 | return "LG", lnum + (dir == ">" and 0 or 10) | ||
706 | end | ||
707 | -- extern label (extern label reference) | ||
708 | local extname = match(label, "^extern%s+(%S+)$") | ||
709 | if extname then | ||
710 | return "EXT", map_extern[extname] | ||
711 | end | ||
712 | end | ||
713 | werror("bad label `"..label.."'") | ||
714 | end | ||
715 | |||
716 | ------------------------------------------------------------------------------ | ||
717 | |||
718 | -- Handle opcodes defined with template strings. | ||
719 | map_op[".template__"] = function(params, template, nparams) | ||
720 | if not params then return sub(template, 9) end | ||
721 | local op = tonumber(sub(template, 1, 8), 16) | ||
722 | local n = 1 | ||
723 | |||
724 | -- Limit number of section buffer positions used by a single dasm_put(). | ||
725 | -- A single opcode needs a maximum of 2 positions (ins/ext). | ||
726 | if secpos+2 > maxsecpos then wflush() end | ||
727 | local pos = wpos() | ||
728 | |||
729 | -- Process each character. | ||
730 | for p in gmatch(sub(template, 9), ".") do | ||
731 | if p == "D" then | ||
732 | op = op + parse_gpr(params[n]) * 2^11; n = n + 1 | ||
733 | elseif p == "T" then | ||
734 | op = op + parse_gpr(params[n]) * 2^16; n = n + 1 | ||
735 | elseif p == "S" then | ||
736 | op = op + parse_gpr(params[n]) * 2^21; n = n + 1 | ||
737 | elseif p == "F" then | ||
738 | op = op + parse_fpr(params[n]) * 2^6; n = n + 1 | ||
739 | elseif p == "G" then | ||
740 | op = op + parse_fpr(params[n]) * 2^11; n = n + 1 | ||
741 | elseif p == "H" then | ||
742 | op = op + parse_fpr(params[n]) * 2^16; n = n + 1 | ||
743 | elseif p == "R" then | ||
744 | op = op + parse_fpr(params[n]) * 2^21; n = n + 1 | ||
745 | elseif p == "I" then | ||
746 | op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 | ||
747 | elseif p == "U" then | ||
748 | op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 | ||
749 | elseif p == "O" then | ||
750 | op = op + parse_disp(params[n]); n = n + 1 | ||
751 | elseif p == "X" then | ||
752 | op = op + parse_index(params[n]); n = n + 1 | ||
753 | elseif p == "B" or p == "J" then | ||
754 | local mode, n, s = parse_label(params[n], false) | ||
755 | if p == "B" then n = n + 2048 end | ||
756 | waction("REL_"..mode, n, s, 1) | ||
757 | n = n + 1 | ||
758 | elseif p == "A" then | ||
759 | op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1 | ||
760 | elseif p == "M" then | ||
761 | op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1 | ||
762 | elseif p == "N" then | ||
763 | op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1 | ||
764 | elseif p == "C" then | ||
765 | op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1 | ||
766 | elseif p == "V" then | ||
767 | op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1 | ||
768 | elseif p == "W" then | ||
769 | op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1 | ||
770 | elseif p == "Y" then | ||
771 | op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1 | ||
772 | elseif p == "Z" then | ||
773 | op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1 | ||
774 | elseif p == "=" then | ||
775 | local d = ((op - op % 2^11) / 2^11) % 32 | ||
776 | op = op + d * 2^16 -- Copy D to T for clz, clo. | ||
777 | else | ||
778 | assert(false) | ||
779 | end | ||
780 | end | ||
781 | wputpos(pos, op) | ||
782 | end | ||
783 | |||
784 | ------------------------------------------------------------------------------ | ||
785 | |||
786 | -- Pseudo-opcode to mark the position where the action list is to be emitted. | ||
787 | map_op[".actionlist_1"] = function(params) | ||
788 | if not params then return "cvar" end | ||
789 | local name = params[1] -- No syntax check. You get to keep the pieces. | ||
790 | wline(function(out) writeactions(out, name) end) | ||
791 | end | ||
792 | |||
793 | -- Pseudo-opcode to mark the position where the global enum is to be emitted. | ||
794 | map_op[".globals_1"] = function(params) | ||
795 | if not params then return "prefix" end | ||
796 | local prefix = params[1] -- No syntax check. You get to keep the pieces. | ||
797 | wline(function(out) writeglobals(out, prefix) end) | ||
798 | end | ||
799 | |||
800 | -- Pseudo-opcode to mark the position where the global names are to be emitted. | ||
801 | map_op[".globalnames_1"] = function(params) | ||
802 | if not params then return "cvar" end | ||
803 | local name = params[1] -- No syntax check. You get to keep the pieces. | ||
804 | wline(function(out) writeglobalnames(out, name) end) | ||
805 | end | ||
806 | |||
807 | -- Pseudo-opcode to mark the position where the extern names are to be emitted. | ||
808 | map_op[".externnames_1"] = function(params) | ||
809 | if not params then return "cvar" end | ||
810 | local name = params[1] -- No syntax check. You get to keep the pieces. | ||
811 | wline(function(out) writeexternnames(out, name) end) | ||
812 | end | ||
813 | |||
814 | ------------------------------------------------------------------------------ | ||
815 | |||
816 | -- Label pseudo-opcode (converted from trailing colon form). | ||
817 | map_op[".label_1"] = function(params) | ||
818 | if not params then return "[1-9] | ->global | =>pcexpr" end | ||
819 | if secpos+1 > maxsecpos then wflush() end | ||
820 | local mode, n, s = parse_label(params[1], true) | ||
821 | if mode == "EXT" then werror("bad label definition") end | ||
822 | waction("LABEL_"..mode, n, s, 1) | ||
823 | end | ||
824 | |||
825 | ------------------------------------------------------------------------------ | ||
826 | |||
827 | -- Pseudo-opcodes for data storage. | ||
828 | map_op[".long_*"] = function(params) | ||
829 | if not params then return "imm..." end | ||
830 | for _,p in ipairs(params) do | ||
831 | local n = tonumber(p) | ||
832 | if not n then werror("bad immediate `"..p.."'") end | ||
833 | if n < 0 then n = n + 2^32 end | ||
834 | wputw(n) | ||
835 | if secpos+2 > maxsecpos then wflush() end | ||
836 | end | ||
837 | end | ||
838 | |||
839 | -- Alignment pseudo-opcode. | ||
840 | map_op[".align_1"] = function(params) | ||
841 | if not params then return "numpow2" end | ||
842 | if secpos+1 > maxsecpos then wflush() end | ||
843 | local align = tonumber(params[1]) | ||
844 | if align then | ||
845 | local x = align | ||
846 | -- Must be a power of 2 in the range (2 ... 256). | ||
847 | for i=1,8 do | ||
848 | x = x / 2 | ||
849 | if x == 1 then | ||
850 | waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. | ||
851 | return | ||
852 | end | ||
853 | end | ||
854 | end | ||
855 | werror("bad alignment") | ||
856 | end | ||
857 | |||
858 | ------------------------------------------------------------------------------ | ||
859 | |||
860 | -- Pseudo-opcode for (primitive) type definitions (map to C types). | ||
861 | map_op[".type_3"] = function(params, nparams) | ||
862 | if not params then | ||
863 | return nparams == 2 and "name, ctype" or "name, ctype, reg" | ||
864 | end | ||
865 | local name, ctype, reg = params[1], params[2], params[3] | ||
866 | if not match(name, "^[%a_][%w_]*$") then | ||
867 | werror("bad type name `"..name.."'") | ||
868 | end | ||
869 | local tp = map_type[name] | ||
870 | if tp then | ||
871 | werror("duplicate type `"..name.."'") | ||
872 | end | ||
873 | -- Add #type to defines. A bit unclean to put it in map_archdef. | ||
874 | map_archdef["#"..name] = "sizeof("..ctype..")" | ||
875 | -- Add new type and emit shortcut define. | ||
876 | local num = ctypenum + 1 | ||
877 | map_type[name] = { | ||
878 | ctype = ctype, | ||
879 | ctypefmt = format("Dt%X(%%s)", num), | ||
880 | reg = reg, | ||
881 | } | ||
882 | wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) | ||
883 | ctypenum = num | ||
884 | end | ||
885 | map_op[".type_2"] = map_op[".type_3"] | ||
886 | |||
887 | -- Dump type definitions. | ||
888 | local function dumptypes(out, lvl) | ||
889 | local t = {} | ||
890 | for name in pairs(map_type) do t[#t+1] = name end | ||
891 | sort(t) | ||
892 | out:write("Type definitions:\n") | ||
893 | for _,name in ipairs(t) do | ||
894 | local tp = map_type[name] | ||
895 | local reg = tp.reg or "" | ||
896 | out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) | ||
897 | end | ||
898 | out:write("\n") | ||
899 | end | ||
900 | |||
901 | ------------------------------------------------------------------------------ | ||
902 | |||
903 | -- Set the current section. | ||
904 | function _M.section(num) | ||
905 | waction("SECTION", num) | ||
906 | wflush(true) -- SECTION is a terminal action. | ||
907 | end | ||
908 | |||
909 | ------------------------------------------------------------------------------ | ||
910 | |||
911 | -- Dump architecture description. | ||
912 | function _M.dumparch(out) | ||
913 | out:write(format("DynASM %s version %s, released %s\n\n", | ||
914 | _info.arch, _info.version, _info.release)) | ||
915 | dumpactions(out) | ||
916 | end | ||
917 | |||
918 | -- Dump all user defined elements. | ||
919 | function _M.dumpdef(out, lvl) | ||
920 | dumptypes(out, lvl) | ||
921 | dumpglobals(out, lvl) | ||
922 | dumpexterns(out, lvl) | ||
923 | end | ||
924 | |||
925 | ------------------------------------------------------------------------------ | ||
926 | |||
927 | -- Pass callbacks from/to the DynASM core. | ||
928 | function _M.passcb(wl, we, wf, ww) | ||
929 | wline, werror, wfatal, wwarn = wl, we, wf, ww | ||
930 | return wflush | ||
931 | end | ||
932 | |||
933 | -- Setup the arch-specific module. | ||
934 | function _M.setup(arch, opt) | ||
935 | g_arch, g_opt = arch, opt | ||
936 | end | ||
937 | |||
938 | -- Merge the core maps and the arch-specific maps. | ||
939 | function _M.mergemaps(map_coreop, map_def) | ||
940 | setmetatable(map_op, { __index = map_coreop }) | ||
941 | setmetatable(map_def, { __index = map_archdef }) | ||
942 | return map_op, map_def | ||
943 | end | ||
944 | |||
945 | return _M | ||
946 | |||
947 | ------------------------------------------------------------------------------ | ||
948 | |||