1 ------------------------------------------------------------------------------
2 -- DynASM ARM64 module.
4 -- Copyright (C) 2005-2015 Mike Pall. All rights reserved.
5 -- See dynasm.lua for full copyright notice.
6 ------------------------------------------------------------------------------
11 description
= "DynASM ARM64 module",
14 release
= "2014-12-03",
19 -- Exported glue functions for the arch-specific module.
20 local _M
= { _info
= _info
}
22 -- Cache library functions.
23 local type, tonumber, pairs
, ipairs
= type, tonumber, pairs
, ipairs
24 local assert, setmetatable
, rawget = assert, setmetatable
, rawget
26 local sub
, format, byte
, char
= _s
.sub
, _s
.format, _s
.byte
, _s
.char
27 local match
, gmatch
, gsub = _s
.match
, _s
.gmatch
, _s
.gsub
28 local concat
, sort, insert
= table.concat
, table.sort, table.insert
29 local bit
= bit
or require("bit")
30 local band
, shl
, shr
, sar
= bit
.band
, bit
.lshift
, bit
.rshift
, bit
.arshift
31 local ror
, tohex
= bit
.ror
, bit
.tohex
33 -- Inherited tables and callbacks.
35 local wline
, werror
, wfatal
, wwarn
38 -- CHECK: Keep this in sync with the C code!
39 local action_names
= {
40 "STOP", "SECTION", "ESC", "REL_EXT",
41 "ALIGN", "REL_LG", "LABEL_LG",
42 "REL_PC", "LABEL_PC", "IMM", "IMM6", "IMM12", "IMM13W", "IMM13X", "IMML",
45 -- Maximum number of section buffer positions for dasm_put().
46 -- CHECK: Keep this in sync with the C code!
47 local maxsecpos
= 25 -- Keep this low, to avoid excessively long C lines.
49 -- Action name -> action number.
51 for n
,name
in ipairs(action_names
) do
52 map_action
[name
] = n
-1
55 -- Action list buffer.
58 -- Argument list for next dasm_put(). Start with offset 0 into action list.
61 -- Current number of section buffer positions for dasm_put().
64 ------------------------------------------------------------------------------
66 -- Dump action names and numbers.
67 local function dumpactions(out
)
68 out
:write("DynASM encoding engine action codes:\n")
69 for n
,name
in ipairs(action_names
) do
70 local num
= map_action
[name
]
71 out
:write(format(" %-10s %02X %d\n", name
, num
, num
))
76 -- Write action list buffer as a huge static C array.
77 local function writeactions(out
, name
)
79 if nn
== 0 then nn
= 1; actlist
[0] = map_action
.STOP
end
80 out
:write("static const unsigned int ", name
, "[", nn
, "] = {\n")
82 assert(out
:write("0x", tohex(actlist
[i
]), ",\n"))
84 assert(out
:write("0x", tohex(actlist
[nn
]), "\n};\n\n"))
87 ------------------------------------------------------------------------------
89 -- Add word to action list.
90 local function wputxw(n
)
91 assert(n
>= 0 and n
<= 0xffffffff and n
% 1 == 0, "word out of range")
92 actlist
[#actlist
+1] = n
95 -- Add action to list with optional arg. Advance buffer pos, too.
96 local function waction(action
, val
, a
, num
)
97 local w
= assert(map_action
[action
], "bad action name `"..action
.."'")
98 wputxw(w
* 0x10000 + (val
or 0))
99 if a
then actargs
[#actargs
+1] = a
end
100 if a
or num
then secpos
= secpos
+ (num
or 1) end
103 -- Flush action list (intervening C code or buffer pos overflow).
104 local function wflush(term
)
105 if #actlist
== actargs
[1] then return end -- Nothing to flush.
106 if not term
then waction("STOP") end -- Terminate action list.
107 wline(format("dasm_put(Dst, %s);", concat(actargs
, ", ")), true)
108 actargs
= { #actlist
} -- Actionlist offset is 1st arg to next dasm_put().
109 secpos
= 1 -- The actionlist offset occupies a buffer position, too.
113 local function wputw(n
)
114 if n
<= 0x000fffff then waction("ESC") end
118 -- Reserve position for word.
119 local function wpos()
120 local pos
= #actlist
+1
125 -- Store word to reserved position.
126 local function wputpos(pos
, n
)
127 assert(n
>= 0 and n
<= 0xffffffff and n
% 1 == 0, "word out of range")
128 if n
<= 0x000fffff then
129 insert(actlist
, pos
+1, n
)
130 n
= map_action
.ESC
* 0x10000
135 ------------------------------------------------------------------------------
137 -- Global label name -> global label number. With auto assignment on 1st use.
138 local next_global
= 20
139 local map_global
= setmetatable({}, { __index
= function(t
, name
)
140 if not match(name
, "^[%a_][%w_]*$") then werror("bad global label") end
141 local n
= next_global
142 if n
> 2047 then werror("too many global labels") end
148 -- Dump global labels.
149 local function dumpglobals(out
, lvl
)
151 for name
, n
in pairs(map_global
) do t
[n
] = name
end
152 out
:write("Global labels:\n")
153 for i
=20,next_global
-1 do
154 out
:write(format(" %s\n", t
[i
]))
159 -- Write global label enum.
160 local function writeglobals(out
, prefix
)
162 for name
, n
in pairs(map_global
) do t
[n
] = name
end
163 out
:write("enum {\n")
164 for i
=20,next_global
-1 do
165 out
:write(" ", prefix
, t
[i
], ",\n")
167 out
:write(" ", prefix
, "_MAX\n};\n")
170 -- Write global label names.
171 local function writeglobalnames(out
, name
)
173 for name
, n
in pairs(map_global
) do t
[n
] = name
end
174 out
:write("static const char *const ", name
, "[] = {\n")
175 for i
=20,next_global
-1 do
176 out
:write(" \"", t
[i
], "\",\n")
178 out
:write(" (const char *)0\n};\n")
181 ------------------------------------------------------------------------------
183 -- Extern label name -> extern label number. With auto assignment on 1st use.
184 local next_extern
= 0
185 local map_extern_
= {}
186 local map_extern
= setmetatable({}, { __index
= function(t
, name
)
187 -- No restrictions on the name for now.
188 local n
= next_extern
189 if n
> 2047 then werror("too many extern labels") end
192 map_extern_
[n
] = name
196 -- Dump extern labels.
197 local function dumpexterns(out
, lvl
)
198 out
:write("Extern labels:\n")
199 for i
=0,next_extern
-1 do
200 out
:write(format(" %s\n", map_extern_
[i
]))
205 -- Write extern label names.
206 local function writeexternnames(out
, name
)
207 out
:write("static const char *const ", name
, "[] = {\n")
208 for i
=0,next_extern
-1 do
209 out
:write(" \"", map_extern_
[i
], "\",\n")
211 out
:write(" (const char *)0\n};\n")
214 ------------------------------------------------------------------------------
216 -- Arch-specific maps.
218 -- Ext. register name -> int. name.
219 local map_archdef
= { xzr
= "@x31", wzr
= "@w31", lr
= "x30", }
221 -- Int. register name -> ext. name.
222 local map_reg_rev
= { ["@x31"] = "xzr", ["@w31"] = "wzr", x30
= "lr", }
224 local map_type
= {} -- Type name -> { ctype, reg }
225 local ctypenum
= 0 -- Type number (for Dt... macros).
227 -- Reverse defines for registers.
228 function _M
.revdef(s
)
229 return map_reg_rev
[s
] or s
232 local map_shift
= { lsl
= 0, lsr
= 1, asr
= 2, }
235 uxtb
= 0, uxth
= 1, uxtw
= 2, uxtx
= 3,
236 sxtb
= 4, sxth
= 5, sxtw
= 6, sxtx
= 7,
240 eq
= 0, ne
= 1, cs
= 2, cc
= 3, mi
= 4, pl
= 5, vs
= 6, vc
= 7,
241 hi
= 8, ls
= 9, ge
= 10, lt
= 11, gt
= 12, le
= 13, al
= 14,
245 ------------------------------------------------------------------------------
249 local function parse_reg(expr
)
250 if not expr
then werror("expected register name") end
251 local tname
, ovreg
= match(expr
, "^([%w_]+):(@?%l%d+)$")
252 local tp
= map_type
[tname
or expr
]
254 local reg
= ovreg
or tp
.reg
256 werror("type `"..(tname
or expr
).."' needs a register override")
260 local ok31
, rt
, r
= match(expr
, "^(@?)([xwqdshb])([123]?[0-9])$")
263 if r
<= 30 or (r
== 31 and ok31
~= "" or (rt
~= "w" and rt
~= "x")) then
264 if not parse_reg_type
then
266 elseif parse_reg_type
~= rt
then
267 werror("register size mismatch")
272 werror("bad register name `"..expr
.."'")
275 local function parse_reg_base(expr
)
276 if expr
== "sp" then return 0x3e0 end
277 local base
, tp
= parse_reg(expr
)
278 if parse_reg_type
~= "x" then werror("bad register type") end
279 parse_reg_type
= false
280 return shl(base
, 5), tp
285 local loadenv
= setfenv
and function(s
)
286 local code
= loadstring(s
, "")
287 if code
then setfenv(code
, parse_ctx
) end
290 return load(s
, "", nil, parse_ctx
)
293 -- Try to parse simple arithmetic, too, since some basic ops are aliases.
294 local function parse_number(n
)
295 local x
= tonumber(n
)
296 if x
then return x
end
297 local code
= loadenv("return "..n
)
299 local ok
, y
= pcall(code
)
300 if ok
then return y
end
305 local function parse_imm(imm
, bits
, shift
, scale
, signed
)
306 imm
= match(imm
, "^#(.*)$")
307 if not imm
then werror("expected immediate operand") end
308 local n
= parse_number(imm
)
310 local m
= sar(n
, scale
)
311 if shl(m
, scale
) == n
then
313 local s
= sar(m
, bits
-1)
314 if s
== 0 then return shl(m
, shift
)
315 elseif s
== -1 then return shl(m
+ shl(1, bits
), shift
) end
317 if sar(m
, bits
) == 0 then return shl(m
, shift
) end
320 werror("out of range immediate `"..imm
.."'")
322 waction("IMM", (signed
and 32768 or 0)+scale
*1024+bits
*32+shift
, imm
)
327 local function parse_imm12(imm
)
328 imm
= match(imm
, "^#(.*)$")
329 if not imm
then werror("expected immediate operand") end
330 local n
= parse_number(imm
)
332 if shr(n
, 12) == 0 then
334 elseif band(n
, 0xff000fff) == 0 then
335 return shr(n
, 2) + 0x00400000
337 werror("out of range immediate `"..imm
.."'")
339 waction("IMM12", 0, imm
)
344 local function parse_imm13(imm
)
345 imm
= match(imm
, "^#(.*)$")
346 if not imm
then werror("expected immediate operand") end
347 local n
= parse_number(imm
)
348 local r64
= parse_reg_type
== "x"
349 if n
and n
% 1 == 0 and n
>= 0 and n
<= 0xffffffff then
351 if band(n
, 1) == 1 then n
= bit
.bnot(n
); inv
= true end
353 for i
=1,32 do t
[i
] = band(n
, 1); n
= shr(n
, 1) end
354 local b
= table.concat(t
)
355 b
= b
..(r64
and (inv
and "1" or "0"):rep(32) or b
)
356 local p0
, p1
, p0a
, p1a
= b
:match("^(0+)(1+)(0*)(1*)")
358 local w
= p1a
== "" and (r64
and 64 or 32) or #p1
+#p0a
359 if band(w
, w
-1) == 0 and b
== b
:sub(1, w
):rep(64/w
) then
360 local s
= band(-2*w
, 0x3f) - 1
361 if w
== 64 then s
= s
+ 0x1000 end
363 return shl(w
-#p1
-#p0
, 16) + shl(s
+w
-#p1
, 10)
365 return shl(w
-#p0
, 16) + shl(s
+#p1
, 10)
369 werror("out of range immediate `"..imm
.."'")
371 waction("IMM13X", 0, format("(unsigned int)(%s)", imm
))
372 actargs
[#actargs
+1] = format("(unsigned int)((unsigned long long)(%s)>>32)", imm
)
375 waction("IMM13W", 0, imm
)
380 local function parse_imm6(imm
)
381 imm
= match(imm
, "^#(.*)$")
382 if not imm
then werror("expected immediate operand") end
383 local n
= parse_number(imm
)
385 if n
>= 0 and n
<= 63 then
386 return shl(band(n
, 0x1f), 19) + (n
>= 32 and 0x80000000 or 0)
388 werror("out of range immediate `"..imm
.."'")
390 waction("IMM6", 0, imm
)
395 local function parse_imm_load(imm
, scale
)
396 local n
= parse_number(imm
)
398 local m
= sar(n
, scale
)
399 if shl(m
, scale
) == n
and m
>= 0 and m
< 0x1000 then
400 return shl(m
, 10) + 0x01000000 -- Scaled, unsigned 12 bit offset.
401 elseif n
>= -256 and n
< 256 then
402 return shl(band(n
, 511), 12) -- Unscaled, signed 9 bit offset.
404 werror("out of range immediate `"..imm
.."'")
406 waction("IMML", 0, imm
)
411 local function parse_fpimm(imm
)
412 imm
= match(imm
, "^#(.*)$")
413 if not imm
then werror("expected immediate operand") end
414 local n
= parse_number(imm
)
416 local m
, e
= math
.frexp(n
)
417 local s
, e2
= 0, band(e
-2, 7)
418 if m
< 0 then m
= -m
; s
= 0x00100000 end
420 if m
% 1 == 0 and m
>= 0 and m
<= 15 and sar(shl(e2
, 29), 29)+2 == e
then
421 return s
+ shl(e2
, 17) + shl(m
, 13)
423 werror("out of range immediate `"..imm
.."'")
425 werror("NYI fpimm action")
429 local function parse_shift(expr
)
430 local s
, s2
= match(expr
, "^(%S+)%s*(.*)$")
432 if not s
then werror("expected shift operand") end
433 return parse_imm(s2
, 6, 10, 0, false) + shl(s
, 22)
436 local function parse_lslx16(expr
)
437 local n
= match(expr
, "^lsl%s*#(%d+)$")
439 if not n
then werror("expected shift operand") end
440 if band(n
, parse_reg_type
== "x" and 0xffffffcf or 0xffffffef) ~= 0 then
441 werror("bad shift amount")
446 local function parse_extend(expr
)
447 local s
, s2
= match(expr
, "^(%S+)%s*(.*)$")
449 s
= parse_reg_type
== "x" and 3 or 2
453 if not s
then werror("expected extend operand") end
454 return (s2
== "" and 0 or parse_imm(s2
, 3, 10, 0, false)) + shl(s
, 13)
457 local function parse_cond(expr
, inv
)
458 local c
= map_cond
[expr
]
459 if not c
then werror("expected condition operand") end
460 return shl(bit
.bxor(c
, inv
), 12)
463 local function parse_load(params
, nparams
, n
, op
)
464 if params
[n
+2] then werror("too many operands") end
465 local pn
, p2
= params
[n
], params
[n
+1]
466 local p1
, wb
= match(pn
, "^%[%s*(.-)%s*%](!?)$")
469 local reg
, tailr
= match(pn
, "^([%w_:]+)%s*(.*)$")
470 if reg
and tailr
~= "" then
471 local base
, tp
= parse_reg_base(reg
)
473 waction("IMML", 0, format(tp
.ctypefmt
, tailr
))
478 werror("expected address operand")
480 local scale
= shr(op
, 30)
482 if wb
== "!" then werror("bad use of '!'") end
483 op
= op
+ parse_reg_base(p1
) + parse_imm(p2
, 9, 12, 0, true) + 0x400
484 elseif wb
== "!" then
485 local p1a
, p2a
= match(p1
, "^([^,%s]*)%s*,%s*(.*)$")
486 if not p1a
then werror("bad use of '!'") end
487 op
= op
+ parse_reg_base(p1a
) + parse_imm(p2a
, 9, 12, 0, true) + 0xc00
489 local p1a
, p2a
= match(p1
, "^([^,%s]*)%s*(.*)$")
490 op
= op
+ parse_reg_base(p1a
)
492 local imm
= match(p2a
, "^,%s*#(.*)$")
494 op
= op
+ parse_imm_load(imm
, scale
)
496 local p2b
, p3b
, p3s
= match(p2a
, "^,%s*([^,%s]*)%s*,?%s*(%S*)%s*(.*)$")
497 op
= op
+ shl(parse_reg(p2b
), 16) + 0x00200800
498 if parse_reg_type
~= "x" and parse_reg_type
~= "w" then
499 werror("bad index register type")
502 if parse_reg_type
~= "x" then werror("bad index register type") end
505 if p3s
== "" or p3s
== "#0" then
506 elseif p3s
== "#"..scale
then
511 if parse_reg_type
== "x" then
512 if p3b
== "lsl" and p3s
~= "" then op
= op
+ 0x6000
513 elseif p3b
== "sxtx" then op
= op
+ 0xe000
515 werror("bad extend/shift specifier")
518 if p3b
== "uxtw" then op
= op
+ 0x4000
519 elseif p3b
== "sxtw" then op
= op
+ 0xc000
521 werror("bad extend/shift specifier")
527 if wb
== "!" then werror("bad use of '!'") end
534 local function parse_load_pair(params
, nparams
, n
, op
)
535 if params
[n
+2] then werror("too many operands") end
536 local pn
, p2
= params
[n
], params
[n
+1]
537 local scale
= shr(op
, 30) == 0 and 2 or 3
538 local p1
, wb
= match(pn
, "^%[%s*(.-)%s*%](!?)$")
541 local reg
, tailr
= match(pn
, "^([%w_:]+)%s*(.*)$")
542 if reg
and tailr
~= "" then
543 local base
, tp
= parse_reg_base(reg
)
545 waction("IMM", 32768+7*32+15+scale
*1024, format(tp
.ctypefmt
, tailr
))
546 return op
+ base
+ 0x01000000
550 werror("expected address operand")
553 if wb
== "!" then werror("bad use of '!'") end
556 local p1a
, p2a
= match(p1
, "^([^,%s]*)%s*,%s*(.*)$")
557 if p1a
then p1
, p2
= p1a
, p2a
else p2
= "#0" end
558 op
= op
+ (wb
== "!" and 0x01800000 or 0x01000000)
560 return op
+ parse_reg_base(p1
) + parse_imm(p2
, 7, 15, scale
, true)
563 local function parse_label(label
, def
)
564 local prefix
= sub(label
, 1, 2)
565 -- =>label (pc label reference)
566 if prefix
== "=>" then
567 return "PC", 0, sub(label
, 3)
569 -- ->name (global label reference)
570 if prefix
== "->" then
571 return "LG", map_global
[sub(label
, 3)]
574 -- [1-9] (local label definition)
575 if match(label
, "^[1-9]$") then
576 return "LG", 10+tonumber(label
)
579 -- [<>][1-9] (local label reference)
580 local dir
, lnum
= match(label
, "^([<>])([1-9])$")
581 if dir
then -- Fwd: 1-9, Bkwd: 11-19.
582 return "LG", lnum
+ (dir
== ">" and 0 or 10)
584 -- extern label (extern label reference)
585 local extname
= match(label
, "^extern%s+(%S+)$")
587 return "EXT", map_extern
[extname
]
590 werror("bad label `"..label
.."'")
593 local function branch_type(op
)
594 if band(op
, 0x7c000000) == 0x14000000 then return 0 -- B, BL
595 elseif shr(op
, 24) == 0x54 or band(op
, 0x7e000000) == 0x34000000 or
596 band(op
, 0x3b000000) == 0x18000000 then
597 return 0x800 -- B.cond, CBZ, CBNZ, LDR* literal
598 elseif band(op
, 0x7e000000) == 0x36000000 then return 0x1000 -- TBZ, TBNZ
599 elseif band(op
, 0x9f000000) == 0x10000000 then return 0x2000 -- ADR
600 elseif band(op
, 0x9f000000) == band(0x90000000) then return 0x3000 -- ADRP
602 assert(false, "unknown branch type")
606 ------------------------------------------------------------------------------
608 local map_op
, op_template
610 local function op_alias(opname
, f
)
611 return function(params
, nparams
)
612 if not params
then return "-> "..opname
:sub(1, -3) end
614 op_template(params
, map_op
[opname
], nparams
)
618 local function alias_bfx(p
)
619 p
[4] = "#("..p
[3]:sub(2)..")+("..p
[4]:sub(2)..")-1"
622 local function alias_bfiz(p
)
624 if parse_reg_type
== "w" then
625 p
[3] = "#-("..p
[3]:sub(2)..")%32"
626 p
[4] = "#("..p
[4]:sub(2)..")-1"
628 p
[3] = "#-("..p
[3]:sub(2)..")%64"
629 p
[4] = "#("..p
[4]:sub(2)..")-1"
633 local alias_lslimm
= op_alias("ubfm_4", function(p
)
635 local sh
= p
[3]:sub(2)
636 if parse_reg_type
== "w" then
637 p
[3] = "#-("..sh
..")%32"
638 p
[4] = "#31-("..sh
..")"
640 p
[3] = "#-("..sh
..")%64"
641 p
[4] = "#63-("..sh
..")"
645 -- Template strings for ARM instructions.
647 -- Basic data processing instructions.
648 add_3
= "0b000000DNMg|11000000pDpNIg|8b206000pDpNMx",
649 add_4
= "0b000000DNMSg|0b200000DNMXg|8b200000pDpNMXx|8b200000pDpNxMwX",
650 adds_3
= "2b000000DNMg|31000000DpNIg|ab206000DpNMx",
651 adds_4
= "2b000000DNMSg|2b200000DNMXg|ab200000DpNMXx|ab200000DpNxMwX",
652 cmn_2
= "2b00001fNMg|3100001fpNIg|ab20601fpNMx",
653 cmn_3
= "2b00001fNMSg|2b20001fNMXg|ab20001fpNMXx|ab20001fpNxMwX",
655 sub_3
= "4b000000DNMg|51000000pDpNIg|cb206000pDpNMx",
656 sub_4
= "4b000000DNMSg|4b200000DNMXg|cb200000pDpNMXx|cb200000pDpNxMwX",
657 subs_3
= "6b000000DNMg|71000000DpNIg|eb206000DpNMx",
658 subs_4
= "6b000000DNMSg|6b200000DNMXg|eb200000DpNMXx|eb200000DpNxMwX",
659 cmp_2
= "6b00001fNMg|7100001fpNIg|eb20601fpNMx",
660 cmp_3
= "6b00001fNMSg|6b20001fNMXg|eb20001fpNMXx|eb20001fpNxMwX",
662 neg_2
= "4b0003e0DMg",
663 neg_3
= "4b0003e0DMSg",
664 negs_2
= "6b0003e0DMg",
665 negs_3
= "6b0003e0DMSg",
667 adc_3
= "1a000000DNMg",
668 adcs_3
= "3a000000DNMg",
669 sbc_3
= "5a000000DNMg",
670 sbcs_3
= "7a000000DNMg",
671 ngc_2
= "5a0003e0DMg",
672 ngcs_2
= "7a0003e0DMg",
674 and_3
= "0a000000DNMg|12000000pDNig",
675 and_4
= "0a000000DNMSg",
676 orr_3
= "2a000000DNMg|32000000pDNig",
677 orr_4
= "2a000000DNMSg",
678 eor_3
= "4a000000DNMg|52000000pDNig",
679 eor_4
= "4a000000DNMSg",
680 ands_3
= "6a000000DNMg|72000000DNig",
681 ands_4
= "6a000000DNMSg",
682 tst_2
= "6a00001fNMg|7200001fNig",
683 tst_3
= "6a00001fNMSg",
685 bic_3
= "0a200000DNMg",
686 bic_4
= "0a200000DNMSg",
687 orn_3
= "2a200000DNMg",
688 orn_4
= "2a200000DNMSg",
689 eon_3
= "4a200000DNMg",
690 eon_4
= "4a200000DNMSg",
691 bics_3
= "6a200000DNMg",
692 bics_4
= "6a200000DNMSg",
694 movn_2
= "12800000DWg",
695 movn_3
= "12800000DWRg",
696 movz_2
= "52800000DWg",
697 movz_3
= "52800000DWRg",
698 movk_2
= "72800000DWg",
699 movk_3
= "72800000DWRg",
701 -- TODO: this doesn't cover all valid immediates for mov reg, #imm.
702 mov_2
= "2a0003e0DMg|52800000DW|320003e0pDig|11000000pDpNg",
703 mov_3
= "2a0003e0DMSg",
704 mvn_2
= "2a2003e0DMg",
705 mvn_3
= "2a2003e0DMSg",
707 adr_2
= "10000000DBx",
708 adrp_2
= "90000000DBx",
710 csel_4
= "1a800000DNMCg",
711 csinc_4
= "1a800400DNMCg",
712 csinv_4
= "5a800000DNMCg",
713 csneg_4
= "5a800400DNMCg",
714 cset_2
= "1a9f07e0Dcg",
715 csetm_2
= "5a9f03e0Dcg",
716 cinc_3
= "1a800400DNmcg",
717 cinv_3
= "5a800000DNmcg",
718 cneg_3
= "5a800400DNmcg",
720 ccmn_4
= "3a400000NMVCg|3a400800N5VCg",
721 ccmp_4
= "7a400000NMVCg|7a400800N5VCg",
723 madd_4
= "1b000000DNMAg",
724 msub_4
= "1b008000DNMAg",
725 mul_3
= "1b007c00DNMg",
726 mneg_3
= "1b00fc00DNMg",
728 smaddl_4
= "9b200000DxNMwAx",
729 smsubl_4
= "9b208000DxNMwAx",
730 smull_3
= "9b207c00DxNMw",
731 smnegl_3
= "9b20fc00DxNMw",
732 smulh_3
= "9b407c00DNMx",
733 umaddl_4
= "9ba00000DxNMwAx",
734 umsubl_4
= "9ba08000DxNMwAx",
735 umull_3
= "9ba07c00DxNMw",
736 umnegl_3
= "9ba0fc00DxNMw",
737 umulh_3
= "9bc07c00DNMx",
739 udiv_3
= "1ac00800DNMg",
740 sdiv_3
= "1ac00c00DNMg",
743 sbfm_4
= "13000000DN12w|93400000DN12x",
744 bfm_4
= "33000000DN12w|b3400000DN12x",
745 ubfm_4
= "53000000DN12w|d3400000DN12x",
746 extr_4
= "13800000DNM2w|93c00000DNM2x",
748 sxtb_2
= "13001c00DNw|93401c00DNx",
749 sxth_2
= "13003c00DNw|93403c00DNx",
750 sxtw_2
= "93407c00DxNw",
751 uxtb_2
= "53001c00DNw",
752 uxth_2
= "53003c00DNw",
754 sbfx_4
= op_alias("sbfm_4", alias_bfx
),
755 bfxil_4
= op_alias("bfm_4", alias_bfx
),
756 ubfx_4
= op_alias("ubfm_4", alias_bfx
),
757 sbfiz_4
= op_alias("sbfm_4", alias_bfiz
),
758 bfi_4
= op_alias("bfm_4", alias_bfiz
),
759 ubfiz_4
= op_alias("ubfm_4", alias_bfiz
),
761 lsl_3
= function(params
, nparams
)
762 if params
and params
[3]:byte() == 35 then
763 return alias_lslimm(params
, nparams
)
765 return op_template(params
, "1ac02000DNMg", nparams
)
768 lsr_3
= "1ac02400DNMg|53007c00DN1w|d340fc00DN1x",
769 asr_3
= "1ac02800DNMg|13007c00DN1w|9340fc00DN1x",
770 ror_3
= "1ac02c00DNMg|13800000DNm2w|93c00000DNm2x",
772 clz_2
= "5ac01000DNg",
773 cls_2
= "5ac01400DNg",
774 rbit_2
= "5ac00000DNg",
775 rev_2
= "5ac00800DNw|dac00c00DNx",
776 rev16_2
= "5ac00400DNg",
777 rev32_2
= "dac00800DNx",
780 ["strb_*"] = "38000000DwL",
781 ["ldrb_*"] = "38400000DwL",
782 ["ldrsb_*"] = "38c00000DwL|38800000DxL",
783 ["strh_*"] = "78000000DwL",
784 ["ldrh_*"] = "78400000DwL",
785 ["ldrsh_*"] = "78c00000DwL|78800000DxL",
786 ["str_*"] = "b8000000DwL|f8000000DxL|bc000000DsL|fc000000DdL",
787 ["ldr_*"] = "18000000DwB|58000000DxB|1c000000DsB|5c000000DdB|b8400000DwL|f8400000DxL|bc400000DsL|fc400000DdL",
788 ["ldrsw_*"] = "98000000DxB|b8800000DxL",
789 -- NOTE: ldur etc. are handled by ldr et al.
791 ["stp_*"] = "28000000DAwP|a8000000DAxP|2c000000DAsP|6c000000DAdP",
792 ["ldp_*"] = "28400000DAwP|a8400000DAxP|2c400000DAsP|6c400000DAdP",
793 ["ldpsw_*"] = "68400000DAxP",
798 blr_1
= "d63f0000Nx",
801 ret_1
= "d65f0000Nx",
802 -- b.cond is added below.
803 cbz_2
= "34000000DBg",
804 cbnz_2
= "35000000DBg",
805 tbz_3
= "36000000DTBw|36000000DTBx",
806 tbnz_3
= "37000000DTBw|37000000DTBx",
808 -- Miscellaneous instructions.
809 -- TODO: hlt, hvc, smc, svc, eret, dcps[123], drps, mrs, msr
810 -- TODO: sys, sysl, ic, dc, at, tlbi
811 -- TODO: hint, yield, wfe, wfi, sev, sevl
812 -- TODO: clrex, dsb, dmb, isb
817 -- Floating point instructions.
818 fmov_2
= "1e204000DNf|1e260000DwNs|1e270000DsNw|9e660000DxNd|9e670000DdNx|1e201000DFf",
819 fabs_2
= "1e20c000DNf",
820 fneg_2
= "1e214000DNf",
821 fsqrt_2
= "1e21c000DNf",
823 fcvt_2
= "1e22c000DdNs|1e624000DsNd",
825 -- TODO: half-precision and fixed-point conversions.
826 fcvtas_2
= "1e240000DwNs|9e240000DxNs|1e640000DwNd|9e640000DxNd",
827 fcvtau_2
= "1e250000DwNs|9e250000DxNs|1e650000DwNd|9e650000DxNd",
828 fcvtms_2
= "1e300000DwNs|9e300000DxNs|1e700000DwNd|9e700000DxNd",
829 fcvtmu_2
= "1e310000DwNs|9e310000DxNs|1e710000DwNd|9e710000DxNd",
830 fcvtns_2
= "1e200000DwNs|9e200000DxNs|1e600000DwNd|9e600000DxNd",
831 fcvtnu_2
= "1e210000DwNs|9e210000DxNs|1e610000DwNd|9e610000DxNd",
832 fcvtps_2
= "1e280000DwNs|9e280000DxNs|1e680000DwNd|9e680000DxNd",
833 fcvtpu_2
= "1e290000DwNs|9e290000DxNs|1e690000DwNd|9e690000DxNd",
834 fcvtzs_2
= "1e380000DwNs|9e380000DxNs|1e780000DwNd|9e780000DxNd",
835 fcvtzu_2
= "1e390000DwNs|9e390000DxNs|1e790000DwNd|9e790000DxNd",
837 scvtf_2
= "1e220000DsNw|9e220000DsNx|1e620000DdNw|9e620000DdNx",
838 ucvtf_2
= "1e230000DsNw|9e230000DsNx|1e630000DdNw|9e630000DdNx",
840 frintn_2
= "1e244000DNf",
841 frintp_2
= "1e24c000DNf",
842 frintm_2
= "1e254000DNf",
843 frintz_2
= "1e25c000DNf",
844 frinta_2
= "1e264000DNf",
845 frintx_2
= "1e274000DNf",
846 frinti_2
= "1e27c000DNf",
848 fadd_3
= "1e202800DNMf",
849 fsub_3
= "1e203800DNMf",
850 fmul_3
= "1e200800DNMf",
851 fnmul_3
= "1e208800DNMf",
852 fdiv_3
= "1e201800DNMf",
854 fmadd_4
= "1f000000DNMAf",
855 fmsub_4
= "1f008000DNMAf",
856 fnmadd_4
= "1f200000DNMAf",
857 fnmsub_4
= "1f208000DNMAf",
859 fmax_3
= "1e204800DNMf",
860 fmaxnm_3
= "1e206800DNMf",
861 fmin_3
= "1e205800DNMf",
862 fminnm_3
= "1e207800DNMf",
864 fcmp_2
= "1e202000NMf|1e202008NZf",
865 fcmpe_2
= "1e202010NMf|1e202018NZf",
867 fccmp_4
= "1e200400NMVCf",
868 fccmpe_4
= "1e200410NMVCf",
870 fcsel_4
= "1e200c00DNMCf",
872 -- TODO: crc32*, aes*, sha*, pmull
873 -- TODO: SIMD instructions.
876 for cond
,c
in pairs(map_cond
) do
877 map_op
["b"..cond
.."_1"] = tohex(0x54000000+c
).."B"
880 ------------------------------------------------------------------------------
882 -- Handle opcodes defined with template strings.
883 local function parse_template(params
, template
, nparams
, pos
)
884 local op
= tonumber(sub(template
, 1, 8), 16)
888 parse_reg_type
= false
890 -- Process each character.
891 for p
in gmatch(sub(template
, 9), ".") do
894 op
= op
+ parse_reg(q
); n
= n
+ 1
896 op
= op
+ shl(parse_reg(q
), 5); n
= n
+ 1
898 op
= op
+ shl(parse_reg(q
), 16); n
= n
+ 1
900 op
= op
+ shl(parse_reg(q
), 10); n
= n
+ 1
902 op
= op
+ shl(parse_reg(params
[n
-1]), 16)
905 if q
== "sp" then params
[n
] = "@x31" end
907 if parse_reg_type
== "x" then
909 elseif parse_reg_type
~= "w" then
910 werror("bad register type")
912 parse_reg_type
= false
914 if parse_reg_type
== "d" then
916 elseif parse_reg_type
~= "s" then
917 werror("bad register type")
919 parse_reg_type
= false
920 elseif p
== "x" or p
== "w" or p
== "d" or p
== "s" then
921 if parse_reg_type
~= p
then
922 werror("register size mismatch")
924 parse_reg_type
= false
927 op
= parse_load(params
, nparams
, n
, op
)
929 op
= parse_load_pair(params
, nparams
, n
, op
)
932 local mode
, v
, s
= parse_label(q
, false); n
= n
+ 1
933 local m
= branch_type(op
)
934 waction("REL_"..mode
, v
+m
, s
, 1)
937 op
= op
+ parse_imm12(q
); n
= n
+ 1
939 op
= op
+ parse_imm13(q
); n
= n
+ 1
941 op
= op
+ parse_imm(q
, 16, 5, 0, false); n
= n
+ 1
943 op
= op
+ parse_imm6(q
); n
= n
+ 1
945 op
= op
+ parse_imm(q
, 6, 16, 0, false); n
= n
+ 1
947 op
= op
+ parse_imm(q
, 6, 10, 0, false); n
= n
+ 1
949 op
= op
+ parse_imm(q
, 5, 16, 0, false); n
= n
+ 1
951 op
= op
+ parse_imm(q
, 4, 0, 0, false); n
= n
+ 1
953 op
= op
+ parse_fpimm(q
); n
= n
+ 1
955 if q
~= "#0" and q
~= "#0.0" then werror("expected zero immediate") end
959 op
= op
+ parse_shift(q
); n
= n
+ 1
961 op
= op
+ parse_extend(q
); n
= n
+ 1
963 op
= op
+ parse_lslx16(q
); n
= n
+ 1
965 op
= op
+ parse_cond(q
, 0); n
= n
+ 1
967 op
= op
+ parse_cond(q
, 1); n
= n
+ 1
976 function op_template(params
, template
, nparams
)
977 if not params
then return template
:gsub("%x%x%x%x%x%x%x%x", "") end
979 -- Limit number of section buffer positions used by a single dasm_put().
980 -- A single opcode needs a maximum of 3 positions.
981 if secpos
+3 > maxsecpos
then wflush() end
983 local lpos
, apos
, spos
= #actlist
, #actargs
, secpos
986 for t
in gmatch(template
, "[^|]+") do
987 ok
, err
= pcall(parse_template
, params
, t
, nparams
, pos
)
988 if ok
then return end
990 actlist
[lpos
+1] = nil
991 actlist
[lpos
+2] = nil
992 actlist
[lpos
+3] = nil
993 actargs
[apos
+1] = nil
994 actargs
[apos
+2] = nil
995 actargs
[apos
+3] = nil
1000 map_op
[".template__"] = op_template
1002 ------------------------------------------------------------------------------
1004 -- Pseudo-opcode to mark the position where the action list is to be emitted.
1005 map_op
[".actionlist_1"] = function(params
)
1006 if not params
then return "cvar" end
1007 local name
= params
[1] -- No syntax check. You get to keep the pieces.
1008 wline(function(out
) writeactions(out
, name
) end)
1011 -- Pseudo-opcode to mark the position where the global enum is to be emitted.
1012 map_op
[".globals_1"] = function(params
)
1013 if not params
then return "prefix" end
1014 local prefix
= params
[1] -- No syntax check. You get to keep the pieces.
1015 wline(function(out
) writeglobals(out
, prefix
) end)
1018 -- Pseudo-opcode to mark the position where the global names are to be emitted.
1019 map_op
[".globalnames_1"] = function(params
)
1020 if not params
then return "cvar" end
1021 local name
= params
[1] -- No syntax check. You get to keep the pieces.
1022 wline(function(out
) writeglobalnames(out
, name
) end)
1025 -- Pseudo-opcode to mark the position where the extern names are to be emitted.
1026 map_op
[".externnames_1"] = function(params
)
1027 if not params
then return "cvar" end
1028 local name
= params
[1] -- No syntax check. You get to keep the pieces.
1029 wline(function(out
) writeexternnames(out
, name
) end)
1032 ------------------------------------------------------------------------------
1034 -- Label pseudo-opcode (converted from trailing colon form).
1035 map_op
[".label_1"] = function(params
)
1036 if not params
then return "[1-9] | ->global | =>pcexpr" end
1037 if secpos
+1 > maxsecpos
then wflush() end
1038 local mode
, n
, s
= parse_label(params
[1], true)
1039 if mode
== "EXT" then werror("bad label definition") end
1040 waction("LABEL_"..mode
, n
, s
, 1)
1043 ------------------------------------------------------------------------------
1045 -- Pseudo-opcodes for data storage.
1046 map_op
[".long_*"] = function(params
)
1047 if not params
then return "imm..." end
1048 for _
,p
in ipairs(params
) do
1049 local n
= tonumber(p
)
1050 if not n
then werror("bad immediate `"..p
.."'") end
1051 if n
< 0 then n
= n
+ 2^
32 end
1053 if secpos
+2 > maxsecpos
then wflush() end
1057 -- Alignment pseudo-opcode.
1058 map_op
[".align_1"] = function(params
)
1059 if not params
then return "numpow2" end
1060 if secpos
+1 > maxsecpos
then wflush() end
1061 local align
= tonumber(params
[1])
1064 -- Must be a power of 2 in the range (2 ... 256).
1068 waction("ALIGN", align
-1, nil, 1) -- Action byte is 2**n-1.
1073 werror("bad alignment")
1076 ------------------------------------------------------------------------------
1078 -- Pseudo-opcode for (primitive) type definitions (map to C types).
1079 map_op
[".type_3"] = function(params
, nparams
)
1081 return nparams
== 2 and "name, ctype" or "name, ctype, reg"
1083 local name
, ctype
, reg
= params
[1], params
[2], params
[3]
1084 if not match(name
, "^[%a_][%w_]*$") then
1085 werror("bad type name `"..name
.."'")
1087 local tp
= map_type
[name
]
1089 werror("duplicate type `"..name
.."'")
1091 -- Add #type to defines. A bit unclean to put it in map_archdef.
1092 map_archdef
["#"..name
] = "sizeof("..ctype
..")"
1093 -- Add new type and emit shortcut define.
1094 local num
= ctypenum
+ 1
1097 ctypefmt
= format("Dt%X(%%s)", num
),
1100 wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num
, ctype
))
1103 map_op
[".type_2"] = map_op
[".type_3"]
1105 -- Dump type definitions.
1106 local function dumptypes(out
, lvl
)
1108 for name
in pairs(map_type
) do t
[#t
+1] = name
end
1110 out
:write("Type definitions:\n")
1111 for _
,name
in ipairs(t
) do
1112 local tp
= map_type
[name
]
1113 local reg
= tp
.reg
or ""
1114 out
:write(format(" %-20s %-20s %s\n", name
, tp
.ctype
, reg
))
1119 ------------------------------------------------------------------------------
1121 -- Set the current section.
1122 function _M
.section(num
)
1123 waction("SECTION", num
)
1124 wflush(true) -- SECTION is a terminal action.
1127 ------------------------------------------------------------------------------
1129 -- Dump architecture description.
1130 function _M
.dumparch(out
)
1131 out
:write(format("DynASM %s version %s, released %s\n\n",
1132 _info
.arch
, _info
.version
, _info
.release
))
1136 -- Dump all user defined elements.
1137 function _M
.dumpdef(out
, lvl
)
1139 dumpglobals(out
, lvl
)
1140 dumpexterns(out
, lvl
)
1143 ------------------------------------------------------------------------------
1145 -- Pass callbacks from/to the DynASM core.
1146 function _M
.passcb(wl
, we
, wf
, ww
)
1147 wline
, werror
, wfatal
, wwarn
= wl
, we
, wf
, ww
1151 -- Setup the arch-specific module.
1152 function _M
.setup(arch
, opt
)
1153 g_arch
, g_opt
= arch
, opt
1156 -- Merge the core maps and the arch-specific maps.
1157 function _M
.mergemaps(map_coreop
, map_def
)
1158 setmetatable(map_op
, { __index
= map_coreop
})
1159 setmetatable(map_def
, { __index
= map_archdef
})
1160 return map_op
, map_def
1165 ------------------------------------------------------------------------------