summaryrefslogtreecommitdiff
path: root/dynasm/dasm_arm.lua
diff options
context:
space:
mode:
Diffstat (limited to 'dynasm/dasm_arm.lua')
-rw-r--r--dynasm/dasm_arm.lua933
1 files changed, 933 insertions, 0 deletions
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