------------------------------------------------------------------------------ -- DynASM s390x module. -- -- Copyright (C) 2005-2016 Mike Pall. All rights reserved. -- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------ -- Module information: local _info = { arch = "s390x", description = "DynASM s390x module", version = "1.4.0", vernum = 10400, release = "2015-10-18", author = "Mike Pall", license = "MIT", } -- Exported glue functions for the arch-specific module. local _M = { _info = _info } -- Cache library functions. local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs local assert, setmetatable, rawget = assert, setmetatable, rawget local _s = string local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub local concat, sort, insert = table.concat, table.sort, table.insert local bit = bit or require("bit") local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift local ror, tohex = bit.ror, bit.tohex -- Inherited tables and callbacks. local g_opt, g_arch local wline, werror, wfatal, wwarn -- Action name list. -- CHECK: Keep this in sync with the C code! local action_names = { "STOP", "SECTION", "ESC", "REL_EXT", "ALIGN", "REL_LG", "LABEL_LG", "REL_PC", "LABEL_PC", "IMM", "IMM6", "IMM12", "IMM13W", "IMM13X", "IMML", } -- Maximum number of section buffer positions for dasm_put(). -- CHECK: Keep this in sync with the C code! local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. -- Action name -> action number. local map_action = {} for n,name in ipairs(action_names) do map_action[name] = n-1 end -- Action list buffer. local actlist = {} -- Argument list for next dasm_put(). Start with offset 0 into action list. local actargs = { 0 } -- Current number of section buffer positions for dasm_put(). local secpos = 1 ------------------------------------------------------------------------------ -- Dump action names and numbers. local function dumpactions(out) out:write("DynASM encoding engine action codes:\n") for n,name in ipairs(action_names) do local num = map_action[name] out:write(format(" %-10s %02X %d\n", name, num, num)) end out:write("\n") end -- Write action list buffer as a huge static C array. local function writeactions(out, name) local nn = #actlist if nn == 0 then nn = 1; actlist[0] = map_action.STOP end out:write("static const unsigned int ", name, "[", nn, "] = {\n") for i = 1,nn-1 do assert(out:write("0x", tohex(actlist[i]), ",\n")) end assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) end ------------------------------------------------------------------------------ -- Add word to action list. local function wputxw(n) assert(n >= 0 and n <= 0xffffffffffff and n % 1 == 0, "word out of range") -- s390x inst can be 6 bytes actlist[#actlist+1] = n end -- Add action to list with optional arg. Advance buffer pos, too. local function waction(action, val, a, num) local w = assert(map_action[action], "bad action name `"..action.."'") wputxw(w * 0x10000 + (val or 0)) if a then actargs[#actargs+1] = a end if a or num then secpos = secpos + (num or 1) end end -- Flush action list (intervening C code or buffer pos overflow). local function wflush(term) if #actlist == actargs[1] then return end -- Nothing to flush. if not term then waction("STOP") end -- Terminate action list. wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). secpos = 1 -- The actionlist offset occupies a buffer position, too. end -- Put escaped word. --Need to check this as well, not sure how it will work on s390x local function wputw(n) if n <= 0x000fffff then waction("ESC") end wputxw(n) end -- Reserve position for word. local function wpos() local pos = #actlist+1 actlist[pos] = "" return pos end -- Store word to reserved position. -- added 2 bytes more since s390x has 6 bytes inst as well local function wputpos(pos, n) assert(n >= 0 and n <= 0xffffffffffff and n % 1 == 0, "word out of range") if n <= 0x000fffff then insert(actlist, pos+1, n) n = map_action.ESC * 0x10000 end actlist[pos] = n end ------------------------------------------------------------------------------ -- Global label name -> global label number. With auto assignment on 1st use. local next_global = 20 local map_global = setmetatable({}, { __index = function(t, name) if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end local n = next_global if n > 2047 then werror("too many global labels") end next_global = n + 1 t[name] = n return n end}) -- Dump global labels. local function dumpglobals(out, lvl) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("Global labels:\n") for i=20,next_global-1 do out:write(format(" %s\n", t[i])) end out:write("\n") end -- Write global label enum. local function writeglobals(out, prefix) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("enum {\n") for i=20,next_global-1 do out:write(" ", prefix, t[i], ",\n") end out:write(" ", prefix, "_MAX\n};\n") end -- Write global label names. local function writeglobalnames(out, name) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("static const char *const ", name, "[] = {\n") for i=20,next_global-1 do out:write(" \"", t[i], "\",\n") end out:write(" (const char *)0\n};\n") end ------------------------------------------------------------------------------ -- Extern label name -> extern label number. With auto assignment on 1st use. local next_extern = 0 local map_extern_ = {} local map_extern = setmetatable({}, { __index = function(t, name) -- No restrictions on the name for now. local n = next_extern if n > 2047 then werror("too many extern labels") end next_extern = n + 1 t[name] = n map_extern_[n] = name return n end}) -- Dump extern labels. local function dumpexterns(out, lvl) out:write("Extern labels:\n") for i=0,next_extern-1 do out:write(format(" %s\n", map_extern_[i])) end out:write("\n") end -- Write extern label names. local function writeexternnames(out, name) out:write("static const char *const ", name, "[] = {\n") for i=0,next_extern-1 do out:write(" \"", map_extern_[i], "\",\n") end out:write(" (const char *)0\n};\n") end ------------------------------------------------------------------------------ -- Arch-specific maps. -- TODO: add s390x related register names -- Ext. register name -> int. name. --local map_archdef = { xzr = "@x31", wzr = "@w31", lr = "x30", } local map_archdef = {} -- Int. register name -> ext. name. -- local map_reg_rev = { ["@x31"] = "xzr", ["@w31"] = "wzr", x30 = "lr", } local map_reg_rev = {} local map_type = {} -- Type name -> { ctype, reg } local ctypenum = 0 -- Type number (for Dt... macros). -- Reverse defines for registers. function _M.revdef(s) return map_reg_rev[s] or s end -- not sure of these local map_shift = { lsl = 0, lsr = 1, asr = 2, } local map_extend = { uxtb = 0, uxth = 1, uxtw = 2, uxtx = 3, sxtb = 4, sxth = 5, sxtw = 6, sxtx = 7, } local map_cond = { o = 1, h = 2, hle = 3, l = 4, nhe = 5, lh = 6, ne = 7, e = 8, nlh = 9, he = 10, nl = 11, le = 12, nh = 13, no = 14, [""] = 15, } ------------------------------------------------------------------------------ local parse_reg_type local function parse_gpr(expr) -- assuming we get r0-r31 for now local r = match(expr, "^r([1-3]?[0-9])$") if r then r = tonumber(r) if r <= 31 then return r, tp end end werror("bad register name `"..expr.."'") end local function parse_fpr(expr) local r = match(expr, "^f([1-3]?[0-9])$") if r then r = tonumber(r) if r <= 31 then return r end end werror("bad register name `"..expr.."'") end local function parse_reg_base(expr) if expr == "sp" then return 0x3e0 end local base, tp = parse_reg(expr) if parse_reg_type ~= "x" then werror("bad register type") end parse_reg_type = false return shl(base, 5), tp -- why is it shifted not able to make out end local parse_ctx = {} local loadenv = setfenv and function(s) local code = loadstring(s, "") if code then setfenv(code, parse_ctx) end return code end or function(s) return load(s, "", nil, parse_ctx) end -- Try to parse simple arithmetic, too, since some basic ops are aliases. local function parse_number(n) local x = tonumber(n) if x then return x end local code = loadenv("return "..n) if code then local ok, y = pcall(code) if ok then return y end end return nil end local function parse_imm(imm, bits, shift, scale, signed) imm = match(imm, "^#(.*)$") if not imm then werror("expected immediate operand") end local n = parse_number(imm) if n then local m = sar(n, scale) if shl(m, scale) == n then if signed then local s = sar(m, bits-1) if s == 0 then return shl(m, shift) elseif s == -1 then return shl(m + shl(1, bits), shift) end else if sar(m, bits) == 0 then return shl(m, shift) end end end werror("out of range immediate `"..imm.."'") else waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) return 0 end end local function parse_imm12(imm) imm = match(imm, "^#(.*)$") if not imm then werror("expected immediate operand") end local n = parse_number(imm) if n then if shr(n, 12) == 0 then return shl(n, 10) elseif band(n, 0xff000fff) == 0 then return shr(n, 2) + 0x00400000 end werror("out of range immediate `"..imm.."'") else waction("IMM12", 0, imm) return 0 end end local function parse_imm13(imm) imm = match(imm, "^#(.*)$") if not imm then werror("expected immediate operand") end local n = parse_number(imm) local r64 = parse_reg_type == "x" if n and n % 1 == 0 and n >= 0 and n <= 0xffffffff then local inv = false if band(n, 1) == 1 then n = bit.bnot(n); inv = true end local t = {} for i=1,32 do t[i] = band(n, 1); n = shr(n, 1) end local b = table.concat(t) b = b..(r64 and (inv and "1" or "0"):rep(32) or b) local p0, p1, p0a, p1a = b:match("^(0+)(1+)(0*)(1*)") if p0 then local w = p1a == "" and (r64 and 64 or 32) or #p1+#p0a if band(w, w-1) == 0 and b == b:sub(1, w):rep(64/w) then local s = band(-2*w, 0x3f) - 1 if w == 64 then s = s + 0x1000 end if inv then return shl(w-#p1-#p0, 16) + shl(s+w-#p1, 10) else return shl(w-#p0, 16) + shl(s+#p1, 10) end end end werror("out of range immediate `"..imm.."'") elseif r64 then waction("IMM13X", 0, format("(unsigned int)(%s)", imm)) actargs[#actargs+1] = format("(unsigned int)((unsigned long long)(%s)>>32)", imm) return 0 else waction("IMM13W", 0, imm) return 0 end end local function parse_imm6(imm) imm = match(imm, "^#(.*)$") if not imm then werror("expected immediate operand") end local n = parse_number(imm) if n then if n >= 0 and n <= 63 then return shl(band(n, 0x1f), 19) + (n >= 32 and 0x80000000 or 0) end werror("out of range immediate `"..imm.."'") else waction("IMM6", 0, imm) return 0 end end local function parse_imm_load(imm, scale) local n = parse_number(imm) if n then local m = sar(n, scale) if shl(m, scale) == n and m >= 0 and m < 0x1000 then return shl(m, 10) + 0x01000000 -- Scaled, unsigned 12 bit offset. elseif n >= -256 and n < 256 then return shl(band(n, 511), 12) -- Unscaled, signed 9 bit offset. end werror("out of range immediate `"..imm.."'") else waction("IMML", 0, imm) return 0 end end local function parse_fpimm(imm) imm = match(imm, "^#(.*)$") if not imm then werror("expected immediate operand") end local n = parse_number(imm) if n then local m, e = math.frexp(n) local s, e2 = 0, band(e-2, 7) if m < 0 then m = -m; s = 0x00100000 end m = m*32-16 if m % 1 == 0 and m >= 0 and m <= 15 and sar(shl(e2, 29), 29)+2 == e then return s + shl(e2, 17) + shl(m, 13) end werror("out of range immediate `"..imm.."'") else werror("NYI fpimm action") end end local function parse_shift(expr) local s, s2 = match(expr, "^(%S+)%s*(.*)$") s = map_shift[s] if not s then werror("expected shift operand") end return parse_imm(s2, 6, 10, 0, false) + shl(s, 22) end local function parse_lslx16(expr) local n = match(expr, "^lsl%s*#(%d+)$") n = tonumber(n) if not n then werror("expected shift operand") end if band(n, parse_reg_type == "x" and 0xffffffcf or 0xffffffef) ~= 0 then werror("bad shift amount") end return shl(n, 17) end local function parse_extend(expr) local s, s2 = match(expr, "^(%S+)%s*(.*)$") if s == "lsl" then s = parse_reg_type == "x" and 3 or 2 else s = map_extend[s] end if not s then werror("expected extend operand") end return (s2 == "" and 0 or parse_imm(s2, 3, 10, 0, false)) + shl(s, 13) end local function parse_cond(expr, inv) local c = map_cond[expr] if not c then werror("expected condition operand") end return shl(bit.bxor(c, inv), 12) end local function parse_load(params, nparams, n, op) if params[n+2] then werror("too many operands") end local pn, p2 = params[n], params[n+1] local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") if not p1 then if not p2 then local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") if reg and tailr ~= "" then local base, tp = parse_reg_base(reg) if tp then waction("IMML", 0, format(tp.ctypefmt, tailr)) return op + base end end end werror("expected address operand") end local scale = shr(op, 30) if p2 then if wb == "!" then werror("bad use of '!'") end op = op + parse_reg_base(p1) + parse_imm(p2, 9, 12, 0, true) + 0x400 elseif wb == "!" then local p1a, p2a = match(p1, "^([^,%s]*)%s*,%s*(.*)$") if not p1a then werror("bad use of '!'") end op = op + parse_reg_base(p1a) + parse_imm(p2a, 9, 12, 0, true) + 0xc00 else local p1a, p2a = match(p1, "^([^,%s]*)%s*(.*)$") op = op + parse_reg_base(p1a) if p2a ~= "" then local imm = match(p2a, "^,%s*#(.*)$") if imm then op = op + parse_imm_load(imm, scale) else local p2b, p3b, p3s = match(p2a, "^,%s*([^,%s]*)%s*,?%s*(%S*)%s*(.*)$") op = op + shl(parse_reg(p2b), 16) + 0x00200800 if parse_reg_type ~= "x" and parse_reg_type ~= "w" then werror("bad index register type") end if p3b == "" then if parse_reg_type ~= "x" then werror("bad index register type") end op = op + 0x6000 else if p3s == "" or p3s == "#0" then elseif p3s == "#"..scale then op = op + 0x1000 else werror("bad scale") end if parse_reg_type == "x" then if p3b == "lsl" and p3s ~= "" then op = op + 0x6000 elseif p3b == "sxtx" then op = op + 0xe000 else werror("bad extend/shift specifier") end else if p3b == "uxtw" then op = op + 0x4000 elseif p3b == "sxtw" then op = op + 0xc000 else werror("bad extend/shift specifier") end end end end else if wb == "!" then werror("bad use of '!'") end op = op + 0x01000000 end end return op end local function parse_load_pair(params, nparams, n, op) if params[n+2] then werror("too many operands") end local pn, p2 = params[n], params[n+1] local scale = shr(op, 30) == 0 and 2 or 3 local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") if not p1 then if not p2 then local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") if reg and tailr ~= "" then local base, tp = parse_reg_base(reg) if tp then waction("IMM", 32768+7*32+15+scale*1024, format(tp.ctypefmt, tailr)) return op + base + 0x01000000 end end end werror("expected address operand") end if p2 then if wb == "!" then werror("bad use of '!'") end op = op + 0x00800000 else local p1a, p2a = match(p1, "^([^,%s]*)%s*,%s*(.*)$") if p1a then p1, p2 = p1a, p2a else p2 = "#0" end op = op + (wb == "!" and 0x01800000 or 0x01000000) end return op + parse_reg_base(p1) + parse_imm(p2, 7, 15, scale, true) end local function parse_label(label, def) local prefix = sub(label, 1, 2) -- =>label (pc label reference) if prefix == "=>" then return "PC", 0, sub(label, 3) end -- ->name (global label reference) if prefix == "->" then return "LG", map_global[sub(label, 3)] end if def then -- [1-9] (local label definition) if match(label, "^[1-9]$") then return "LG", 10+tonumber(label) end else -- [<>][1-9] (local label reference) local dir, lnum = match(label, "^([<>])([1-9])$") if dir then -- Fwd: 1-9, Bkwd: 11-19. return "LG", lnum + (dir == ">" and 0 or 10) end -- extern label (extern label reference) local extname = match(label, "^extern%s+(%S+)$") if extname then return "EXT", map_extern[extname] end end werror("bad label `"..label.."'") end local function branch_type(op) if band(op, 0x7c000000) == 0x14000000 then return 0 -- B, BL elseif shr(op, 24) == 0x54 or band(op, 0x7e000000) == 0x34000000 or band(op, 0x3b000000) == 0x18000000 then return 0x800 -- B.cond, CBZ, CBNZ, LDR* literal elseif band(op, 0x7e000000) == 0x36000000 then return 0x1000 -- TBZ, TBNZ elseif band(op, 0x9f000000) == 0x10000000 then return 0x2000 -- ADR elseif band(op, 0x9f000000) == band(0x90000000) then return 0x3000 -- ADRP else assert(false, "unknown branch type") end end ------------------------------------------------------------------------------ local map_op, op_template local function op_alias(opname, f) return function(params, nparams) if not params then return "-> "..opname:sub(1, -3) end f(params, nparams) op_template(params, map_op[opname], nparams) end end local function alias_bfx(p) p[4] = "#("..p[3]:sub(2)..")+("..p[4]:sub(2)..")-1" end local function alias_bfiz(p) parse_reg(p[1]) if parse_reg_type == "w" then p[3] = "#-("..p[3]:sub(2)..")%32" p[4] = "#("..p[4]:sub(2)..")-1" else p[3] = "#-("..p[3]:sub(2)..")%64" p[4] = "#("..p[4]:sub(2)..")-1" end end local alias_lslimm = op_alias("ubfm_4", function(p) parse_reg(p[1]) local sh = p[3]:sub(2) if parse_reg_type == "w" then p[3] = "#-("..sh..")%32" p[4] = "#31-("..sh..")" else p[3] = "#-("..sh..")%64" p[4] = "#63-("..sh..")" end end) -- Template strings for s390x instructions. map_op = { a_4 = "000000005a000000j", ar_2 = "0000000000001a00g", ay_5 = "0000e3000000005al", ag_5 = "0000e30000000008l", agr_2 = "00000000b9080000h", agf_5 = "0000e30000000018l", agfr_2 = "00000000b9180000h", axbr_2 = "00000000b34a0000h", adbr_2 = "00000000b31a0000h", aebr_2 = "00000000b30a0000h", ah_4 = "000000004a000000j", ahy_5 = "0000e3000000007al", afi_3 = "0000c20900000000n", agfi_3 = "0000c20800000000n", aih_3 = "0000cc0800000000n", al_4 = "000000005e000000j", alr_2 = "0000000000001e00g", aly_5 = "0000e3000000005el", alg_5 = "0000e3000000000al", algr_2 = "00000000b90a0000h", algf_5 = "0000e3000000001al", algfr_2 = "00000000b91a0000h", alfi_3 = "0000c20b00000000n", algfi_3 = "0000c20a00000000n", alc_5 = "0000e30000000098l", alcr_2 = "00000000b9980000h", alcg_5 = "0000e30000000088l", alcgr_2 = "00000000b9880000h", alsih_3 = "0000cc0a00000000n", alsihn_3 = "0000cc0b00000000n", axr_2 = "0000000000003600g", ad_4 = "000000006a000000j", adr_2 = "0000000000002a00g", ae_4 = "000000007a000000j", aer_2 = "0000000000003a00g", aw_4 = "000000006e000000j", awr_2 = "0000000000002e00g", au_4 = "000000007e000000j", aur_2 = "0000000000003e00g", n_4 = "0000000054000000j", nr_2 = "0000000000001400g", ny_5 = "0000e30000000054l", ng_5 = "0000e30000000080l", ngr_2 = "00000000b9800000h", nihf_3 = "0000c00a00000000n", nilf_3 = "0000c00b00000000n", bal_4 = "0000000045000000j", balr_2 = "000000000000500g", bas_4 = "000000004d000000j", basr_2 = "0000000000000d00g", bassm_2 = "0000000000000c00g", bsa_2 = "00000000b25a0000h", bsm_2 = "0000000000000b00g", bakr_2 = "00000000b2400000h", bsg_2 = "00000000b2580000h", bc_4 = "0000000047000000k", bcr_2 = "000000000000700g", bct_4 = "0000000046000000j", bctr_2 = "000000000000600g", bctg_5 = "0000e30000000046l", bctgr_2 = "00000000b9460000h", bxh_4 = "0000000086000000q", bxhg_5 = "0000eb0000000044s", bxle_4 = "0000000087000000q", bxleg_5 = "0000eb0000000045s", brasl_3 = "0000c00500000000o", brcl_3 = "0000c00400000000p", brcth_3 = "0000cc0600000000o", cksm_2 = "00000000b2410000h", km_2 = "00000000b92e0000h", kmf_2 = "00000000b92a0000h", kmc_2 = "00000000b92f0000h", kmo_2 = "00000000b92b0000h", c_4 = "0000000059000000j", cr_2 = "0000000000001900g", cy_5 = "0000e30000000059l", cg_5 = "0000e30000000020l", cgr_2 = "00000000b9200000h", cgf_5 = "0000e30000000030l", cgfr_2 = "00000000b9300000h", cxbr_2 = "00000000b3490000h", cxtr_2 = "00000000b3ec0000h", cxr_2 = "00000000b3690000h", cdbr_2 = "00000000b3190000h", cdtr_2 = "00000000b3e40000h", cd_4 = "0000000069000000j", cdr_2 = "0000000000002900g", cebr_2 = "00000000b3090000h", ce_4 = "0000000079000000j", cer_2 = "0000000000003900g", kxbr_2 = "00000000b3480000h", kxtr_2 = "00000000b3e80000h", kdbr_2 = "00000000b3180000h", kdtr_2 = "00000000b3e00000h", kebr_2 = "00000000b3080000h", cs_4 = "00000000ba000000q", csy_5 = "0000eb0000000014s", csg_5 = "0000eb0000000030s", csp_2 = "00000000b2500000h", cspg_2 = "00000000b98a0000h", cextr_2 = "00000000b3fc0000h", cedtr_2 = "00000000b3f40000h", cds_4 = "00000000bb000000q", cdsy_5 = "0000eb0000000031s", cdsg_5 = "0000eb000000003es", ch_4 = "0000000049000000j", chy_5 = "0000e30000000079l", cgh_5 = "0000e30000000034l", chrl_3 = "0000c60500000000o", cghrl_3 = "0000c60400000000o", chf_5 = "0000e300000000cdl", chhr_2 = "00000000b9cd0000h", chlr_2 = "00000000b9dd0000h", cfi_3 = "0000c20d00000000n", cgfi_3 = "0000c20c00000000n", cih_3 = "0000cc0d00000000n", cl_4 = "0000000055000000j", clr_2 = "0000000000001500g", cly_5 = "0000e30000000055l", clg_5 = "0000e30000000021l", clgr_2 = "00000000b9210000h", clgf_5 = "0000e30000000031l", clgfr_2 = "00000000b9310000h", clmh_5 = "0000eb0000000020t", clm_4 = "00000000bd000000r", clmy_5 = "0000eb0000000021t", clhf_5 = "0000e300000000cfl", clhhr_2 = "00000000b9cf0000h", clhlr_2 = "00000000b9df0000h", clfi_3 = "0000c20f00000000n", clgfi_3 = "0000c20e00000000n", clih_3 = "0000cc0f00000000n", clcl_2 = "0000000000000f00g", clcle_4 = "00000000a9000000q", clclu_5 = "0000eb000000008fs", clrl_3 = "0000c60f00000000o", clhrl_3 = "0000c60700000000o", clgrl_3 = "0000c60a00000000o", clghrl_3 = "0000c60600000000o", clgfrl_3 = "0000c60e00000000o", clst_2 = "00000000b25d0000h", crl_3 = "0000c60d00000000o", cgrl_3 = "0000c60800000000o", cgfrl_3 = "0000c60c00000000o", cuse_2 = "00000000b2570000h", cmpsc_2 = "00000000b2630000h", kimd_2 = "00000000b93e0000h", klmd_2 = "00000000b93f0000h", kmac_2 = "00000000b91e0000h", thdr_2 = "00000000b3590000h", thder_2 = "00000000b3580000h", cxfbr_2 = "00000000b3960000h", cxftr_2 = "00000000b9590000h", cxfr_2 = "00000000b3b60000h", cdfbr_2 = "00000000b3950000h", cdftr_2 = "00000000b9510000h", cdfr_2 = "00000000b3b50000h", cefbr_2 = "00000000b3940000h", cefr_2 = "00000000b3b40000h", cxgbr_2 = "00000000b3a60000h", cxgtr_2 = "00000000b3f90000h", cxgr_2 = "00000000b3c60000h", cdgbr_2 = "00000000b3a50000h", cdgtr_2 = "00000000b3f10000h", cdgr_2 = "00000000b3c50000h", cegbr_2 = "00000000b3a40000h", cegr_2 = "00000000b3c40000h", cxstr_2 = "00000000b3fb0000h", cdstr_2 = "00000000b3f30000h", cxutr_2 = "00000000b3fa0000h", cdutr_2 = "00000000b3f20000h", cvb_4 = "000000004f000000j", cvby_5 = "0000e30000000006l", cvbg_5 = "0000e3000000000el", cvd_4 = "000000004e000000j", cvdy_5 = "0000e30000000026l", cvdg_5 = "0000e3000000002el", cuxtr_2 = "00000000b3ea0000h", cudtr_2 = "00000000b3e20000h", cu42_2 = "00000000b9b30000h", cu41_2 = "00000000b9b20000h", cpya_2 = "00000000b24d0000h", d_4 = "000000005d000000j", dr_2 = "0000000000001d00g", dxbr_2 = "00000000b34d0000h", dxr_2 = "00000000b22d0000h", ddbr_2 = "00000000b31d0000h", dd_4 = "000000006d000000j", ddr_2 = "0000000000002d00g", debr_2 = "00000000b30d0000h", de_4 = "000000007d000000j", der_2 = "0000000000003d00g", dl_5 = "0000e30000000097l", dlr_2 = "00000000b9970000h", dlg_5 = "0000e30000000087l", dlgr_2 = "00000000b9870000h", dsg_5 = "0000e3000000000dl", dsgr_2 = "00000000b90d0000h", dsgf_5 = "0000e3000000001dl", dsgfr_2 = "00000000b91d0000h", x_4 = "0000000057000000j", xr_2 = "0000000000001700g", xy_5 = "0000e30000000057l", xg_5 = "0000e30000000082l", xgr_2 = "00000000b9820000h", xihf_3 = "0000c00600000000n", xilf_3 = "0000c00700000000n", ex_4 = "0000000044000000j", exrl_3 = "0000c60000000000o", ear_2 = "00000000b24f0000h", esea_2 = "00000000b99d0000h", eextr_2 = "00000000b3ed0000h", eedtr_2 = "00000000b3e50000h", ecag_5 = "0000eb000000004cs", efpc_2 = "00000000b38c0000h", epar_2 = "00000000b2260000h", epair_2 = "00000000b99a0000h", epsw_2 = "00000000b98d0000h", esar_2 = "00000000b2270000h", esair_2 = "00000000b99b0000h", esxtr_2 = "00000000b3ef0000h", esdtr_2 = "00000000b3e70000h", ereg_2 = "00000000b2490000h", eregg_2 = "00000000b90e0000h", esta_2 = "00000000b24a0000h", flogr_2 = "00000000b9830000h", hdr_2 = "0000000000002400g", her_2 = "0000000000003400g", iac_2 = "00000000b2240000h", ic_4 = "0000000043000000j", icy_5 = "0000e30000000073l", icmh_5 = "0000eb0000000080t", icm_4 = "00000000bf000000r", icmy_5 = "0000eb0000000081t", iihf_3 = "0000c00800000000n", iilf_3 = "0000c00900000000n", ipm_2 = "00000000b2220000h", iske_2 = "00000000b2290000h", ivsk_2 = "00000000b2230000h", l_4 = "0000000058000000j", lr_2 = "0000000000001800g", ly_5 = "0000e30000000058l", lg_5 = "0000e30000000004l", lgr_2 = "00000000b9040000h", lgf_5 = "0000e30000000014l", lgfr_2 = "00000000b9140000h", lxr_2 = "00000000b3650000h", ld_4 = "0000000068000000j", ldr_2 = "0000000000002800g", ldy_5 = "0000ed0000000065l", le_4 = "0000000078000000j", ler_2 = "0000000000003800g", ley_5 = "0000ed0000000064l", lam_4 = "000000009a000000q", lamy_5 = "0000eb000000009as", la_4 = "0000000041000000j", lay_5 = "0000e30000000071l", lae_4 = "0000000051000000j", laey_5 = "0000e30000000075l", larl_3 = "0000c00000000000o", laa_5 = "0000eb00000000f8s", laag_5 = "0000eb00000000e8s", laal_5 = "0000eb00000000fas", laalg_5 = "0000eb00000000eas", lan_5 = "0000eb00000000f4s", lang_5 = "0000eb00000000e4s", lax_5 = "0000eb00000000f7s", laxg_5 = "0000eb00000000e7s", lao_5 = "0000eb00000000f6s", laog_5 = "0000eb00000000e6s", lt_5 = "0000e30000000012l", ltr_2 = "0000000000001200g", ltg_5 = "0000e30000000002l", ltgr_2 = "00000000b9020000h", ltgf_5 = "0000e30000000032l", ltgfr_2 = "00000000b9120000h", ltxbr_2 = "00000000b3420000h", ltxtr_2 = "00000000b3de0000h", ltxr_2 = "00000000b3620000h", ltdbr_2 = "00000000b3120000h", ltdtr_2 = "00000000b3d60000h", ltdr_2 = "0000000000002200g", ltebr_2 = "00000000b3020000h", lter_2 = "0000000000003200g", lb_5 = "0000e30000000076l", lbr_2 = "00000000b9260000h", lgb_5 = "0000e30000000077l", lgbr_2 = "00000000b9060000h", lbh_5 = "0000e300000000c0l", lcr_2 = "0000000000001300g", lcgr_2 = "00000000b9030000h", lcgfr_2 = "00000000b9130000h", lcxbr_2 = "00000000b3430000h", lcxr_2 = "00000000b3630000h", lcdbr_2 = "00000000b3130000h", lcdr_2 = "0000000000002300g", lcdfr_2 = "00000000b3730000h", lcebr_2 = "00000000b3030000h", lcer_2 = "0000000000003300g", lctl_4 = "00000000b7000000q", lctlg_5 = "0000eb000000002fs", fixr_2 = "00000000b3670000h", fidr_2 = "00000000b37f0000h", fier_2 = "00000000b3770000h", ldgr_2 = "00000000b3c10000h", lgdr_2 = "00000000b3cd0000h", lh_4 = "0000000048000000j", lhr_2 = "00000000b9270000h", lhy_5 = "0000e30000000078l", lgh_5 = "0000e30000000015l", lghr_2 = "00000000b9070000h", lhh_5 = "0000e300000000c4l", lhrl_3 = "0000c40500000000o", lghrl_3 = "0000c40400000000o", lfh_5 = "0000e300000000cal", lgfi_3 = "0000c00100000000n", lxdbr_2 = "00000000b3050000h", lxdr_2 = "00000000b3250000h", lxebr_2 = "00000000b3060000h", lxer_2 = "00000000b3260000h", ldebr_2 = "00000000b3040000h", lder_2 = "00000000b3240000h", llgf_5 = "0000e30000000016l", llgfr_2 = "00000000b9160000h", llc_5 = "0000e30000000094l", llcr_2 = "00000000b9940000h", llgc_5 = "0000e30000000090l", llgcr_2 = "00000000b9840000h", llch_5 = "0000e300000000c2l", llh_5 = "0000e30000000095l", llhr_2 = "00000000b9950000h", llgh_5 = "0000e30000000091l", llghr_2 = "00000000b9850000h", llhh_5 = "0000e300000000c6l", llhrl_3 = "0000c40200000000o", llghrl_3 = "0000c40600000000o", llihf_3 = "0000c00e00000000n", llilf_3 = "0000c00f00000000n", llgfrl_3 = "0000c40e00000000o", llgt_5 = "0000e30000000017l", llgtr_2 = "00000000b9170000h", lm_4 = "0000000098000000q", lmy_5 = "0000eb0000000098s", lmg_5 = "0000eb0000000004s", lmh_5 = "0000eb0000000096s", lnr_2 = "0000000000001100g", lngr_2 = "00000000b9010000h", lngfr_2 = "00000000b9110000h", lnxbr_2 = "00000000b3410000h", lnxr_2 = "00000000b3610000h", lndbr_2 = "00000000b3110000h", lndr_2 = "0000000000002100g", lndfr_2 = "00000000b3710000h", lnebr_2 = "00000000b3010000h", lner_2 = "0000000000003100g", loc_5 = "0000eb00000000f2t", locg_5 = "0000eb00000000e2t", lpq_5 = "0000e3000000008fl", lpr_2 = "0000000000001000g", lpgr_2 = "00000000b9000000h", lpgfr_2 = "00000000b9100000h", lpxbr_2 = "00000000b3400000h", lpxr_2 = "00000000b3600000h", lpdbr_2 = "00000000b3100000h", lpdr_2 = "0000000000002000g", lpdfr_2 = "00000000b3700000h", lpebr_2 = "00000000b3000000h", lper_2 = "0000000000003000g", lra_4 = "00000000b1000000j", lray_5 = "0000e30000000013l", lrag_5 = "0000e30000000003l", lrl_3 = "0000c40d00000000o", lgrl_3 = "0000c40800000000o", lgfrl_3 = "0000c40c00000000o", lrvh_5 = "0000e3000000001fl", lrv_5 = "0000e3000000001el", lrvr_2 = "00000000b91f0000h", lrvg_5 = "0000e3000000000fl", lrvgr_2 = "00000000b90f0000h", ldxbr_2 = "00000000b3450000h", ldxr_2 = "0000000000002500g", lrdr_2 = "0000000000002500g", lexbr_2 = "00000000b3460000h", lexr_2 = "00000000b3660000h", ledbr_2 = "00000000b3440000h", ledr_2 = "0000000000003500g", lrer_2 = "0000000000003500g", lura_2 = "00000000b24b0000h", lurag_2 = "00000000b9050000h", lzxr_2 = "00000000b3760000h", lzdr_2 = "00000000b3750000h", lzer_2 = "00000000b3740000h", msta_2 = "00000000b2470000h", mvcl_2 = "0000000000000e00g", mvcle_4 = "00000000a8000000q", mvclu_5 = "0000eb000000008es", mvpg_2 = "00000000b2540000h", mvst_2 = "00000000b2550000h", m_4 = "000000005c000000j", mfy_5 = "0000e3000000005cl", mr_2 = "0000000000001c00g", mxbr_2 = "00000000b34c0000h", mxr_2 = "0000000000002600g", mdbr_2 = "00000000b31c0000h", md_4 = "000000006c000000j", mdr_2 = "0000000000002c00g", mxdbr_2 = "00000000b3070000h", mxd_4 = "0000000067000000j", mxdr_2 = "0000000000002700g", meebr_2 = "00000000b3170000h", meer_2 = "00000000b3370000h", mdebr_2 = "00000000b30c0000h", mde_4 = "000000007c000000j", mder_2 = "0000000000003c00g", me_4 = "000000007c000000j", mer_2 = "0000000000003c00g", mh_4 = "000000004c000000j", mhy_5 = "0000e3000000007cl", mlg_5 = "0000e30000000086l", mlgr_2 = "00000000b9860000h", ml_5 = "0000e30000000096l", mlr_2 = "00000000b9960000h", ms_4 = "0000000071000000j", msr_2 = "00000000b2520000h", msy_5 = "0000e30000000051l", msg_5 = "0000e3000000000cl", msgr_2 = "00000000b90c0000h", msgf_5 = "0000e3000000001cl", msgfr_2 = "00000000b91c0000h", msfi_3 = "0000c20100000000n", msgfi_3 = "0000c20000000000n", o_4 = "0000000056000000j", ["or_2"] = "0000000000001600g", oy_5 = "0000e30000000056l", og_5 = "0000e30000000081l", ogr_2 = "00000000b9810000h", oihf_3 = "0000c00c00000000n", oilf_3 = "0000c00d00000000n", pgin_2 = "00000000b22e0000h", pgout_2 = "00000000b22f0000h", pcc_2 = "00000000b92c0000h", pckmo_2 = "00000000b9280000h", pfmf_2 = "00000000b9af0000h", ptf_2 = "00000000b9a20000h", popcnt_2 = "00000000b9e10000h", pfd_5 = "0000e30000000036m", pfdrl_3 = "0000c60200000000p", pt_2 = "00000000b2280000h", pti_2 = "00000000b99e0000h", palb_2 = "00000000b2480000h", rrbe_2 = "00000000b22a0000h", rrbm_2 = "00000000b9ae0000h", rll_5 = "0000eb000000001ds", rllg_5 = "0000eb000000001cs", srst_2 = "00000000b25e0000h", srstu_2 = "00000000b9be0000h", sar_2 = "00000000b24e0000h", sfpc_2 = "00000000b3840000h", sfasr_2 = "00000000b3850000h", spm_2 = "000000000000400g", ssar_2 = "00000000b2250000h", ssair_2 = "00000000b99f0000h", slda_4 = "000000008f000000q", sldl_4 = "000000008d000000q", sla_4 = "000000008b000000q", slak_5 = "0000eb00000000dds", slag_5 = "0000eb000000000bs", sll_4 = "0000000089000000q", sllk_5 = "0000eb00000000dfs", sllg_5 = "0000eb000000000ds", srda_4 = "000000008e000000q", srdl_4 = "000000008c000000q", sra_4 = "000000008a000000q", srak_5 = "0000eb00000000dcs", srag_5 = "0000eb000000000as", srl_4 = "0000000088000000q", srlk_5 = "0000eb00000000des", srlg_5 = "0000eb000000000cs", sqxbr_2 = "00000000b3160000h", sqxr_2 = "00000000b3360000h", sqdbr_2 = "00000000b3150000h", sqdr_2 = "00000000b2440000h", sqebr_2 = "00000000b3140000h", sqer_2 = "00000000b2450000h", st_4 = "0000000050000000j", sty_5 = "0000e30000000050l", stg_5 = "0000e30000000024l", std_4 = "0000000060000000j", stdy_5 = "0000ed0000000067l", ste_4 = "0000000070000000j", stey_5 = "0000ed0000000066l", stam_4 = "000000009b000000q", stamy_5 = "0000eb000000009bs", stc_4 = "0000000042000000j", stcy_5 = "0000e30000000072l", stch_5 = "0000e300000000c3l", stcmh_5 = "0000eb000000002ct", stcm_4 = "00000000be000000r", stcmy_5 = "0000eb000000002dt", stctl_4 = "00000000b6000000q", stctg_5 = "0000eb0000000025s", sth_4 = "0000000040000000j", sthy_5 = "0000e30000000070l", sthh_5 = "0000e300000000c7l", sthrl_3 = "0000c40700000000o", stfh_5 = "0000e300000000cbl", stm_4 = "0000000090000000q", stmy_5 = "0000eb0000000090s", stmg_5 = "0000eb0000000024s", stmh_5 = "0000eb0000000026s", stoc_5 = "0000eb00000000f3t", stocg_5 = "0000eb00000000e3t", stpq_5 = "0000e3000000008el", strl_3 = "0000c40f00000000o", stgrl_3 = "0000c40b00000000o", strvh_5 = "0000e3000000003fl", strv_5 = "0000e3000000003el", strvg_5 = "0000e3000000002fl", stura_2 = "00000000b2460000h", sturg_2 = "00000000b9250000h", s_4 = "000000005b000000j", sr_2 = "0000000000001b00g", sy_5 = "0000e3000000005bl", sg_5 = "0000e30000000009l", sgr_2 = "00000000b9090000h", sgf_5 = "0000e30000000019l", sgfr_2 = "00000000b9190000h", sxbr_2 = "00000000b34b0000h", sdbr_2 = "00000000b31b0000h", sebr_2 = "00000000b30b0000h", sh_4 = "000000004b000000j", shy_5 = "0000e3000000007bl", sl_4 = "000000005f000000j", slr_2 = "0000000000001f00g", sly_5 = "0000e3000000005fl", slg_5 = "0000e3000000000bl", slgr_2 = "00000000b90b0000h", slgf_5 = "0000e3000000001bl", slgfr_2 = "00000000b91b0000h", slfi_3 = "0000c20500000000n", slgfi_3 = "0000c20400000000n", slb_5 = "0000e30000000099l", slbr_2 = "00000000b9990000h", slbg_5 = "0000e30000000089l", slbgr_2 = "00000000b9890000h", sxr_2 = "0000000000003700g", sd_4 = "000000006b000000j", sdr_2 = "0000000000002b00g", se_4 = "000000007b000000j", ser_2 = "0000000000003b00g", su_4 = "000000007f000000j", sur_2 = "0000000000003f00g", sw_4 = "000000006f000000j", swr_2 = "0000000000002f00g", tar_2 = "00000000b24c0000h", tb_2 = "00000000b22c0000h", trace_4 = "0000000099000000q", tracg_5 = "0000eb000000000fs", tre_2 = "00000000b2a50000h", } for cond,c in pairs(map_cond) do -- Extended mnemonics for branches. -- TODO: replace 'B' with correct encoding. -- brc map_op["j"..cond.."_1"] = "00000000"..tohex(0xa7040000+shl(c, 20)).."B" -- brcl map_op["jg"..cond.."_1"] = tohex(0xc004+shl(c, 4)).."00000000".."B" -- bc map_op["b"..cond.."_1"] = "00000000"..tohex(0x47000000+shl(c, 20)).."B" -- bcr map_op["b"..cond.."r_1"] = "00000000"..tohex(0x0700+shl(c, 4)).."B" end ------------------------------------------------------------------------------ -- Handle opcodes defined with template strings. local function parse_template(params, template, nparams, pos) local op = tonumber(sub(template, 1, 16), 16) -- -- 00000000005a0000 converts to 90 local n,rs = 1,26 parse_reg_type = false -- Process each character. for p in gmatch(sub(template, 17), ".") do local pr1,pr2,pr3 if p == "g" then pr1,pr2=param[n],param[n+1] op = op + shl(parse_reg(pr1),4) + parse_reg(pr2); n = n + 1 -- not sure if we will require n later, so keeping it as it is now elseif p == "h" then pr1,pr2=param[n],param[n+1] op = op + shl(parse_reg(pr1),4) + parse_reg(pr2) elseif p == "j" then op = op + shl(parse_reg(param[1]),24) + shl(parse_reg(param[2]),20) + shl(parse_reg(param[3]),16) + parse_number(param[4]) -- assuming that the parameters are passes in order (R1,X2,B2,D) --only RX-a is satisfied elseif p == "k" then op = op + shl(parse_reg(param[1]),40) + shl(parse_reg(param[2]),36) + shl(parse_reg(param[3]),32) + parse_number(param[4]) + parse_number(param[5]) -- assuming params are passed as (R1,X2,B2,DL2,DH2) elseif p == "l" then elseif p == "m" then elseif p == "n" then end end wputpos(pos, op) end function op_template(params, template, nparams) if not params then return template:gsub("%x%x%x%x%x%x%x%x", "") end -- Limit number of section buffer positions used by a single dasm_put(). -- A single opcode needs a maximum of 3 positions. if secpos+3 > maxsecpos then wflush() end local pos = wpos() local lpos, apos, spos = #actlist, #actargs, secpos local ok, err for t in gmatch(template, "[^|]+") do ok, err = pcall(parse_template, params, t, nparams, pos) if ok then return end secpos = spos actlist[lpos+1] = nil actlist[lpos+2] = nil actlist[lpos+3] = nil actargs[apos+1] = nil actargs[apos+2] = nil actargs[apos+3] = nil end error(err, 0) end map_op[".template__"] = op_template ------------------------------------------------------------------------------ -- Pseudo-opcode to mark the position where the action list is to be emitted. map_op[".actionlist_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeactions(out, name) end) end -- Pseudo-opcode to mark the position where the global enum is to be emitted. map_op[".globals_1"] = function(params) if not params then return "prefix" end local prefix = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeglobals(out, prefix) end) end -- Pseudo-opcode to mark the position where the global names are to be emitted. map_op[".globalnames_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeglobalnames(out, name) end) end -- Pseudo-opcode to mark the position where the extern names are to be emitted. map_op[".externnames_1"] = function(params) if not params then return "cvar" end local name = params[1] -- No syntax check. You get to keep the pieces. wline(function(out) writeexternnames(out, name) end) end ------------------------------------------------------------------------------ -- Label pseudo-opcode (converted from trailing colon form). map_op[".label_1"] = function(params) if not params then return "[1-9] | ->global | =>pcexpr" end if secpos+1 > maxsecpos then wflush() end local mode, n, s = parse_label(params[1], true) if mode == "EXT" then werror("bad label definition") end waction("LABEL_"..mode, n, s, 1) end ------------------------------------------------------------------------------ -- Pseudo-opcodes for data storage. map_op[".long_*"] = function(params) if not params then return "imm..." end for _,p in ipairs(params) do local n = tonumber(p) if not n then werror("bad immediate `"..p.."'") end if n < 0 then n = n + 2^32 end wputw(n) if secpos+2 > maxsecpos then wflush() end end end -- Alignment pseudo-opcode. map_op[".align_1"] = function(params) if not params then return "numpow2" end if secpos+1 > maxsecpos then wflush() end local align = tonumber(params[1]) if align then local x = align -- Must be a power of 2 in the range (2 ... 256). for i=1,8 do x = x / 2 if x == 1 then waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. return end end end werror("bad alignment") end ------------------------------------------------------------------------------ -- Pseudo-opcode for (primitive) type definitions (map to C types). map_op[".type_3"] = function(params, nparams) if not params then return nparams == 2 and "name, ctype" or "name, ctype, reg" end local name, ctype, reg = params[1], params[2], params[3] if not match(name, "^[%a_][%w_]*$") then werror("bad type name `"..name.."'") end local tp = map_type[name] if tp then werror("duplicate type `"..name.."'") end -- Add #type to defines. A bit unclean to put it in map_archdef. map_archdef["#"..name] = "sizeof("..ctype..")" -- Add new type and emit shortcut define. local num = ctypenum + 1 map_type[name] = { ctype = ctype, ctypefmt = format("Dt%X(%%s)", num), reg = reg, } wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) ctypenum = num end map_op[".type_2"] = map_op[".type_3"] -- Dump type definitions. local function dumptypes(out, lvl) local t = {} for name in pairs(map_type) do t[#t+1] = name end sort(t) out:write("Type definitions:\n") for _,name in ipairs(t) do local tp = map_type[name] local reg = tp.reg or "" out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) end out:write("\n") end ------------------------------------------------------------------------------ -- Set the current section. function _M.section(num) waction("SECTION", num) wflush(true) -- SECTION is a terminal action. end ------------------------------------------------------------------------------ -- Dump architecture description. function _M.dumparch(out) out:write(format("DynASM %s version %s, released %s\n\n", _info.arch, _info.version, _info.release)) dumpactions(out) end -- Dump all user defined elements. function _M.dumpdef(out, lvl) dumptypes(out, lvl) dumpglobals(out, lvl) dumpexterns(out, lvl) end ------------------------------------------------------------------------------ -- Pass callbacks from/to the DynASM core. function _M.passcb(wl, we, wf, ww) wline, werror, wfatal, wwarn = wl, we, wf, ww return wflush end -- Setup the arch-specific module. function _M.setup(arch, opt) g_arch, g_opt = arch, opt end -- Merge the core maps and the arch-specific maps. function _M.mergemaps(map_coreop, map_def) setmetatable(map_op, { __index = map_coreop }) setmetatable(map_def, { __index = map_archdef }) return map_op, map_def end return _M ------------------------------------------------------------------------------