aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pall <mike>2011-03-23 01:25:14 +0100
committerMike Pall <mike>2011-03-23 01:25:14 +0100
commit156bf1578363c58f4bb1f1be9ba7e9758c94dd75 (patch)
treec76f16737795f8ef2c4308d96185c80ffb44b375
parent7088abce8f811f68d3375771ba04f24b82e4a72a (diff)
downloadluajit-156bf1578363c58f4bb1f1be9ba7e9758c94dd75.tar.gz
luajit-156bf1578363c58f4bb1f1be9ba7e9758c94dd75.tar.bz2
luajit-156bf1578363c58f4bb1f1be9ba7e9758c94dd75.zip
ARM: Add DynASM ARM module and encoding engine.
-rw-r--r--dynasm/dasm_arm.h440
-rw-r--r--dynasm/dasm_arm.lua933
-rw-r--r--dynasm/dynasm.lua10
3 files changed, 1379 insertions, 4 deletions
diff --git a/dynasm/dasm_arm.h b/dynasm/dasm_arm.h
new file mode 100644
index 00000000..3fd795b7
--- /dev/null
+++ b/dynasm/dasm_arm.h
@@ -0,0 +1,440 @@
1/*
2** DynASM ARM encoding engine.
3** Copyright (C) 2005-2011 Mike Pall. All rights reserved.
4** Released under the MIT/X 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 "arm"
13
14#ifndef DASM_EXTERN
15#define DASM_EXTERN(a,b,c,d) 0
16#endif
17
18/* Action definitions. */
19enum {
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,
25 DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12,
26 DASM__MAX
27};
28
29/* Maximum number of section buffer positions for a single dasm_put() call. */
30#define DASM_MAXSECPOS 25
31
32/* DynASM encoder status codes. Action list offset or number are or'ed in. */
33#define DASM_S_OK 0x00000000
34#define DASM_S_NOMEM 0x01000000
35#define DASM_S_PHASE 0x02000000
36#define DASM_S_MATCH_SEC 0x03000000
37#define DASM_S_RANGE_I 0x11000000
38#define DASM_S_RANGE_SEC 0x12000000
39#define DASM_S_RANGE_LG 0x13000000
40#define DASM_S_RANGE_PC 0x14000000
41#define DASM_S_RANGE_REL 0x15000000
42#define DASM_S_UNDEF_LG 0x21000000
43#define DASM_S_UNDEF_PC 0x22000000
44
45/* Macros to convert positions (8 bit section + 24 bit index). */
46#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
47#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
48#define DASM_SEC2POS(sec) ((sec)<<24)
49#define DASM_POS2SEC(pos) ((pos)>>24)
50#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
51
52/* Action list type. */
53typedef const unsigned int *dasm_ActList;
54
55/* Per-section structure. */
56typedef struct dasm_Section {
57 int *rbuf; /* Biased buffer pointer (negative section bias). */
58 int *buf; /* True buffer pointer. */
59 size_t bsize; /* Buffer size in bytes. */
60 int pos; /* Biased buffer position. */
61 int epos; /* End of biased buffer position - max single put. */
62 int ofs; /* Byte offset into section. */
63} dasm_Section;
64
65/* Core structure holding the DynASM encoding state. */
66struct dasm_State {
67 size_t psize; /* Allocated size of this structure. */
68 dasm_ActList actionlist; /* Current actionlist pointer. */
69 int *lglabels; /* Local/global chain/pos ptrs. */
70 size_t lgsize;
71 int *pclabels; /* PC label chains/pos ptrs. */
72 size_t pcsize;
73 void **globals; /* Array of globals (bias -10). */
74 dasm_Section *section; /* Pointer to active section. */
75 size_t codesize; /* Total size of all code sections. */
76 int maxsection; /* 0 <= sectionidx < maxsection. */
77 int status; /* Status code. */
78 dasm_Section sections[1]; /* All sections. Alloc-extended. */
79};
80
81/* The size of the core structure depends on the max. number of sections. */
82#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
83
84
85/* Initialize DynASM state. */
86void dasm_init(Dst_DECL, int maxsection)
87{
88 dasm_State *D;
89 size_t psz = 0;
90 int i;
91 Dst_REF = NULL;
92 DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
93 D = Dst_REF;
94 D->psize = psz;
95 D->lglabels = NULL;
96 D->lgsize = 0;
97 D->pclabels = NULL;
98 D->pcsize = 0;
99 D->globals = NULL;
100 D->maxsection = maxsection;
101 for (i = 0; i < maxsection; i++) {
102 D->sections[i].buf = NULL; /* Need this for pass3. */
103 D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
104 D->sections[i].bsize = 0;
105 D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
106 }
107}
108
109/* Free DynASM state. */
110void dasm_free(Dst_DECL)
111{
112 dasm_State *D = Dst_REF;
113 int i;
114 for (i = 0; i < D->maxsection; i++)
115 if (D->sections[i].buf)
116 DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
117 if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
118 if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
119 DASM_M_FREE(Dst, D, D->psize);
120}
121
122/* Setup global label array. Must be called before dasm_setup(). */
123void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
124{
125 dasm_State *D = Dst_REF;
126 D->globals = gl - 10; /* Negative bias to compensate for locals. */
127 DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
128}
129
130/* Grow PC label array. Can be called after dasm_setup(), too. */
131void dasm_growpc(Dst_DECL, unsigned int maxpc)
132{
133 dasm_State *D = Dst_REF;
134 size_t osz = D->pcsize;
135 DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
136 memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
137}
138
139/* Setup encoder. */
140void dasm_setup(Dst_DECL, const void *actionlist)
141{
142 dasm_State *D = Dst_REF;
143 int i;
144 D->actionlist = (dasm_ActList)actionlist;
145 D->status = DASM_S_OK;
146 D->section = &D->sections[0];
147 memset((void *)D->lglabels, 0, D->lgsize);
148 if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
149 for (i = 0; i < D->maxsection; i++) {
150 D->sections[i].pos = DASM_SEC2POS(i);
151 D->sections[i].ofs = 0;
152 }
153}
154
155
156#ifdef DASM_CHECKS
157#define CK(x, st) \
158 do { if (!(x)) { \
159 D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
160#define CKPL(kind, st) \
161 do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
162 D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
163#else
164#define CK(x, st) ((void)0)
165#define CKPL(kind, st) ((void)0)
166#endif
167
168static int dasm_imm12(unsigned int n)
169{
170 int i;
171 for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30))
172 if (n <= 255) return (int)(n + (i << 8));
173 return -1;
174}
175
176/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
177void dasm_put(Dst_DECL, int start, ...)
178{
179 va_list ap;
180 dasm_State *D = Dst_REF;
181 dasm_ActList p = D->actionlist + start;
182 dasm_Section *sec = D->section;
183 int pos = sec->pos, ofs = sec->ofs;
184 int *b;
185
186 if (pos >= sec->epos) {
187 DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
188 sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
189 sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
190 sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
191 }
192
193 b = sec->rbuf;
194 b[pos++] = start;
195
196 va_start(ap, start);
197 while (1) {
198 unsigned int ins = *p++;
199 unsigned int action = (ins >> 16);
200 if (action >= DASM__MAX) {
201 ofs += 4;
202 } else {
203 int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
204 switch (action) {
205 case DASM_STOP: goto stop;
206 case DASM_SECTION:
207 n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
208 D->section = &D->sections[n]; goto stop;
209 case DASM_ESC: p++; ofs += 4; break;
210 case DASM_REL_EXT: break;
211 case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
212 case DASM_REL_LG:
213 n = (ins & 2047) - 10; pl = D->lglabels + n;
214 if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */
215 pl += 10; n = *pl;
216 if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
217 goto linkrel;
218 case DASM_REL_PC:
219 pl = D->pclabels + n; CKPL(pc, PC);
220 putrel:
221 n = *pl;
222 if (n < 0) { /* Label exists. Get label pos and store it. */
223 b[pos] = -n;
224 } else {
225 linkrel:
226 b[pos] = n; /* Else link to rel chain, anchored at label. */
227 *pl = pos;
228 }
229 pos++;
230 break;
231 case DASM_LABEL_LG:
232 pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
233 case DASM_LABEL_PC:
234 pl = D->pclabels + n; CKPL(pc, PC);
235 putlabel:
236 n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
237 while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
238 }
239 *pl = -pos; /* Label exists now. */
240 b[pos++] = ofs; /* Store pass1 offset estimate. */
241 break;
242 case DASM_IMM:
243 case DASM_IMM16:
244#ifdef DASM_CHECKS
245 CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
246 if ((ins & 0x8000))
247 CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
248 else
249 CK((n>>((ins>>5)&31)) == 0, RANGE_I);
250#endif
251 b[pos++] = n;
252 break;
253 case DASM_IMML8:
254 case DASM_IMML12:
255 CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) :
256 (((-n)>>((ins>>5)&31)) == 0), RANGE_I);
257 b[pos++] = n;
258 break;
259 case DASM_IMM12:
260 CK(dasm_imm12((unsigned int)n) != -1, RANGE_I);
261 b[pos++] = n;
262 break;
263 }
264 }
265 }
266stop:
267 va_end(ap);
268 sec->pos = pos;
269 sec->ofs = ofs;
270}
271#undef CK
272
273/* Pass 2: Link sections, shrink aligns, fix label offsets. */
274int dasm_link(Dst_DECL, size_t *szp)
275{
276 dasm_State *D = Dst_REF;
277 int secnum;
278 int ofs = 0;
279
280#ifdef DASM_CHECKS
281 *szp = 0;
282 if (D->status != DASM_S_OK) return D->status;
283 {
284 int pc;
285 for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
286 if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
287 }
288#endif
289
290 { /* Handle globals not defined in this translation unit. */
291 int idx;
292 for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
293 int n = D->lglabels[idx];
294 /* Undefined label: Collapse rel chain and replace with marker (< 0). */
295 while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
296 }
297 }
298
299 /* Combine all code sections. No support for data sections (yet). */
300 for (secnum = 0; secnum < D->maxsection; secnum++) {
301 dasm_Section *sec = D->sections + secnum;
302 int *b = sec->rbuf;
303 int pos = DASM_SEC2POS(secnum);
304 int lastpos = sec->pos;
305
306 while (pos != lastpos) {
307 dasm_ActList p = D->actionlist + b[pos++];
308 while (1) {
309 unsigned int ins = *p++;
310 unsigned int action = (ins >> 16);
311 switch (action) {
312 case DASM_STOP: case DASM_SECTION: goto stop;
313 case DASM_ESC: p++; break;
314 case DASM_REL_EXT: break;
315 case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
316 case DASM_REL_LG: case DASM_REL_PC: pos++; break;
317 case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
318 case DASM_IMM: case DASM_IMM12: case DASM_IMM16:
319 case DASM_IMML8: case DASM_IMML12: pos++; break;
320 }
321 }
322 stop: (void)0;
323 }
324 ofs += sec->ofs; /* Next section starts right after current section. */
325 }
326
327 D->codesize = ofs; /* Total size of all code sections */
328 *szp = ofs;
329 return DASM_S_OK;
330}
331
332#ifdef DASM_CHECKS
333#define CK(x, st) \
334 do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
335#else
336#define CK(x, st) ((void)0)
337#endif
338
339/* Pass 3: Encode sections. */
340int dasm_encode(Dst_DECL, void *buffer)
341{
342 dasm_State *D = Dst_REF;
343 char *base = (char *)buffer;
344 unsigned int *cp = (unsigned int *)buffer;
345 int secnum;
346
347 /* Encode all code sections. No support for data sections (yet). */
348 for (secnum = 0; secnum < D->maxsection; secnum++) {
349 dasm_Section *sec = D->sections + secnum;
350 int *b = sec->buf;
351 int *endb = sec->rbuf + sec->pos;
352
353 while (b != endb) {
354 dasm_ActList p = D->actionlist + *b++;
355 while (1) {
356 unsigned int ins = *p++;
357 unsigned int action = (ins >> 16);
358 int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
359 switch (action) {
360 case DASM_STOP: case DASM_SECTION: goto stop;
361 case DASM_ESC: *cp++ = *p++; break;
362 case DASM_REL_EXT:
363 n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1);
364 goto patchrel;
365 case DASM_ALIGN:
366 ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000;
367 break;
368 case DASM_REL_LG:
369 CK(n >= 0, UNDEF_LG);
370 case DASM_REL_PC:
371 CK(n >= 0, UNDEF_PC);
372 n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base);
373 patchrel:
374 CK((n & 3) == 0 && ((n-4+0x02000000) >> 26) == 0, RANGE_REL);
375 cp[-1] |= (((n-4) >> 2) & 0x00ffffff);
376 break;
377 case DASM_LABEL_LG:
378 ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
379 break;
380 case DASM_LABEL_PC: break;
381 case DASM_IMM:
382 cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31);
383 break;
384 case DASM_IMM12:
385 cp[-1] |= dasm_imm12((unsigned int)n);
386 break;
387 case DASM_IMM16:
388 cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff);
389 break;
390 case DASM_IMML8:
391 cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) :
392 ((-n & 0x0f) | ((-n & 0xf0) << 4));
393 break;
394 case DASM_IMML12:
395 cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n);
396 break;
397 default: *cp++ = ins; break;
398 }
399 }
400 stop: (void)0;
401 }
402 }
403
404 if (base + D->codesize != (char *)cp) /* Check for phase errors. */
405 return DASM_S_PHASE;
406 return DASM_S_OK;
407}
408#undef CK
409
410/* Get PC label offset. */
411int dasm_getpclabel(Dst_DECL, unsigned int pc)
412{
413 dasm_State *D = Dst_REF;
414 if (pc*sizeof(int) < D->pcsize) {
415 int pos = D->pclabels[pc];
416 if (pos < 0) return *DASM_POS2PTR(D, -pos);
417 if (pos > 0) return -1; /* Undefined. */
418 }
419 return -2; /* Unused or out of range. */
420}
421
422#ifdef DASM_CHECKS
423/* Optional sanity checker to call between isolated encoding steps. */
424int dasm_checkstep(Dst_DECL, int secmatch)
425{
426 dasm_State *D = Dst_REF;
427 if (D->status == DASM_S_OK) {
428 int i;
429 for (i = 1; i <= 9; i++) {
430 if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
431 D->lglabels[i] = 0;
432 }
433 }
434 if (D->status == DASM_S_OK && secmatch >= 0 &&
435 D->section != &D->sections[secmatch])
436 D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
437 return D->status;
438}
439#endif
440
diff --git a/dynasm/dasm_arm.lua b/dynasm/dasm_arm.lua
new file mode 100644
index 00000000..37ba7fab
--- /dev/null
+++ b/dynasm/dasm_arm.lua
@@ -0,0 +1,933 @@
1------------------------------------------------------------------------------
2-- DynASM ARM 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:
9local _info = {
10 arch = "arm",
11 description = "DynASM ARM module",
12 version = "1.2.2",
13 vernum = 10202,
14 release = "2011-03-23",
15 author = "Mike Pall",
16 license = "MIT",
17}
18
19-- Exported glue functions for the arch-specific module.
20local _M = { _info = _info }
21
22-- Cache library functions.
23local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
24local assert, setmetatable, rawget = assert, setmetatable, rawget
25local _s = string
26local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
27local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub
28local concat, sort = table.concat, table.sort
29
30-- Inherited tables and callbacks.
31local g_opt, g_arch
32local wline, werror, wfatal, wwarn
33
34-- Action name list.
35-- CHECK: Keep this in sync with the C code!
36local action_names = {
37 "STOP", "SECTION", "ESC", "REL_EXT",
38 "ALIGN", "REL_LG", "LABEL_LG",
39 "REL_PC", "LABEL_PC", "IMM", "IMM12", "IMM16", "IMML8", "IMML12",
40}
41
42-- Maximum number of section buffer positions for dasm_put().
43-- CHECK: Keep this in sync with the C code!
44local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
45
46-- Action name -> action number.
47local map_action = {}
48for n,name in ipairs(action_names) do
49 map_action[name] = n-1
50end
51
52-- Action list buffer.
53local actlist = {}
54
55-- Argument list for next dasm_put(). Start with offset 0 into action list.
56local actargs = { 0 }
57
58-- Current number of section buffer positions for dasm_put().
59local secpos = 1
60
61------------------------------------------------------------------------------
62
63-- Return 8 digit hex number.
64local function tohex(x)
65 return sub(format("%08x", x), -8) -- Avoid 64 bit portability problem in Lua.
66end
67
68-- Dump action names and numbers.
69local 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")
76end
77
78-- Write action list buffer as a huge static C array.
79local 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"))
87end
88
89------------------------------------------------------------------------------
90
91-- Add word to action list.
92local function wputxw(n)
93 assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
94 actlist[#actlist+1] = n
95end
96
97-- Add action to list with optional arg. Advance buffer pos, too.
98local function waction(action, val, a, num)
99 local w = assert(map_action[action], "bad action name `"..action.."'")
100 wputxw(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
103end
104
105-- Flush action list (intervening C code or buffer pos overflow).
106local 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.
112end
113
114-- Put escaped word.
115local function wputw(n)
116 if n <= 0x000fffff then waction("ESC") end
117 wputxw(n)
118end
119
120-- Reserve position for word.
121local function wpos()
122 local pos = #actlist+1
123 actlist[pos] = ""
124 return pos
125end
126
127-- Store word to reserved position.
128local function wputpos(pos, n)
129 assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
130 actlist[pos] = n
131end
132
133------------------------------------------------------------------------------
134
135-- Global label name -> global label number. With auto assignment on 1st use.
136local next_global = 20
137local 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
144end})
145
146-- Dump global labels.
147local 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")
155end
156
157-- Write global label enum.
158local 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")
166end
167
168-- Write global label names.
169local 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")
177end
178
179------------------------------------------------------------------------------
180
181-- Extern label name -> extern label number. With auto assignment on 1st use.
182local next_extern = 0
183local map_extern_ = {}
184local 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
192end})
193
194-- Dump extern labels.
195local 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")
201end
202
203-- Write extern label names.
204local 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")
210end
211
212------------------------------------------------------------------------------
213
214-- Arch-specific maps.
215
216-- Ext. register name -> int. name.
217local map_archdef = { sp = "r13", lr = "r14", pc = "r15", }
218
219-- Int. register name -> ext. name.
220local map_reg_rev = { r13 = "sp", r14 = "lr", r15 = "pc", }
221
222local map_type = {} -- Type name -> { ctype, reg }
223local ctypenum = 0 -- Type number (for Dt... macros).
224
225-- Reverse defines for registers.
226function _M.revdef(s)
227 return map_reg_rev[s] or s
228end
229
230local map_shift = { lsl = 0, lsr = 1, asr = 2, ror = 3, }
231
232local map_cond = {
233 eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7,
234 hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14,
235 hs = 2, lo = 3,
236}
237
238------------------------------------------------------------------------------
239
240-- Template strings for ARM instructions.
241local map_op = {
242 -- Basic data processing instructions.
243 and_3 = "e0000000DNPs",
244 eor_3 = "e0200000DNPs",
245 sub_3 = "e0400000DNPs",
246 rsb_3 = "e0600000DNPs",
247 add_3 = "e0800000DNPs",
248 adc_3 = "e0a00000DNPs",
249 sbc_3 = "e0c00000DNPs",
250 rsc_3 = "e0e00000DNPs",
251 tst_2 = "e1100000NP",
252 teq_2 = "e1300000NP",
253 cmp_2 = "e1500000NP",
254 cmn_2 = "e1700000NP",
255 orr_3 = "e1800000DNPs",
256 mov_2 = "e1a00000DPs",
257 bic_3 = "e1c00000DNPs",
258 mvn_2 = "e1e00000DPs",
259
260 and_4 = "e0000000DNMps",
261 eor_4 = "e0200000DNMps",
262 sub_4 = "e0400000DNMps",
263 rsb_4 = "e0600000DNMps",
264 add_4 = "e0800000DNMps",
265 adc_4 = "e0a00000DNMps",
266 sbc_4 = "e0c00000DNMps",
267 rsc_4 = "e0e00000DNMps",
268 tst_3 = "e1100000NMp",
269 teq_3 = "e1300000NMp",
270 cmp_3 = "e1500000NMp",
271 cmn_3 = "e1700000NMp",
272 orr_4 = "e1800000DNMps",
273 mov_3 = "e1a00000DMps",
274 bic_4 = "e1c00000DNMps",
275 mvn_3 = "e1e00000DMps",
276
277 lsl_3 = "e1a00000DMvs",
278 lsr_3 = "e1a00020DMvs",
279 asr_3 = "e1a00040DMvs",
280 ror_3 = "e1a00060DMvs",
281 rrx_2 = "e1a00060DMs",
282
283 -- Multiply and multiply-accumulate.
284 mul_3 = "e0000090NMSs",
285 mla_4 = "e0200090NMSDs",
286 umaal_4 = "e0400090DNMSs", -- v6
287 mls_4 = "e0600090DNMSs", -- v6T2
288 umull_4 = "e0800090DNMSs",
289 umlal_4 = "e0a00090DNMSs",
290 smull_4 = "e0c00090DNMSs",
291 smlal_4 = "e0e00090DNMSs",
292
293 -- Halfword multiply and multiply-accumulate.
294 smlabb_4 = "e1000080NMSD", -- v5TE
295 smlatb_4 = "e10000a0NMSD", -- v5TE
296 smlabt_4 = "e10000c0NMSD", -- v5TE
297 smlatt_4 = "e10000e0NMSD", -- v5TE
298 smlawb_4 = "e1200080NMSD", -- v5TE
299 smulwb_3 = "e12000a0NMS", -- v5TE
300 smlawt_4 = "e12000c0NMSD", -- v5TE
301 smulwt_3 = "e12000e0NMS", -- v5TE
302 smlalbb_4 = "e1400080NMSD", -- v5TE
303 smlaltb_4 = "e14000a0NMSD", -- v5TE
304 smlalbt_4 = "e14000c0NMSD", -- v5TE
305 smlaltt_4 = "e14000e0NMSD", -- v5TE
306 smulbb_3 = "e1600080NMS", -- v5TE
307 smultb_3 = "e16000a0NMS", -- v5TE
308 smulbt_3 = "e16000c0NMS", -- v5TE
309 smultt_3 = "e16000e0NMS", -- v5TE
310
311 -- Miscellaneous data processing instructions.
312 clz_2 = "e16f0f10DM", -- v5T
313 rev_2 = "e6bf0f30DM", -- v6
314 rev16_2 = "e6bf0fb0DM", -- v6
315 revsh_2 = "e6ff0fb0DM", -- v6
316 sel_3 = "e6800fb0DNM", -- v6
317 usad8_3 = "e780f010NMS", -- v6
318 usada8_4 = "e7800010NMSD", -- v6
319 rbit_2 = "e6ff0f30DM", -- v6T2
320 movw_2 = "e3000000DW", -- v6T2
321 movt_2 = "e3400000DW", -- v6T2
322 -- Note: the X encodes width-1, not width.
323 sbfx_4 = "e7a00050DMvX", -- v6T2
324 ubfx_4 = "e7e00050DMvX", -- v6T2
325 -- Note: the X encodes the msb field, not the width.
326 bfc_3 = "e7c0001fDvX", -- v6T2
327 bfi_4 = "e7c00010DMvX", -- v6T2
328
329 -- Packing and unpacking instructions.
330 pkhbt_3 = "e6800010DNM", pkhbt_4 = "e6800010DNMv", -- v6
331 pkhtb_3 = "e6800050DNM", pkhtb_4 = "e6800050DNMv", -- v6
332 sxtab_3 = "e6a00070DNM", sxtab_4 = "e6a00070DNMv", -- v6
333 sxtab16_3 = "e6800070DNM", sxtab16_4 = "e6800070DNMv", -- v6
334 sxtah_3 = "e6b00070DNM", sxtah_4 = "e6b00070DNMv", -- v6
335 sxtb_2 = "e6af0070DM", sxtb_3 = "e6af0070DMv", -- v6
336 sxtb16_2 = "e68f0070DM", sxtb16_3 = "e68f0070DMv", -- v6
337 sxth_2 = "e6bf0070DM", sxth_3 = "e6bf0070DMv", -- v6
338 uxtab_3 = "e6e00070DNM", uxtab_4 = "e6e00070DNMv", -- v6
339 uxtab16_3 = "e6c00070DNM", uxtab16_4 = "e6c00070DNMv", -- v6
340 uxtah_3 = "e6f00070DNM", uxtah_4 = "e6f00070DNMv", -- v6
341 uxtb_2 = "e6ef0070DM", uxtb_3 = "e6ef0070DMv", -- v6
342 uxtb16_2 = "e6cf0070DM", uxtb16_3 = "e6cf0070DMv", -- v6
343 uxth_2 = "e6ff0070DM", uxth_3 = "e6ff0070DMv", -- v6
344
345 -- Saturating instructions.
346 qadd_3 = "e1000050DMN", -- v5TE
347 qsub_3 = "e1200050DMN", -- v5TE
348 qdadd_3 = "e1400050DMN", -- v5TE
349 qdsub_3 = "e1600050DMN", -- v5TE
350 -- Note: the X for ssat* encodes sat_imm-1, not sat_imm.
351 ssat_3 = "e6a00010DXM", ssat_4 = "e6a00010DXMp", -- v6
352 usat_3 = "e6e00010DXM", usat_4 = "e6e00010DXMp", -- v6
353 ssat16_3 = "e6a00f30DXM", -- v6
354 usat16_3 = "e6e00f30DXM", -- v6
355
356 -- Parallel addition and subtraction.
357 sadd16_3 = "e6100f10DNM", -- v6
358 sasx_3 = "e6100f30DNM", -- v6
359 ssax_3 = "e6100f50DNM", -- v6
360 ssub16_3 = "e6100f70DNM", -- v6
361 sadd8_3 = "e6100f90DNM", -- v6
362 ssub8_3 = "e6100ff0DNM", -- v6
363 qadd16_3 = "e6200f10DNM", -- v6
364 qasx_3 = "e6200f30DNM", -- v6
365 qsax_3 = "e6200f50DNM", -- v6
366 qsub16_3 = "e6200f70DNM", -- v6
367 qadd8_3 = "e6200f90DNM", -- v6
368 qsub8_3 = "e6200ff0DNM", -- v6
369 shadd16_3 = "e6300f10DNM", -- v6
370 shasx_3 = "e6300f30DNM", -- v6
371 shsax_3 = "e6300f50DNM", -- v6
372 shsub16_3 = "e6300f70DNM", -- v6
373 shadd8_3 = "e6300f90DNM", -- v6
374 shsub8_3 = "e6300ff0DNM", -- v6
375 uadd16_3 = "e6500f10DNM", -- v6
376 uasx_3 = "e6500f30DNM", -- v6
377 usax_3 = "e6500f50DNM", -- v6
378 usub16_3 = "e6500f70DNM", -- v6
379 uadd8_3 = "e6500f90DNM", -- v6
380 usub8_3 = "e6500ff0DNM", -- v6
381 uqadd16_3 = "e6600f10DNM", -- v6
382 uqasx_3 = "e6600f30DNM", -- v6
383 uqsax_3 = "e6600f50DNM", -- v6
384 uqsub16_3 = "e6600f70DNM", -- v6
385 uqadd8_3 = "e6600f90DNM", -- v6
386 uqsub8_3 = "e6600ff0DNM", -- v6
387 uhadd16_3 = "e6700f10DNM", -- v6
388 uhasx_3 = "e6700f30DNM", -- v6
389 uhsax_3 = "e6700f50DNM", -- v6
390 uhsub16_3 = "e6700f70DNM", -- v6
391 uhadd8_3 = "e6700f90DNM", -- v6
392 uhsub8_3 = "e6700ff0DNM", -- v6
393
394 -- Load/store instructions.
395 str_2 = "e4000000DL", str_3 = "e4000000DL", str_4 = "e4000000DL",
396 strb_2 = "e4400000DL", strb_3 = "e4400000DL", strb_4 = "e4400000DL",
397 ldr_2 = "e4100000DL", ldr_3 = "e4100000DL", ldr_4 = "e4100000DL",
398 ldrb_2 = "e4500000DL", ldrb_3 = "e4500000DL", ldrb_4 = "e4500000DL",
399 strh_2 = "e00000b0DL", strh_3 = "e00000b0DL",
400 ldrh_2 = "e01000b0DL", ldrh_3 = "e01000b0DL",
401 ldrd_2 = "e00000d0DL", ldrd_3 = "e00000d0DL", -- v5TE
402 ldrsb_2 = "e01000d0DL", ldrsb_3 = "e01000d0DL",
403 strd_2 = "e00000f0DL", strd_3 = "e00000f0DL", -- v5TE
404 ldrsh_2 = "e01000f0DL", ldrsh_3 = "e01000f0DL",
405
406 ldm_2 = "e8900000nR", ldmia_2 = "e8900000nR", ldmfd_2 = "e8900000nR",
407 ldmda_2 = "e8100000nR", ldmfa_2 = "e8100000nR",
408 ldmdb_2 = "e9100000nR", ldmea_2 = "e9100000nR",
409 ldmib_2 = "e9900000nR", ldmed_2 = "e9900000nR",
410 stm_2 = "e8800000nR", stmia_2 = "e8800000nR", stmfd_2 = "e8800000nR",
411 stmda_2 = "e8000000nR", stmfa_2 = "e8000000nR",
412 stmdb_2 = "e9000000nR", stmea_2 = "e9000000nR",
413 stmib_2 = "e9800000nR", stmed_2 = "e9800000nR",
414 pop_1 = "e8bd0000R", push_1 = "e92d0000R",
415
416 -- Branch instructions.
417 b_1 = "ea000000B",
418 bl_1 = "eb000000B",
419 blx_1 = "e12fff30C",
420 bx_1 = "e12fff10M",
421
422 -- Miscellaneous instructions.
423 nop_0 = "e1a00000",
424 mrs_1 = "e10f0000D",
425 bkpt_1 = "e1200070K", -- v5T
426 svc_1 = "ef000000T", swi_1 = "ef000000T",
427 ud_0 = "e7f001f0",
428
429 -- NYI: Advanced SIMD and VFP instructions.
430
431 -- NYI instructions, since I have no need for them right now:
432 -- swp, swpb, strex, ldrex, strexd, ldrexd, strexb, ldrexb, strexh, ldrexh
433 -- msr, nopv6, yield, wfe, wfi, sev, dbg, bxj, smc, srs, rfe
434 -- cps, setend, pli, pld, pldw, clrex, dsb, dmb, isb
435 -- stc, ldc, mcr, mcr2, mrc, mrc2, mcrr, mcrr2, mrrc, mrrc2, cdp, cdp2
436}
437
438-- Add mnemonics for "s" variants.
439do
440 local t = {}
441 for k,v in pairs(map_op) do
442 if sub(v, -1) == "s" then
443 local v2 = sub(v, 1, 2)..char(byte(v, 3)+1)..sub(v, 4, -2)
444 t[sub(k, 1, -3).."s"..sub(k, -2)] = v2
445 end
446 end
447 for k,v in pairs(t) do
448 map_op[k] = v
449 end
450end
451
452------------------------------------------------------------------------------
453
454local function parse_gpr(expr)
455 local tname, ovreg = match(expr, "^([%w_]+):(r1?[0-9])$")
456 local tp = map_type[tname or expr]
457 if tp then
458 local reg = ovreg or tp.reg
459 if not reg then
460 werror("type `"..(tname or expr).."' needs a register override")
461 end
462 expr = reg
463 end
464 local r = match(expr, "^r(1?[0-9])$")
465 if r then
466 r = tonumber(r)
467 if r <= 15 then return r, tp end
468 end
469 werror("bad register name `"..expr.."'")
470end
471
472local function parse_gpr_pm(expr)
473 local pm, expr2 = match(expr, "^([+-]?)(.*)$")
474 return parse_gpr(expr2), (pm == "-")
475end
476
477local function parse_reglist(reglist)
478 reglist = match(reglist, "^{%s*([^}]*)}$")
479 if not reglist then werror("register list expected") end
480 local rr = 0
481 for p in gmatch(reglist..",", "%s*([^,]*),") do
482 local rbit = 2^parse_gpr(gsub(p, "%s+$", ""))
483 if ((rr - (rr % rbit)) / rbit) % 2 ~= 0 then
484 werror("duplicate register `"..p.."'")
485 end
486 rr = rr + rbit
487 end
488 return rr
489end
490
491local function parse_imm(imm, bits, shift, scale, signed)
492 imm = match(imm, "^#(.*)$")
493 if not imm then werror("expected immediate operand") end
494 local n = tonumber(imm)
495 if n then
496 if n % 2^scale == 0 then
497 n = n / 2^scale
498 if signed then
499 if n >= 0 then
500 if n < 2^(bits-1) then return n*2^shift end
501 else
502 if n >= -(2^(bits-1))-1 then return (n+2^bits)*2^shift end
503 end
504 else
505 if n >= 0 and n <= 2^bits-1 then return n*2^shift end
506 end
507 end
508 werror("out of range immediate `"..imm.."'")
509 else
510 waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm)
511 return 0
512 end
513end
514
515local function parse_imm12(imm)
516 local n = tonumber(imm)
517 if n then
518 local m = n
519 for i=0,-15,-1 do
520 if m >= 0 and m <= 255 and n % 1 == 0 then return m + (i%16) * 256 end
521 local t = m % 4
522 m = (m - t) / 4 + t * 2^30
523 end
524 werror("out of range immediate `"..imm.."'")
525 else
526 waction("IMM12", 0, imm)
527 return 0
528 end
529end
530
531local function parse_imm16(imm)
532 imm = match(imm, "^#(.*)$")
533 if not imm then werror("expected immediate operand") end
534 local n = tonumber(imm)
535 if n then
536 if n >= 0 and n <= 65535 and n % 1 == 0 then
537 local t = n % 4096
538 return (n - t) * 16 + t
539 end
540 werror("out of range immediate `"..imm.."'")
541 else
542 waction("IMM16", 32*16, imm)
543 return 0
544 end
545end
546
547local function parse_imm_load(imm, ext)
548 local n = tonumber(imm)
549 if n then
550 if ext then
551 if n >= -255 and n <= 255 then
552 local up = 0x00800000
553 if n < 0 then n = -n; up = 0 end
554 return (n-(n%16))*16+(n%16) + up
555 end
556 else
557 if n >= -4095 and n <= 4095 then
558 if n >= 0 then return n+0x00800000 end
559 return -n
560 end
561 end
562 werror("out of range immediate `"..imm.."'")
563 else
564 waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12), imm)
565 return 0
566 end
567end
568
569local function parse_shift(shift, gprok)
570 if shift == "rrx" then
571 return 3 * 32
572 else
573 local s, s2 = match(shift, "^(%S+)%s*(.*)$")
574 s = map_shift[s]
575 if not s then werror("expected shift operand") end
576 if sub(s2, 1, 1) == "#" then
577 return parse_imm(s2, 5, 7, 0, false) + s * 32
578 else
579 if not gprok then werror("expected immediate shift operand") end
580 return parse_gpr(s2) * 256 + s * 32 + 16
581 end
582 end
583end
584
585local function parse_load(params, nparams, n, op)
586 local oplo = op % 256
587 local ext, ldrd = (oplo ~= 0), (oplo == 208)
588 local d
589 if (ldrd or oplo == 240) then
590 d = ((op - (op % 4096)) / 4096) % 16
591 if d % 2 ~= 0 then werror("odd destination register") end
592 end
593 local p1, wb = match(params[n], "^%[%s*(.-)%s*%](!?)$")
594 local p2 = params[n+1]
595 if not p1 then
596 if not p2 then
597 local reg, tailr = match(params[n], "^([%w_:]+)%s*(.*)$")
598 if reg and tailr ~= "" then
599 local d, tp = parse_gpr(reg)
600 if tp then
601 waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12),
602 format(tp.ctypefmt, tailr))
603 return op + d * 65536 + 0x01000000 + (ext and 0x00400000 or 0)
604 end
605 end
606 end
607 werror("expected address operand")
608 end
609 if wb == "!" then op = op + 0x00200000 end
610 if p2 then
611 if wb == "!" then werror("bad use of '!'") end
612 local p3 = params[n+2]
613 op = op + parse_gpr(p1) * 65536
614 local imm = match(p2, "^#(.*)$")
615 if imm then
616 local m = parse_imm_load(imm, ext)
617 if p3 then werror("too many parameters") end
618 op = op + m + (ext and 0x00400000 or 0)
619 else
620 local m, neg = parse_gpr_pm(p2)
621 if ldrd and (m == d or m-1 == d) then werror("register conflict") end
622 op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000)
623 if p3 then op = op + parse_shift(p3) end
624 end
625 else
626 local p1a, p2 = match(p1, "^([^,%s]*)%s*(.*)$")
627 local n = parse_gpr(p1a)
628 op = op + parse_gpr(p1a) * 65536 + 0x01000000
629 if p2 ~= "" then
630 local imm = match(p2, "^,%s*#(.*)$")
631 if imm then
632 local m = parse_imm_load(imm, ext)
633 op = op + m + (ext and 0x00400000 or 0)
634 else
635 local p2a, p3 = match(p2, "^,%s*([^,%s]*)%s*,?%s*(.*)$")
636 local m, neg = parse_gpr_pm(p2a)
637 if ldrd and (m == d or m-1 == d) then werror("register conflict") end
638 op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000)
639 if p3 ~= "" then
640 if ext then werror("too many parameters") end
641 op = op + parse_shift(p3)
642 end
643 end
644 else
645 if wb == "!" then werror("bad use of '!'") end
646 op = op + (ext and 0x00c00000 or 0x00800000)
647 end
648 end
649 return op
650end
651
652local function parse_label(label, def)
653 local prefix = sub(label, 1, 2)
654 -- =>label (pc label reference)
655 if prefix == "=>" then
656 return "PC", 0, sub(label, 3)
657 end
658 -- ->name (global label reference)
659 if prefix == "->" then
660 return "LG", map_global[sub(label, 3)]
661 end
662 if def then
663 -- [1-9] (local label definition)
664 if match(label, "^[1-9]$") then
665 return "LG", 10+tonumber(label)
666 end
667 else
668 -- [<>][1-9] (local label reference)
669 local dir, lnum = match(label, "^([<>])([1-9])$")
670 if dir then -- Fwd: 1-9, Bkwd: 11-19.
671 return "LG", lnum + (dir == ">" and 0 or 10)
672 end
673 -- extern label (extern label reference)
674 local extname = match(label, "^extern%s+(%S+)$")
675 if extname then
676 return "EXT", map_extern[extname]
677 end
678 end
679 werror("bad label `"..label.."'")
680end
681
682------------------------------------------------------------------------------
683
684-- Handle opcodes defined with template strings.
685map_op[".template__"] = function(params, template, nparams)
686 if not params then return sub(template, 9) end
687 local op = tonumber(sub(template, 1, 8), 16)
688 local n = 1
689
690 -- Limit number of section buffer positions used by a single dasm_put().
691 -- A single opcode needs a maximum of 3 positions (rlwinm).
692 if secpos+3 > maxsecpos then wflush() end
693 local pos = wpos()
694
695 -- Process each character.
696 for p in gmatch(sub(template, 9), ".") do
697 if p == "D" then
698 op = op + parse_gpr(params[n]) * 4096; n = n + 1
699 elseif p == "N" then
700 op = op + parse_gpr(params[n]) * 65536; n = n + 1
701 elseif p == "S" then
702 op = op + parse_gpr(params[n]) * 256; n = n + 1
703 elseif p == "M" then
704 op = op + parse_gpr(params[n]); n = n + 1
705 elseif p == "P" then
706 local imm = match(params[n], "^#(.*)$")
707 if imm then
708 op = op + parse_imm12(imm) + 0x02000000
709 else
710 op = op + parse_gpr(params[n])
711 end
712 n = n + 1
713 elseif p == "p" then
714 op = op + parse_shift(params[n], true); n = n + 1
715 elseif p == "L" then
716 op = parse_load(params, nparams, n, op)
717 elseif p == "B" then
718 local mode, n, s = parse_label(params[n], false)
719 waction("REL_"..mode, n, s, 1)
720 elseif p == "C" then -- blx gpr vs. blx label.
721 local p = params[n]
722 if match(p, "^([%w_]+):(r1?[0-9])$") or match(p, "^r(1?[0-9])$") then
723 op = op + parse_gpr(p)
724 else
725 if op < 0xe0000000 then werror("unconditional instruction") end
726 local mode, n, s = parse_label(params[n], false)
727 waction("REL_"..mode, n, s, 1)
728 op = 0xfa000000
729 end
730 elseif p == "n" then
731 local r, wb = match(params[n], "^([^!]*)(!?)$")
732 op = op + parse_gpr(r) * 65536 + (wb == "!" and 0x00200000 or 0)
733 n = n + 1
734 elseif p == "R" then
735 op = op + parse_reglist(params[n]); n = n + 1
736 elseif p == "W" then
737 op = op + parse_imm16(params[n]); n = n + 1
738 elseif p == "v" then
739 op = op + parse_imm(params[n], 5, 7, 0, false); n = n + 1
740 elseif p == "X" then
741 op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1
742 elseif p == "K" then
743 local imm = tonumber(match(params[n], "^#(.*)$")); n = n + 1
744 if not imm or imm % 1 ~= 0 or imm < 0 or imm > 0xffff then
745 werror("bad immediate operand")
746 end
747 local t = imm % 16
748 op = op + (imm - t) * 16 + t
749 elseif p == "T" then
750 op = op + parse_imm(params[n], 24, 0, 0, false); n = n + 1
751 elseif p == "s" then
752 -- Ignored.
753 else
754 assert(false)
755 end
756 end
757 wputpos(pos, op)
758end
759
760------------------------------------------------------------------------------
761
762-- Pseudo-opcode to mark the position where the action list is to be emitted.
763map_op[".actionlist_1"] = function(params)
764 if not params then return "cvar" end
765 local name = params[1] -- No syntax check. You get to keep the pieces.
766 wline(function(out) writeactions(out, name) end)
767end
768
769-- Pseudo-opcode to mark the position where the global enum is to be emitted.
770map_op[".globals_1"] = function(params)
771 if not params then return "prefix" end
772 local prefix = params[1] -- No syntax check. You get to keep the pieces.
773 wline(function(out) writeglobals(out, prefix) end)
774end
775
776-- Pseudo-opcode to mark the position where the global names are to be emitted.
777map_op[".globalnames_1"] = function(params)
778 if not params then return "cvar" end
779 local name = params[1] -- No syntax check. You get to keep the pieces.
780 wline(function(out) writeglobalnames(out, name) end)
781end
782
783-- Pseudo-opcode to mark the position where the extern names are to be emitted.
784map_op[".externnames_1"] = function(params)
785 if not params then return "cvar" end
786 local name = params[1] -- No syntax check. You get to keep the pieces.
787 wline(function(out) writeexternnames(out, name) end)
788end
789
790------------------------------------------------------------------------------
791
792-- Label pseudo-opcode (converted from trailing colon form).
793map_op[".label_1"] = function(params)
794 if not params then return "[1-9] | ->global | =>pcexpr" end
795 if secpos+1 > maxsecpos then wflush() end
796 local mode, n, s = parse_label(params[1], true)
797 if mode == "EXT" then werror("bad label definition") end
798 waction("LABEL_"..mode, n, s, 1)
799end
800
801------------------------------------------------------------------------------
802
803-- Pseudo-opcodes for data storage.
804map_op[".long_*"] = function(params)
805 if not params then return "imm..." end
806 for _,p in ipairs(params) do
807 local n = tonumber(p)
808 if not n then werror("bad immediate `"..p.."'") end
809 if n < 0 then n = n + 2^32 end
810 wputw(n)
811 if secpos+2 > maxsecpos then wflush() end
812 end
813end
814
815-- Alignment pseudo-opcode.
816map_op[".align_1"] = function(params)
817 if not params then return "numpow2" end
818 if secpos+1 > maxsecpos then wflush() end
819 local align = tonumber(params[1])
820 if align then
821 local x = align
822 -- Must be a power of 2 in the range (2 ... 256).
823 for i=1,8 do
824 x = x / 2
825 if x == 1 then
826 waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
827 return
828 end
829 end
830 end
831 werror("bad alignment")
832end
833
834------------------------------------------------------------------------------
835
836-- Pseudo-opcode for (primitive) type definitions (map to C types).
837map_op[".type_3"] = function(params, nparams)
838 if not params then
839 return nparams == 2 and "name, ctype" or "name, ctype, reg"
840 end
841 local name, ctype, reg = params[1], params[2], params[3]
842 if not match(name, "^[%a_][%w_]*$") then
843 werror("bad type name `"..name.."'")
844 end
845 local tp = map_type[name]
846 if tp then
847 werror("duplicate type `"..name.."'")
848 end
849 -- Add #type to defines. A bit unclean to put it in map_archdef.
850 map_archdef["#"..name] = "sizeof("..ctype..")"
851 -- Add new type and emit shortcut define.
852 local num = ctypenum + 1
853 map_type[name] = {
854 ctype = ctype,
855 ctypefmt = format("Dt%X(%%s)", num),
856 reg = reg,
857 }
858 wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
859 ctypenum = num
860end
861map_op[".type_2"] = map_op[".type_3"]
862
863-- Dump type definitions.
864local function dumptypes(out, lvl)
865 local t = {}
866 for name in pairs(map_type) do t[#t+1] = name end
867 sort(t)
868 out:write("Type definitions:\n")
869 for _,name in ipairs(t) do
870 local tp = map_type[name]
871 local reg = tp.reg or ""
872 out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
873 end
874 out:write("\n")
875end
876
877------------------------------------------------------------------------------
878
879-- Set the current section.
880function _M.section(num)
881 waction("SECTION", num)
882 wflush(true) -- SECTION is a terminal action.
883end
884
885------------------------------------------------------------------------------
886
887-- Dump architecture description.
888function _M.dumparch(out)
889 out:write(format("DynASM %s version %s, released %s\n\n",
890 _info.arch, _info.version, _info.release))
891 dumpactions(out)
892end
893
894-- Dump all user defined elements.
895function _M.dumpdef(out, lvl)
896 dumptypes(out, lvl)
897 dumpglobals(out, lvl)
898 dumpexterns(out, lvl)
899end
900
901------------------------------------------------------------------------------
902
903-- Pass callbacks from/to the DynASM core.
904function _M.passcb(wl, we, wf, ww)
905 wline, werror, wfatal, wwarn = wl, we, wf, ww
906 return wflush
907end
908
909-- Setup the arch-specific module.
910function _M.setup(arch, opt)
911 g_arch, g_opt = arch, opt
912end
913
914-- Merge the core maps and the arch-specific maps.
915function _M.mergemaps(map_coreop, map_def)
916 setmetatable(map_op, { __index = function(t, k)
917 local v = map_coreop[k]
918 if v then return v end
919 local cc = sub(k, -4, -3)
920 local cv = map_cond[cc]
921 if cv then
922 local v = rawget(t, sub(k, 1, -5)..sub(k, -2))
923 if v then return format("%x%s", cv, sub(v, 2)) end
924 end
925 end })
926 setmetatable(map_def, { __index = map_archdef })
927 return map_op, map_def
928end
929
930return _M
931
932------------------------------------------------------------------------------
933
diff --git a/dynasm/dynasm.lua b/dynasm/dynasm.lua
index d9dd1800..da94744e 100644
--- a/dynasm/dynasm.lua
+++ b/dynasm/dynasm.lua
@@ -723,8 +723,10 @@ local function splitstmt_one(c)
723 splitlvl = ")"..splitlvl 723 splitlvl = ")"..splitlvl
724 elseif c == "[" then 724 elseif c == "[" then
725 splitlvl = "]"..splitlvl 725 splitlvl = "]"..splitlvl
726 elseif c == ")" or c == "]" then 726 elseif c == "{" then
727 if sub(splitlvl, 1, 1) ~= c then werror("unbalanced () or []") end 727 splitlvl = "}"..splitlvl
728 elseif c == ")" or c == "]" or c == "}" then
729 if sub(splitlvl, 1, 1) ~= c then werror("unbalanced (), [] or {}") end
728 splitlvl = sub(splitlvl, 2) 730 splitlvl = sub(splitlvl, 2)
729 elseif splitlvl == "" then 731 elseif splitlvl == "" then
730 return " \0 " 732 return " \0 "
@@ -740,7 +742,7 @@ local function splitstmt(stmt)
740 742
741 -- Split at commas and equal signs, but obey parentheses and brackets. 743 -- Split at commas and equal signs, but obey parentheses and brackets.
742 splitlvl = "" 744 splitlvl = ""
743 stmt = gsub(stmt, "[,%(%)%[%]]", splitstmt_one) 745 stmt = gsub(stmt, "[,%(%)%[%]{}]", splitstmt_one)
744 if splitlvl ~= "" then werror("unbalanced () or []") end 746 if splitlvl ~= "" then werror("unbalanced () or []") end
745 747
746 -- Split off opcode. 748 -- Split off opcode.
@@ -783,7 +785,7 @@ dostmt = function(stmt)
783 if not f then 785 if not f then
784 if not g_arch then wfatal("first statement must be .arch") end 786 if not g_arch then wfatal("first statement must be .arch") end
785 -- Improve error report. 787 -- Improve error report.
786 for i=0,16 do 788 for i=0,9 do
787 if map_op[op.."_"..i] then 789 if map_op[op.."_"..i] then
788 werror("wrong number of parameters for `"..op.."'") 790 werror("wrong number of parameters for `"..op.."'")
789 end 791 end