From bb784b48a613cb7c51f012db9baefd5ee52ef9c9 Mon Sep 17 00:00:00 2001 From: Aditya Bisht Date: Thu, 23 Jun 2022 14:05:10 +0530 Subject: [PATCH] Adding s390x support for DynASM --- dynasm/dasm_s390x.h | 546 ++++++++++++++ dynasm/dasm_s390x.lua | 1632 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2178 insertions(+) create mode 100644 dynasm/dasm_s390x.h create mode 100644 dynasm/dasm_s390x.lua diff --git a/dynasm/dasm_s390x.h b/dynasm/dasm_s390x.h new file mode 100644 index 00000000..6f765a5c --- /dev/null +++ b/dynasm/dasm_s390x.h @@ -0,0 +1,546 @@ +/* +** DynASM s390x encoding engine. +** Copyright (C) 2005-2022 Mike Pall. All rights reserved. +** Released under the MIT license. See dynasm.lua for full copyright notice. +*/ + +#include +#include +#include +#include + +#define DASM_ARCH "s390x" + +#ifndef DASM_EXTERN +#define DASM_EXTERN(a,b,c,d) 0 +#endif + +/* Action definitions. */ +enum { + DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, + /* The following actions need a buffer position. */ + DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, + /* The following actions also have an argument. */ + DASM_REL_PC, DASM_LABEL_PC, + DASM_DISP12, DASM_DISP20, + DASM_IMM8, DASM_IMM16, DASM_IMM32, + DASM_LEN8R,DASM_LEN4HR,DASM_LEN4LR, + DASM__MAX +}; + +/* Maximum number of section buffer positions for a single dasm_put() call. */ +#define DASM_MAXSECPOS 25 + +/* DynASM encoder status codes. Action list offset or number are or'ed in. */ +#define DASM_S_OK 0x00000000 +#define DASM_S_NOMEM 0x01000000 +#define DASM_S_PHASE 0x02000000 +#define DASM_S_MATCH_SEC 0x03000000 +#define DASM_S_RANGE_I 0x11000000 +#define DASM_S_RANGE_SEC 0x12000000 +#define DASM_S_RANGE_LG 0x13000000 +#define DASM_S_RANGE_PC 0x14000000 +#define DASM_S_RANGE_REL 0x15000000 +#define DASM_S_UNDEF_LG 0x21000000 +#define DASM_S_UNDEF_PC 0x22000000 + +/* Macros to convert positions (8 bit section + 24 bit index). */ +#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) +#define DASM_POS2BIAS(pos) ((pos)&0xff000000) +#define DASM_SEC2POS(sec) ((sec)<<24) +#define DASM_POS2SEC(pos) ((pos)>>24) +#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) + +/* Action list type. */ +typedef const unsigned short *dasm_ActList; + +/* Per-section structure. */ +typedef struct dasm_Section { + int *rbuf; /* Biased buffer pointer (negative section bias). */ + int *buf; /* True buffer pointer. */ + size_t bsize; /* Buffer size in bytes. */ + int pos; /* Biased buffer position. */ + int epos; /* End of biased buffer position - max single put. */ + int ofs; /* Byte offset into section. */ +} dasm_Section; + +/* Core structure holding the DynASM encoding state. */ +struct dasm_State { + size_t psize; /* Allocated size of this structure. */ + dasm_ActList actionlist; /* Current actionlist pointer. */ + int *lglabels; /* Local/global chain/pos ptrs. */ + size_t lgsize; + int *pclabels; /* PC label chains/pos ptrs. */ + size_t pcsize; + void **globals; /* Array of globals (bias -10). */ + dasm_Section *section; /* Pointer to active section. */ + size_t codesize; /* Total size of all code sections. */ + int maxsection; /* 0 <= sectionidx < maxsection. */ + int status; /* Status code. */ + dasm_Section sections[1]; /* All sections. Alloc-extended. */ +}; + +/* The size of the core structure depends on the max. number of sections. */ +#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) + + +/* Initialize DynASM state. */ +void dasm_init(Dst_DECL, int maxsection) +{ + dasm_State *D; + size_t psz = 0; + int i; + Dst_REF = NULL; + DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); + D = Dst_REF; + D->psize = psz; + D->lglabels = NULL; + D->lgsize = 0; + D->pclabels = NULL; + D->pcsize = 0; + D->globals = NULL; + D->maxsection = maxsection; + for (i = 0; i < maxsection; i++) { + D->sections[i].buf = NULL; /* Need this for pass3. */ + D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); + D->sections[i].bsize = 0; + D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ + } +} + +/* Free DynASM state. */ +void dasm_free(Dst_DECL) +{ + dasm_State *D = Dst_REF; + int i; + for (i = 0; i < D->maxsection; i++) + if (D->sections[i].buf) + DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); + if (D->pclabels) + DASM_M_FREE(Dst, D->pclabels, D->pcsize); + if (D->lglabels) + DASM_M_FREE(Dst, D->lglabels, D->lgsize); + DASM_M_FREE(Dst, D, D->psize); +} + +/* Setup global label array. Must be called before dasm_setup(). */ +void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) +{ + dasm_State *D = Dst_REF; + D->globals = gl - 10; /* Negative bias to compensate for locals. */ + DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10 + maxgl) * sizeof(int)); +} + +/* Grow PC label array. Can be called after dasm_setup(), too. */ +void dasm_growpc(Dst_DECL, unsigned int maxpc) +{ + dasm_State *D = Dst_REF; + size_t osz = D->pcsize; + DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc * sizeof(int)); + memset((void *)(((unsigned char *)D->pclabels) + osz), 0, D->pcsize - osz); +} + +/* Setup encoder. */ +void dasm_setup(Dst_DECL, const void *actionlist) +{ + dasm_State *D = Dst_REF; + int i; + D->actionlist = (dasm_ActList) actionlist; + D->status = DASM_S_OK; + D->section = &D->sections[0]; + memset((void *)D->lglabels, 0, D->lgsize); + if (D->pclabels) + memset((void *)D->pclabels, 0, D->pcsize); + for (i = 0; i < D->maxsection; i++) { + D->sections[i].pos = DASM_SEC2POS(i); + D->sections[i].ofs = 0; + } +} + + +#ifdef DASM_CHECKS +#define CK(x, st) \ + do { if (!(x)) { \ + D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) +#define CKPL(kind, st) \ + do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ + D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) +#else +#define CK(x, st) ((void)0) +#define CKPL(kind, st) ((void)0) +#endif + +/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ +void dasm_put(Dst_DECL, int start, ...) +{ + va_list ap; + dasm_State *D = Dst_REF; + dasm_ActList p = D->actionlist + start; + dasm_Section *sec = D->section; + int pos = sec->pos, ofs = sec->ofs; + int *b; + + if (pos >= sec->epos) { + DASM_M_GROW(Dst, int, sec->buf, sec->bsize, + sec->bsize + 2 * DASM_MAXSECPOS * sizeof(int)); + sec->rbuf = sec->buf - DASM_POS2BIAS(pos); + sec->epos = + (int)sec->bsize / sizeof(int) - DASM_MAXSECPOS + DASM_POS2BIAS(pos); + } + + b = sec->rbuf; + b[pos++] = start; + + va_start(ap, start); + while (1) { + unsigned short ins = *p++; + unsigned short action = ins; + if (action >= DASM__MAX) { + ofs += 2; + continue; + } + + int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; + switch (action) { + case DASM_STOP: + goto stop; + case DASM_SECTION: + n = *p++ & 255; + CK(n < D->maxsection, RANGE_SEC); + D->section = &D->sections[n]; + goto stop; + case DASM_ESC: + p++; + ofs += 2; + break; + case DASM_REL_EXT: + p++; + ofs += 4; + break; + case DASM_ALIGN: + ofs += *p++; + b[pos++] = ofs; + break; + case DASM_REL_LG: + if (p[-2] >> 12 == 0xc) { /* RIL instruction needs 32-bit immediate. */ + ofs += 2; + } + n = *p++ - 10; + pl = D->lglabels + n; + /* Bkwd rel or global. */ + if (n >= 0) { + CK(n >= 10 || *pl < 0, RANGE_LG); + CKPL(lg, LG); + goto putrel; + } + pl += 10; + n = *pl; + if (n < 0) + n = 0; /* Start new chain for fwd rel if label exists. */ + goto linkrel; + case DASM_REL_PC: + if (p[-2] >> 12 == 0xc) { /* RIL instruction needs 32-bit immediate. */ + ofs += 2; + } + pl = D->pclabels + n; + CKPL(pc, PC); + putrel: + n = *pl; + if (n < 0) { /* Label exists. Get label pos and store it. */ + b[pos] = -n; + } else { + linkrel: + b[pos] = n; /* Else link to rel chain, anchored at label. */ + *pl = pos; + } + ofs += 2; + pos++; + break; + case DASM_LABEL_LG: + pl = D->lglabels + *p++ - 10; + CKPL(lg, LG); + goto putlabel; + case DASM_LABEL_PC: + pl = D->pclabels + n; + CKPL(pc, PC); + putlabel: + n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ + while (n > 0) { + int *pb = DASM_POS2PTR(D, n); + n = *pb; + *pb = pos; + } + *pl = -pos; /* Label exists now. */ + b[pos++] = ofs; /* Store pass1 offset estimate. */ + break; + case DASM_IMM8: + b[pos++] = n; + break; + case DASM_IMM16: + CK(((short)n) == n || ((unsigned short)n) == n, RANGE_I); /* TODO: is this the right way to handle unsigned immediates? */ + ofs += 2; + b[pos++] = n; + break; + case DASM_IMM32: + ofs += 4; + b[pos++] = n; + break; + case DASM_DISP20: + CK(-(1 << 19) <= n && n < (1 << 19), RANGE_I); + b[pos++] = n; + break; + case DASM_DISP12: + CK((n >> 12) == 0, RANGE_I); + b[pos++] = n; + break; + case DASM_LEN8R: + CK(n >= 1 && n <= 256, RANGE_I); + b[pos++] = n; + break; + case DASM_LEN4HR: + case DASM_LEN4LR: + CK(n >= 1 && n <= 128, RANGE_I); + b[pos++] = n; + break; + } + } +stop: + va_end(ap); + sec->pos = pos; + sec->ofs = ofs; +} + +#undef CK + +/* Pass 2: Link sections, shrink aligns, fix label offsets. */ +int dasm_link(Dst_DECL, size_t * szp) +{ + dasm_State *D = Dst_REF; + int secnum; + int ofs = 0; + +#ifdef DASM_CHECKS + *szp = 0; + if (D->status != DASM_S_OK) + return D->status; + { + int pc; + for (pc = 0; pc * sizeof(int) < D->pcsize; pc++) + if (D->pclabels[pc] > 0) + return DASM_S_UNDEF_PC | pc; + } +#endif + + { /* Handle globals not defined in this translation unit. */ + int idx; + for (idx = 20; idx * sizeof(int) < D->lgsize; idx++) { + int n = D->lglabels[idx]; + /* Undefined label: Collapse rel chain and replace with marker (< 0). */ + while (n > 0) { + int *pb = DASM_POS2PTR(D, n); + n = *pb; + *pb = -idx; + } + } + } + + /* Combine all code sections. No support for data sections (yet). */ + for (secnum = 0; secnum < D->maxsection; secnum++) { + dasm_Section *sec = D->sections + secnum; + int *b = sec->rbuf; + int pos = DASM_SEC2POS(secnum); + int lastpos = sec->pos; + + while (pos != lastpos) { + dasm_ActList p = D->actionlist + b[pos++]; + while (1) { + unsigned short ins = *p++; + unsigned short action = ins; + switch (action) { + case DASM_STOP: + case DASM_SECTION: + goto stop; + case DASM_ESC: + p++; + break; + case DASM_REL_EXT: + p++; + break; + case DASM_ALIGN: + ofs -= (b[pos++] + ofs) & *p++; + break; + case DASM_REL_LG: + case DASM_REL_PC: + p++; + pos++; + break; + case DASM_LABEL_LG: + case DASM_LABEL_PC: + p++; + b[pos++] += ofs; + break; + case DASM_IMM8: + case DASM_IMM16: + case DASM_IMM32: + case DASM_DISP20: + case DASM_DISP12: + case DASM_LEN8R: + case DASM_LEN4HR: + case DASM_LEN4LR: + pos++; + break; + } + } + stop:(void)0; + } + ofs += sec->ofs; /* Next section starts right after current section. */ + } + + D->codesize = ofs; /* Total size of all code sections */ + *szp = ofs; + return DASM_S_OK; +} + +#ifdef DASM_CHECKS +#define CK(x, st) \ + do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) +#else +#define CK(x, st) ((void)0) +#endif + +/* Pass 3: Encode sections. */ +int dasm_encode(Dst_DECL, void *buffer) +{ + dasm_State *D = Dst_REF; + char *base = (char *)buffer; + unsigned short *cp = (unsigned short *)buffer; + int secnum; + + /* Encode all code sections. No support for data sections (yet). */ + for (secnum = 0; secnum < D->maxsection; secnum++) { + dasm_Section *sec = D->sections + secnum; + int *b = sec->buf; + int *endb = sec->rbuf + sec->pos; + + while (b != endb) { + dasm_ActList p = D->actionlist + *b++; + while (1) { + unsigned short ins = *p++; + unsigned short action = ins; + int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; + switch (action) { + case DASM_STOP: + case DASM_SECTION: + goto stop; + case DASM_ESC: + *cp++ = *p++; + break; + case DASM_REL_EXT: + n = DASM_EXTERN(Dst, (unsigned char *)cp, *p++, 1) - 4; + goto patchrel; + case DASM_ALIGN: + ins = *p++; + /* TODO: emit 4-byte noprs instead of 2-byte nops where possible. */ + while ((((char *)cp - base) & ins)) + *cp++ = 0x0700; /* nop */ + break; + case DASM_REL_LG: + CK(n >= 0, UNDEF_LG); + case DASM_REL_PC: + CK(n >= 0, UNDEF_PC); + n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base); + p++; /* skip argument */ + patchrel: + /* Offsets are halfword aligned (so need to be halved). */ + n += 2; /* Offset is relative to start of instruction. */ + if (cp[-1] >> 12 == 0xc) { + *cp++ = n >> 17; + } else { + CK(-(1 << 16) <= n && n < (1 << 16) && (n & 1) == 0, RANGE_LG); + } + *cp++ = n >> 1; + break; + case DASM_LABEL_LG: + ins = *p++; + if (ins >= 20) + D->globals[ins - 10] = (void *)(base + n); + break; + case DASM_LABEL_PC: + break; + case DASM_IMM8: + cp[-1] |= n & 0xff; + break; + case DASM_IMM16: + *cp++ = n; + break; + case DASM_IMM32: + *cp++ = n >> 16; + *cp++ = n; + break; + case DASM_DISP20: + cp[-2] |= n & 0xfff; + cp[-1] |= (n >> 4) & 0xff00; + break; + case DASM_DISP12: + cp[-1] |= n & 0xfff; + break; + case DASM_LEN8R: + cp[-1] |= (n - 1) & 0xff; + break; + case DASM_LEN4HR: + cp[-1] |= ((n - 1) << 4) & 0xf0; + break; + case DASM_LEN4LR: + cp[-1] |= (n - 1) & 0x0f; + break; + default: + *cp++ = ins; + break; + } + } + stop:(void)0; + } + } + + if (base + D->codesize != (char *)cp) /* Check for phase errors. */ + return DASM_S_PHASE; + return DASM_S_OK; +} + +#undef CK + +/* Get PC label offset. */ +int dasm_getpclabel(Dst_DECL, unsigned int pc) +{ + dasm_State *D = Dst_REF; + if (pc * sizeof(int) < D->pcsize) { + int pos = D->pclabels[pc]; + if (pos < 0) + return *DASM_POS2PTR(D, -pos); + if (pos > 0) + return -1; /* Undefined. */ + } + return -2; /* Unused or out of range. */ +} + +#ifdef DASM_CHECKS +/* Optional sanity checker to call between isolated encoding steps. */ +int dasm_checkstep(Dst_DECL, int secmatch) +{ + dasm_State *D = Dst_REF; + if (D->status == DASM_S_OK) { + int i; + for (i = 1; i <= 9; i++) { + if (D->lglabels[i] > 0) { + D->status = DASM_S_UNDEF_LG | i; + break; + } + D->lglabels[i] = 0; + } + } + if (D->status == DASM_S_OK && secmatch >= 0 && + D->section != &D->sections[secmatch]) + D->status = DASM_S_MATCH_SEC | (D->section - D->sections); + return D->status; +} +#endif diff --git a/dynasm/dasm_s390x.lua b/dynasm/dasm_s390x.lua new file mode 100644 index 00000000..5bb5d2df --- /dev/null +++ b/dynasm/dasm_s390x.lua @@ -0,0 +1,1632 @@ +------------------------------------------------------------------------------ +-- DynASM s390x module. +-- +-- Copyright (C) 2005-2022 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", "DISP12", "DISP20", "IMM8", "IMM16", "IMM32", "LEN8R","LEN4HR","LEN4LR", +} + +-- 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 = {} +local max_action = 0 +for n, name in ipairs(action_names) do + map_action[name] = n-1 + max_action = n +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 + +local function havearg(a) + return a == "ESC" or + a == "SECTION" or + a == "REL_LG" or + a == "LABEL_LG" or + a == "REL_EXT" +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 short ", name, "[", nn, "] = {") + local esc = false -- also need to escape for action arguments + for i = 1, nn do + assert(out:write("\n 0x", sub(tohex(actlist[i]), 5, 8))) + if i ~= nn then assert(out:write(",")) end + local name = action_names[actlist[i]+1] + if not esc and name then + assert(out:write(" /* ", name, " */")) + esc = havearg(name) + else + esc = false + end + end + assert(out:write("\n};\n\n")) +end + +------------------------------------------------------------------------------ + +-- Add halfword to action list. +local function wputxhw(n) + assert(n >= 0 and n <= 0xffff, "halfword out of range") + 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.."'") + wputxhw(w) + if val then wputxhw(val) end -- Not sure about this, do we always have one arg? + if a then actargs[#actargs+1] = a end + if val or 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 halfword. +local function wputhw(n) + if n <= max_action then waction("ESC") end + wputxhw(n) +end + +-- Reserve position for halfword. +local function wpos() + local pos = #actlist+1 + actlist[pos] = "" + return pos +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. +-- Ext. register name -> int. name. +local map_archdef = { sp = "r15" } + +-- Int. register name -> ext. name. +local map_reg_rev = { r15 = "sp" } + +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 + +local map_cond = { + o = 1, h = 2, nle = 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 function parse_reg(expr) + if not expr then werror("expected register name") end + local tname, ovreg = match(expr, "^([%w_]+):(r1?%d)$") + local tp = map_type[tname or expr] + if tp then + local reg = ovreg or tp.reg + if not reg then + werror("type `"..(tname or expr).."' needs a register override") + end + expr = reg + end + local r = match(expr, "^[rf](1?%d)$") + if r then + r = tonumber(r) + if r <= 15 then return r, tp end + end + werror("bad register name `"..expr.."'") +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 is_uint12(num) + return 0 <= num and num < 4096 +end + +local function is_int20(num) + return -shl(1, 19) <= num and num < shl(1, 19) +end + +local function is_int32(num) + return -2147483648 <= num and num < 2147483648 +end + +local function is_uint16(num) + return 0 <= num and num < 0xffff +end + +local function is_int16(num) + return -32768 <= num and num < 32768 +end + +local function is_int8(num) + return -128 <= num and num < 128 +end + +local function is_uint8(num) + return 0 <= num and num < 256 +end + +-- Split a memory operand of the form d(b) or d(x,b) into d, x and b. +-- If x is not specified then it is 0. +local function split_memop(arg) + local reg = "[%w_:]+" + local d, x, b = match(arg, "^(.*)%(%s*("..reg..")%s*,%s*("..reg..")%s*%)$") + if d then + return d, parse_reg(x), parse_reg(b) + end + local d, b = match(arg, "^(.*)%(%s*("..reg..")%s*%)$") + if d then + return d, 0, parse_reg(b) + end + -- Assume the two registers are passed as "(r1,r2)", and displacement(d) is not specified. TODO: not sure if we want to do this, GAS doesn't. + local x, b = match(arg,"%(%s*("..reg..")%s*,%s*("..reg..")%s*%)$") + if b then + return 0, parse_reg(x), parse_reg(b) + end + -- Accept a lone integer as a displacement. TODO: allow expressions/variables here? Interacts badly with the other rules currently. + local d = match(arg,"^(-?[%d]+)$") + if d then + return d, 0, 0 + end + local reg, tailr = match(arg, "^([%w_:]+)%s*(.*)$") + if reg then + local r, tp = parse_reg(reg) + if tp then + return format(tp.ctypefmt, tailr), 0, r + end + end + werror("bad memory operand: "..arg) + return nil +end + +-- Parse memory operand of the form d(x, b) where 0 <= d < 4096 and b and x +-- are GPRs. +-- If the fourth return value is not-nil then it needs to be called to +-- insert an action. +-- Encoded as: xbddd +local function parse_mem_bx(arg) + local d, x, b = split_memop(arg) + local dval = tonumber(d) + if dval then + if not is_uint12(dval) then + werror("displacement out of range: ", dval) + end + return dval, x, b, nil + end + if match(d, "^[rf]1?[0-9]?") then + werror("expected immediate operand, got register") + end + return 0, x, b, function() waction("DISP12", nil, d) end +end + +-- Parse memory operand of the form d(b) where 0 <= d < 4096 and b is a GPR. +-- Encoded as: bddd +local function parse_mem_b(arg) + local d, x, b, a = parse_mem_bx(arg) + if x ~= 0 then + werror("unexpected index register") + end + return d, b, a +end + +-- Parse memory operand of the form d(x, b) where -(2^20)/2 <= d < (2^20)/2 +-- and b and x are GPRs. +-- Encoded as: xblllhh (ls are the low-bits of d, and hs are the high bits). +local function parse_mem_bxy(arg) + local d, x, b = split_memop(arg) + local dval = tonumber(d) + if dval then + if not is_int20(dval) then + werror("displacement out of range: ", dval) + end + return dval, x, b, nil + end + if match(d, "^[rf]1?[0-9]?") then + werror("expected immediate operand, got register") + end + return 0, x, b, function() waction("DISP20", nil, d) end +end + +-- Parse memory operand of the form d(b) where -(2^20)/2 <= d < (2^20)/2 and +-- b is a GPR. +-- Encoded as: blllhh (ls are the low-bits of d, and hs are the high bits). +local function parse_mem_by(arg) + local d, x, b, a = parse_mem_bxy(arg) + if x ~= 0 then + werror("unexpected index register") + end + return d, b, a +end + +-- Parse memory operand of the form d(l, b) where 0 <= d < 4096, 1 <= l <= 256, +-- and b is a GPR. +local function parse_mem_lb(arg) + local reg = "r1?[0-9]" + local d, l, b = match(arg, "^(.*)%s*%(%s*(.*)%s*,%s*("..reg..")%s*%)$") + if not d then + -- TODO: handle values without registers? + -- TODO: handle registers without a displacement? + werror("bad memory operand: "..arg) + return nil + end + local dval = tonumber(d) + local dact = nil + if dval then + if not is_uint12(dval) then + werror("displacement out of range: ", dval) + end + else + dval = 0 + dact = function() waction("DISP12", nil, d) end + end + local lval = tonumber(l) + local lact = nil + if lval then + if lval < 1 or lval > 256 then + werror("length out of range: ", dval) + end + lval = lval - 1 + else + lval = 0 + lact = function() waction("LEN8R", nil, l) end + end + return dval, lval, parse_reg(b), dact, lact +end + +local function parse_mem_l2b(arg, high_l) + local reg = "r1?[0-9]" + local d, l, b = match(arg, "^(.*)%s*%(%s*(.*)%s*,%s*("..reg..")%s*%)$") + if not d then + -- TODO: handle values without registers? + -- TODO: handle registers without a displacement? + werror("bad memory operand: "..arg) + return nil + end + local dval = tonumber(d) + local dact = nil + if dval then + if not is_uint12(dval) then + werror("displacement out of range: ", dval) + end + else + dval = 0 + dact = function() waction("DISP12", nil, d) end + end + local lval = tonumber(l) + local lact = nil + if lval then + if lval < 1 or lval > 128 then + werror("length out of range: ", dval) + end + lval = lval - 1 + else + lval = 0 + if high_l then + lact = function() waction("LEN4HR", nil, l) end + else + lact = function() waction("LEN4LR", nil, l) end + end + end + return dval, lval, parse_reg(b), dact, lact +end + +local function parse_imm32(imm) + local imm_val = tonumber(imm) + if imm_val then + if not is_int32(imm_val) then + werror("immediate value out of range: ", imm_val) + end + wputhw(band(shr(imm_val, 16), 0xffff)) + wputhw(band(imm_val, 0xffff)) + elseif match(imm, "^[rfv]([1-3]?[0-9])$") or + match(imm, "^([%w_]+):(r1?[0-9])$") then + werror("expected immediate operand, got register") + else + waction("IMM32", nil, imm) -- if we get label + end +end + +local function parse_imm16(imm) + local imm_val = tonumber(imm) + if imm_val then + if not is_int16(imm_val) and not is_uint16(imm_val) then + werror("immediate value out of range: ", imm_val) + end + wputhw(band(imm_val, 0xffff)) + elseif match(imm, "^[rfv]([1-3]?[0-9])$") or + match(imm, "^([%w_]+):(r1?[0-9])$") then + werror("expected immediate operand, got register") + else + waction("IMM16", nil, imm) + end +end + +local function parse_imm8(imm) + local imm_val = tonumber(imm) + if imm_val then + if not is_int8(imm_val) and not is_uint8(imm_val) then + werror("Immediate value out of range: ", imm_val) + end + return imm_val, nil + end + return 0, function() waction("IMM8", nil, imm) end +end + +local function parse_mask(mask) + local m3 = parse_number(mask) + if m3 then + if ((m3 == 1) or (m3 == 0) or ( m3 >=3 and m3 <=7)) then + return m3 + else + werror("Mask value should be 0,1 or 3-7: ", m3) + end + end +end + +local function parse_mask2(mask) + local m4 = parse_number(mask) + if ( m4 >=0 and m4 <=1) then + return m4 + else + werror("Mask value should be 0 or 1: ", m4) + end +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 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 + +-- Template strings for s390x instructions. +map_op = { + a_2 = "00005a000000RX-a", + ad_2 = "00006a000000RX-a", + adb_2 = "ed000000001aRXE", + adbr_2 = "0000b31a0000RRE", + adr_2 = "000000002a00RR", + ae_2 = "00007a000000RX-a", + aeb_2 = "ed000000000aRXE", + aebr_2 = "0000b30a0000RRE", + aer_2 = "000000003a00RR", + afi_2 = "c20900000000RIL-a", + ag_2 = "e30000000008RXY-a", + agf_2 = "e30000000018RXY-a", + agfi_2 = "c20800000000RIL-a", + agfr_2 = "0000b9180000RRE", + aghi_2 = "0000a70b0000RI-a", + agr_2 = "0000b9080000RRE", + ah_2 = "00004a000000RX-a", + ahi_2 = "0000a70a0000RI-a", + ahy_2 = "e3000000007aRXY-a", + aih_2 = "cc0800000000RIL-a", + al_2 = "00005e000000RX-a", + alc_2 = "e30000000098RXY-a", + alcg_2 = "e30000000088RXY-a", + alcgr_2 = "0000b9880000RRE", + alcr_2 = "0000b9980000RRE", + alfi_2 = "c20b00000000RIL-a", + alg_2 = "e3000000000aRXY-a", + algf_2 = "e3000000001aRXY-a", + algfi_2 = "c20a00000000RIL-a", + algfr_2 = "0000b91a0000RRE", + algr_2 = "0000b90a0000RRE", + alr_2 = "000000001e00RR", + alsih_2 = "cc0a00000000RIL-a", + alsihn_2 = "cc0b00000000RIL-a", + aly_2 = "e3000000005eRXY-a", + ap_2 = "fa0000000000SS-b", + ar_2 = "000000001a00RR", + au_2 = "00007e000000RX-a", + aur_2 = "000000003e00RR", + aw_2 = "00006e000000RX-a", + awr_2 = "000000002e00RR", + axbr_2 = "0000b34a0000RRE", + axr_2 = "000000003600RR", + ay_2 = "e3000000005aRXY-a", + bakr_2 = "0000b2400000RRE", + bal_2 = "000045000000RX-a", + balr_2 = "000000000500RR", + bas_2 = "00004d000000RX-a", + basr_2 = "000000000d00RR", + bassm_2 = "000000000c00RR", + bc_2 = "000047000000RX-b", + bcr_2 = "000000000700RR", + bct_2 = "000046000000RX-a", + bctg_2 = "e30000000046RXY-a", + bctgr_2 = "0000b9460000RRE", + bctr_2 = "000000000600RR", + bras_2 = "0000a7050000RI-b", + brasl_2 = "c00500000000RIL-b", + brc_2 = "0000a7040000RI-c", + brcl_2 = "c00400000000RIL-c", + brct_2 = "0000a7060000RI-b", + brctg_2 = "0000a7070000RI-b", + brcth_2 = "cc0600000000RIL-b", + brxh_3 = "000084000000RSI", + brxhg_3 = "ec0000000044RIE-e", + bsa_2 = "0000b25a0000RRE", + bsg_2 = "0000b2580000RRE", + bsm_2 = "000000000b00RR", + bxh_3 = "000086000000RS-a", + bxhg_3 = "eb0000000044RSY-a", + bxle_3 = "000087000000RS-a", + bxleg_3 = "eb0000000045RSY-a", + c_2 = "000059000000RX-a", + cd_2 = "000069000000RX-a", + cdb_2 = "ed0000000019RXE", + cdbr_2 = "0000b3190000RRE", + cdfbr_2 = "0000b3950000RRE", + cdfbra_4 = "0000b3950000RRF-e", + cdfr_2 = "0000b3b50000RRE", + cdftr_2 = "0000b9510000RRE", + cdgbr_2 = "0000b3a50000RRE", + cdgbra_4 = "0000b3a50000RRF-e", + cdgr_2 = "0000b3c50000RRE", + cdgtr_2 = "0000b3f10000RRE", + cdr_2 = "000000002900RR", + cds_3 = "0000bb000000RS-a", + cdsg_3 = "eb000000003eRSY-a", + cdstr_2 = "0000b3f30000RRE", + cdsy_3 = "eb0000000031RSY-a", + cdtr_2 = "0000b3e40000RRE", + cdutr_2 = "0000b3f20000RRE", + ce_2 = "000079000000RX-a", + ceb_2 = "ed0000000009RXE", + cebr_2 = "0000b3090000RRE", + cedtr_2 = "0000b3f40000RRE", + cefbr_2 = "0000b3940000RRE", + cefbra_4 = "0000b3940000RRF-e", + cefr_2 = "0000b3b40000RRE", + cegbr_2 = "0000b3a40000RRE", + cegbra_4 = "0000b3a40000RRF-e", + cegr_2 = "0000b3c40000RRE", + cer_2 = "000000003900RR", + cextr_2 = "0000b3fc0000RRE", + cfdbr_3 = "0000b3990000RRF-e", + cfdbra_4 = "0000b3990000RRF-e", + cfebr_3 = "0000b3980000RRF-e", + cfebra_4 = "0000b3980000RRF-e", + cfi_2 = "c20d00000000RIL-a", + cfxbr_3 = "0000b39a0000RRF-e", + cfxbra_4 = "0000b39a0000RRF-e", + cg_2 = "e30000000020RXY-a", + cgdbr_3 = "0000b3a90000RRF-e", + cgdbra_4 = "0000b3a90000RRF-e", + cgebr_3 = "0000b3a80000RRF-e", + cgebra_4 = "0000b3a80000RRF-e", + cgf_2 = "e30000000030RXY-a", + cgfi_2 = "c20c00000000RIL-a", + cgfr_2 = "0000b9300000RRE", + cgfrl_2 = "c60c00000000RIL-b", + cgh_2 = "e30000000034RXY-a", + cghi_2 = "0000a70f0000RI-a", + cghrl_2 = "c60400000000RIL-b", + cgr_2 = "0000b9200000RRE", + cgrl_2 = "c60800000000RIL-b", + cgxbr_3 = "0000b3aa0000RRF-e", + cgxbra_4 = "0000b3aa0000RRF-e", + ch_2 = "000049000000RX-a", + chf_2 = "e300000000cdRXY-a", + chhr_2 = "0000b9cd0000RRE", + chi_2 = "0000a70e0000RI-a", + chlr_2 = "0000b9dd0000RRE", + chrl_2 = "c60500000000RIL-b", + chy_2 = "e30000000079RXY-a", + cih_2 = "cc0d00000000RIL-a", + cksm_2 = "0000b2410000RRE", + cl_2 = "000055000000RX-a", + clc_2 = "d50000000000SS-a", + clcl_2 = "000000000f00RR", + clcle_3 = "0000a9000000RS-a", + clclu_3 = "eb000000008fRSY-a", + clfi_2 = "c20f00000000RIL-a", + clg_2 = "e30000000021RXY-a", + clgf_2 = "e30000000031RXY-a", + clgfi_2 = "c20e00000000RIL-a", + clgfr_2 = "0000b9310000RRE", + clgfrl_2 = "c60e00000000RIL-b", + clghrl_2 = "c60600000000RIL-b", + clgr_2 = "0000b9210000RRE", + clgrl_2 = "c60a00000000RIL-b", + clhf_2 = "e300000000cfRXY-a", + clhhr_2 = "0000b9cf0000RRE", + clhlr_2 = "0000b9df0000RRE", + clhrl_2 = "c60700000000RIL-b", + cli_2 = "000095000000SI", + clih_2 = "cc0f00000000RIL-a", + clm_3 = "0000bd000000RS-b", + clmh_3 = "eb0000000020RSY-b", + clmy_3 = "eb0000000021RSY-b", + clr_2 = "000000001500RR", + clrl_2 = "c60f00000000RIL-b", + clst_2 = "0000b25d0000RRE", + cly_2 = "e30000000055RXY-a", + cmpsc_2 = "0000b2630000RRE", + cpya_2 = "0000b24d0000RRE", + cr_2 = "000000001900RR", + crl_2 = "c60d00000000RIL-b", + cs_3 = "0000ba000000RS-a", + csg_3 = "eb0000000030RSY-a", + csp_2 = "0000b2500000RRE", + cspg_2 = "0000b98a0000RRE", + csy_3 = "eb0000000014RSY-a", + cu41_2 = "0000b9b20000RRE", + cu42_2 = "0000b9b30000RRE", + cudtr_2 = "0000b3e20000RRE", + cuse_2 = "0000b2570000RRE", + cuxtr_2 = "0000b3ea0000RRE", + cvb_2 = "00004f000000RX-a", + cvbg_2 = "e3000000000eRXY-a", + cvby_2 = "e30000000006RXY-a", + cvd_2 = "00004e000000RX-a", + cvdg_2 = "e3000000002eRXY-a", + cvdy_2 = "e30000000026RXY-a", + cxbr_2 = "0000b3490000RRE", + cxfbr_2 = "0000b3960000RRE", + cxfbra_4 = "0000b3960000RRF-e", + cxfr_2 = "0000b3b60000RRE", + cxftr_2 = "0000b9590000RRE", + cxgbr_2 = "0000b3a60000RRE", + cxgbra_4 = "0000b3a60000RRF-e", + cxgr_2 = "0000b3c60000RRE", + cxgtr_2 = "0000b3f90000RRE", + cxr_2 = "0000b3690000RRE", + cxstr_2 = "0000b3fb0000RRE", + cxtr_2 = "0000b3ec0000RRE", + cxutr_2 = "0000b3fa0000RRE", + cy_2 = "e30000000059RXY-a", + d_2 = "00005d000000RX-a", + dd_2 = "00006d000000RX-a", + ddb_2 = "ed000000001dRXE", + ddbr_2 = "0000b31d0000RRE", + ddr_2 = "000000002d00RR", + de_2 = "00007d000000RX-a", + deb_2 = "ed000000000dRXE", + debr_2 = "0000b30d0000RRE", + der_2 = "000000003d00RR", + didbr_4 = "0000b35b0000RRF-b", + dl_2 = "e30000000097RXY-a", + dlg_2 = "e30000000087RXY-a", + dlgr_2 = "0000b9870000RRE", + dlr_2 = "0000b9970000RRE", + dr_2 = "000000001d00RR", + dsg_2 = "e3000000000dRXY-a", + dsgf_2 = "e3000000001dRXY-a", + dsgfr_2 = "0000b91d0000RRE", + dsgr_2 = "0000b90d0000RRE", + dxbr_2 = "0000b34d0000RRE", + dxr_2 = "0000b22d0000RRE", + ear_2 = "0000b24f0000RRE", + ecag_3 = "eb000000004cRSY-a", + ed_2 = "de0000000000SS-a", + edmk_2 = "df0000000000SS-a", + eedtr_2 = "0000b3e50000RRE", + eextr_2 = "0000b3ed0000RRE", + efpc_2 = "0000b38c0000RRE", + epair_2 = "0000b99a0000RRE", + epar_2 = "0000b2260000RRE", + epsw_2 = "0000b98d0000RRE", + ereg_2 = "0000b2490000RRE", + eregg_2 = "0000b90e0000RRE", + esair_2 = "0000b99b0000RRE", + esar_2 = "0000b2270000RRE", + esdtr_2 = "0000b3e70000RRE", + esea_2 = "0000b99d0000RRE", + esta_2 = "0000b24a0000RRE", + esxtr_2 = "0000b3ef0000RRE", + ex_2 = "000044000000RX-a", + exrl_2 = "c60000000000RIL-b", + fidbra_4 = "0000b35f0000RRF-e", + fidr_2 = "0000b37f0000RRE", + fier_2 = "0000b3770000RRE", + fixr_2 = "0000b3670000RRE", + flogr_2 = "0000b9830000RRE", + hdr_2 = "000000002400RR", + her_2 = "000000003400RR", + iac_2 = "0000b2240000RRE", + ic_2 = "000043000000RX-a", + icm_3 = "0000bf000000RS-b", + icmh_3 = "eb0000000080RSY-b", + icmy_3 = "eb0000000081RSY-b", + icy_2 = "e30000000073RXY-a", + iihf_2 = "c00800000000RIL-a", + iihh_2 = "0000a5000000RI-a", + iihl_2 = "0000a5010000RI-a", + iilf_2 = "c00900000000RIL-a", + iilh_2 = "0000a5020000RI-a", + iill_2 = "0000a5030000RI-a", + ipm_2 = "0000b2220000RRE", + iske_2 = "0000b2290000RRE", + ivsk_2 = "0000b2230000RRE", + kdbr_2 = "0000b3180000RRE", + kdtr_2 = "0000b3e00000RRE", + kebr_2 = "0000b3080000RRE", + kimd_2 = "0000b93e0000RRE", + klmd_2 = "0000b93f0000RRE", + km_2 = "0000b92e0000RRE", + kmac_2 = "0000b91e0000RRE", + kmc_2 = "0000b92f0000RRE", + kmf_2 = "0000b92a0000RRE", + kmo_2 = "0000b92b0000RRE", + kxbr_2 = "0000b3480000RRE", + kxtr_2 = "0000b3e80000RRE", + l_2 = "000058000000RX-a", + la_2 = "000041000000RX-a", + laa_3 = "eb00000000f8RSY-a", + laag_3 = "eb00000000e8RSY-a", + laal_3 = "eb00000000faRSY-a", + laalg_3 = "eb00000000eaRSY-a", + lae_2 = "000051000000RX-a", + laey_2 = "e30000000075RXY-a", + lam_3 = "00009a000000RS-a", + lamy_3 = "eb000000009aRSY-a", + lan_3 = "eb00000000f4RSY-a", + lang_3 = "eb00000000e4RSY-a", + lao_3 = "eb00000000f6RSY-a", + laog_3 = "eb00000000e6RSY-a", + larl_2 = "c00000000000RIL-b", + lax_3 = "eb00000000f7RSY-a", + laxg_3 = "eb00000000e7RSY-a", + lay_2 = "e30000000071RXY-a", + lb_2 = "e30000000076RXY-a", + lbh_2 = "e300000000c0RXY-a", + lbr_2 = "0000b9260000RRE", + lcdbr_2 = "0000b3130000RRE", + lcdfr_2 = "0000b3730000RRE", + lcdr_2 = "000000002300RR", + lcebr_2 = "0000b3030000RRE", + lcer_2 = "000000003300RR", + lcgfr_2 = "0000b9130000RRE", + lcgr_2 = "0000b9030000RRE", + lcr_2 = "000000001300RR", + lctl_3 = "0000b7000000RS-a", + lctlg_3 = "eb000000002fRSY-a", + lcxbr_2 = "0000b3430000RRE", + lcxr_2 = "0000b3630000RRE", + ld_2 = "000068000000RX-a", + ldebr_2 = "0000b3040000RRE", + lder_2 = "0000b3240000RRE", + ldgr_2 = "0000b3c10000RRE", + ldr_2 = "000000002800RR", + ldxbr_2 = "0000b3450000RRE", + ldxr_2 = "000000002500RR", + ldy_2 = "ed0000000065RXY-a", + le_2 = "000078000000RX-a", + ledbr_2 = "0000b3440000RRE", + ledr_2 = "000000003500RR", + ler_2 = "000000003800RR", + lexbr_2 = "0000b3460000RRE", + lexr_2 = "0000b3660000RRE", + ley_2 = "ed0000000064RXY-a", + lfh_2 = "e300000000caRXY-a", + lg_2 = "e30000000004RXY-a", + lgb_2 = "e30000000077RXY-a", + lgbr_2 = "0000b9060000RRE", + lgdr_2 = "0000b3cd0000RRE", + lgf_2 = "e30000000014RXY-a", + lgfi_2 = "c00100000000RIL-a", + lgfr_2 = "0000b9140000RRE", + lgfrl_2 = "c40c00000000RIL-b", + lgh_2 = "e30000000015RXY-a", + lghi_2 = "0000a7090000RI-a", + lghr_2 = "0000b9070000RRE", + lghrl_2 = "c40400000000RIL-b", + lgr_2 = "0000b9040000RRE", + lgrl_2 = "c40800000000RIL-b", + lh_2 = "000048000000RX-a", + lhh_2 = "e300000000c4RXY-a", + lhi_2 = "0000a7080000RI-a", + lhr_2 = "0000b9270000RRE", + lhrl_2 = "c40500000000RIL-b", + lhy_2 = "e30000000078RXY-a", + llc_2 = "e30000000094RXY-a", + llch_2 = "e300000000c2RXY-a", + llcr_2 = "0000b9940000RRE", + llgc_2 = "e30000000090RXY-a", + llgcr_2 = "0000b9840000RRE", + llgf_2 = "e30000000016RXY-a", + llgfr_2 = "0000b9160000RRE", + llgfrl_2 = "c40e00000000RIL-b", + llgh_2 = "e30000000091RXY-a", + llghr_2 = "0000b9850000RRE", + llghrl_2 = "c40600000000RIL-b", + llgt_2 = "e30000000017RXY-a", + llgtr_2 = "0000b9170000RRE", + llh_2 = "e30000000095RXY-a", + llhh_2 = "e300000000c6RXY-a", + llhr_2 = "0000b9950000RRE", + llhrl_2 = "c40200000000RIL-b", + llihf_2 = "c00e00000000RIL-a", + llihh_2 = "0000a50c0000RI-a", + llihl_2 = "0000a50d0000RI-a", + llilf_2 = "c00f00000000RIL-a", + llilh_2 = "0000a50e0000RI-a", + llill_2 = "0000a50f0000RI-a", + lm_3 = "000098000000RS-a", + lmg_3 = "eb0000000004RSY-a", + lmh_3 = "eb0000000096RSY-a", + lmy_3 = "eb0000000098RSY-a", + lndbr_2 = "0000b3110000RRE", + lndfr_2 = "0000b3710000RRE", + lndr_2 = "000000002100RR", + lnebr_2 = "0000b3010000RRE", + lner_2 = "000000003100RR", + lngfr_2 = "0000b9110000RRE", + lngr_2 = "0000b9010000RRE", + lnr_2 = "000000001100RR", + lnxbr_2 = "0000b3410000RRE", + lnxr_2 = "0000b3610000RRE", + loc_3 = "eb00000000f2RSY-b", + locg_3 = "eb00000000e2RSY-b", + lpdbr_2 = "0000b3100000RRE", + lpdfr_2 = "0000b3700000RRE", + lpdr_2 = "000000002000RR", + lpebr_2 = "0000b3000000RRE", + lper_2 = "000000003000RR", + lpgfr_2 = "0000b9100000RRE", + lpgr_2 = "0000b9000000RRE", + lpq_2 = "e3000000008fRXY-a", + lpr_2 = "000000001000RR", + lpxbr_2 = "0000b3400000RRE", + lpxr_2 = "0000b3600000RRE", + lr_2 = "000000001800RR", + lra_2 = "0000b1000000RX-a", + lrag_2 = "e30000000003RXY-a", + lray_2 = "e30000000013RXY-a", + lrdr_2 = "000000002500RR", + lrer_2 = "000000003500RR", + lrl_2 = "c40d00000000RIL-b", + lrv_2 = "e3000000001eRXY-a", + lrvg_2 = "e3000000000fRXY-a", + lrvgr_2 = "0000b90f0000RRE", + lrvh_2 = "e3000000001fRXY-a", + lrvr_2 = "0000b91f0000RRE", + lt_2 = "e30000000012RXY-a", + ltdbr_2 = "0000b3120000RRE", + ltdr_2 = "000000002200RR", + ltdtr_2 = "0000b3d60000RRE", + ltebr_2 = "0000b3020000RRE", + lter_2 = "000000003200RR", + ltg_2 = "e30000000002RXY-a", + ltgf_2 = "e30000000032RXY-a", + ltgfr_2 = "0000b9120000RRE", + ltgr_2 = "0000b9020000RRE", + ltr_2 = "000000001200RR", + ltxbr_2 = "0000b3420000RRE", + ltxr_2 = "0000b3620000RRE", + ltxtr_2 = "0000b3de0000RRE", + lura_2 = "0000b24b0000RRE", + lurag_2 = "0000b9050000RRE", + lxdbr_2 = "0000b3050000RRE", + lxdr_2 = "0000b3250000RRE", + lxebr_2 = "0000b3060000RRE", + lxer_2 = "0000b3260000RRE", + lxr_2 = "0000b3650000RRE", + ly_2 = "e30000000058RXY-a", + lzdr_2 = "0000b3750000RRE", + lzer_2 = "0000b3740000RRE", + lzxr_2 = "0000b3760000RRE", + m_2 = "00005c000000RX-a", + madb_3 = "ed000000001eRXF", + maeb_3 = "ed000000000eRXF", + maebr_3 = "0000b30e0000RRD", + maer_3 = "0000b32e0000RRD", + md_2 = "00006c000000RX-a", + mdb_2 = "ed000000001cRXE", + mdbr_2 = "0000b31c0000RRE", + mde_2 = "00007c000000RX-a", + mdeb_2 = "ed000000000cRXE", + mdebr_2 = "0000b30c0000RRE", + mder_2 = "000000003c00RR", + mdr_2 = "000000002c00RR", + me_2 = "00007c000000RX-a", + meeb_2 = "ed0000000017RXE", + meebr_2 = "0000b3170000RRE", + meer_2 = "0000b3370000RRE", + mer_2 = "000000003c00RR", + mfy_2 = "e3000000005cRXY-a", + mghi_2 = "0000a70d0000RI-a", + mh_2 = "00004c000000RX-a", + mhi_2 = "0000a70c0000RI-a", + mhy_2 = "e3000000007cRXY-a", + ml_2 = "e30000000096RXY-a", + mlg_2 = "e30000000086RXY-a", + mlgr_2 = "0000b9860000RRE", + mlr_2 = "0000b9960000RRE", + mr_2 = "000000001c00RR", + ms_2 = "000071000000RX-a", + msfi_2 = "c20100000000RIL-a", + msg_2 = "e3000000000cRXY-a", + msgf_2 = "e3000000001cRXY-a", + msgfi_2 = "c20000000000RIL-a", + msgfr_2 = "0000b91c0000RRE", + msgr_2 = "0000b90c0000RRE", + msr_2 = "0000b2520000RRE", + msta_2 = "0000b2470000RRE", + msy_2 = "e30000000051RXY-a", + mvc_2 = "d20000000000SS-a", + mvcin_2 = "e80000000000SS-a", + mvcl_2 = "000000000e00RR", + mvcle_3 = "0000a8000000RS-a", + mvclu_3 = "eb000000008eRSY-a", + mvghi_2 = "e54800000000SIL", + mvhhi_2 = "e54400000000SIL", + mvhi_2 = "e54c00000000SIL", + mvi_2 = "000092000000SI", + mvn_2 = "d10000000000SS-a", + mvpg_2 = "0000b2540000RRE", + mvst_2 = "0000b2550000RRE", + mvz_2 = "d30000000000SS-a", + mxbr_2 = "0000b34c0000RRE", + mxd_2 = "000067000000RX-a", + mxdb_2 = "ed0000000007RXE", + mxdbr_2 = "0000b3070000RRE", + mxdr_2 = "000000002700RR", + mxr_2 = "000000002600RR", + n_2 = "000054000000RX-a", + nc_2 = "d40000000000SS-a", + ng_2 = "e30000000080RXY-a", + ngr_2 = "0000b9800000RRE", + ni_2 = "000094000000SI", + nihf_2 = "c00a00000000RIL-a", + nihh_2 = "0000a5040000RI-a", + nihl_2 = "0000a5050000RI-a", + nilf_2 = "c00b00000000RIL-a", + nilh_2 = "0000a5060000RI-a", + nill_2 = "0000a5070000RI-a", + nr_2 = "000000001400RR", + ny_2 = "e30000000054RXY-a", + o_2 = "000056000000RX-a", + oc_2 = "d60000000000SS-a", + og_2 = "e30000000081RXY-a", + ogr_2 = "0000b9810000RRE", + oi_2 = "000096000000SI", + oihf_2 = "c00c00000000RIL-a", + oihh_2 = "0000a5080000RI-a", + oihl_2 = "0000a5090000RI-a", + oilf_2 = "c00d00000000RIL-a", + oilh_2 = "0000a50a0000RI-a", + oill_2 = "0000a50b0000RI-a", + or_2 = "000000001600RR", + oy_2 = "e30000000056RXY-a", + palb_2 = "0000b2480000RRE", + pcc_2 = "0000b92c0000RRE", + pckmo_2 = "0000b9280000RRE", + pfd_2 = "e30000000036m", + pfdrl_2 = "c60200000000RIL-c", + pfmf_2 = "0000b9af0000RRE", + pgin_2 = "0000b22e0000RRE", + pgout_2 = "0000b22f0000RRE", + popcnt_2 = "0000b9e10000RRE", + pt_2 = "0000b2280000RRE", + ptf_2 = "0000b9a20000RRE", + pti_2 = "0000b99e0000RRE", + rll_3 = "eb000000001dRSY-a", + rllg_3 = "eb000000001cRSY-a", + rrbe_2 = "0000b22a0000RRE", + rrbm_2 = "0000b9ae0000RRE", + s_2 = "00005b000000RX-a", + sar_2 = "0000b24e0000RRE", + sd_2 = "00006b000000RX-a", + sdb_2 = "ed000000001bRXE", + sdbr_2 = "0000b31b0000RRE", + sdr_2 = "000000002b00RR", + se_2 = "00007b000000RX-a", + seb_2 = "ed000000000bRXE", + sebr_2 = "0000b30b0000RRE", + ser_2 = "000000003b00RR", + sfasr_2 = "0000b3850000RRE", + sfpc_2 = "0000b3840000RRE", + sg_2 = "e30000000009RXY-a", + sgf_2 = "e30000000019RXY-a", + sgfr_2 = "0000b9190000RRE", + sgr_2 = "0000b9090000RRE", + sh_2 = "00004b000000RX-a", + shy_2 = "e3000000007bRXY-a", + sl_2 = "00005f000000RX-a", + sla_2 = "00008b000000RS-a", + slag_3 = "eb000000000bRSY-a", + slak_3 = "eb00000000ddRSY-a", + slb_2 = "e30000000099RXY-a", + slbg_2 = "e30000000089RXY-a", + slbgr_2 = "0000b9890000RRE", + slbr_2 = "0000b9990000RRE", + slda_2 = "00008f000000RS-a", + sldl_2 = "00008d000000RS-a", + slfi_2 = "c20500000000RIL-a", + slg_2 = "e3000000000bRXY-a", + slgf_2 = "e3000000001bRXY-a", + slgfi_2 = "c20400000000RIL-a", + slgfr_2 = "0000b91b0000RRE", + slgr_2 = "0000b90b0000RRE", + sll_2 = "000089000000RS-a", + sllg_3 = "eb000000000dRSY-a", + sllk_3 = "eb00000000dfRSY-a", + slr_2 = "000000001f00RR", + sly_2 = "e3000000005fRXY-a", + spm_2 = "000000000400RR", + sqdb_2 = "ed0000000015RXE", + sqdbr_2 = "0000b3150000RRE", + sqdr_2 = "0000b2440000RRE", + sqeb_2 = "ed0000000014RXE", + sqebr_2 = "0000b3140000RRE", + sqer_2 = "0000b2450000RRE", + sqxbr_2 = "0000b3160000RRE", + sqxr_2 = "0000b3360000RRE", + sr_2 = "000000001b00RR", + sra_2 = "00008a000000RS-a", + srag_3 = "eb000000000aRSY-a", + srak_3 = "eb00000000dcRSY-a", + srda_2 = "00008e000000RS-a", + srdl_2 = "00008c000000RS-a", + srl_2 = "000088000000RS-a", + srlg_3 = "eb000000000cRSY-a", + srlk_3 = "eb00000000deRSY-a", + srst_2 = "0000b25e0000RRE", + srstu_2 = "0000b9be0000RRE", + ssair_2 = "0000b99f0000RRE", + ssar_2 = "0000b2250000RRE", + st_2 = "000050000000RX-a", + stam_3 = "00009b000000RS-a", + stamy_3 = "eb000000009bRSY-a", + stc_2 = "000042000000RX-a", + stch_2 = "e300000000c3RXY-a", + stcm_3 = "0000be000000RS-b", + stcmh_3 = "eb000000002cRSY-b", + stcmy_3 = "eb000000002dRSY-b", + stctg_3 = "eb0000000025RSY-a", + stctl_3 = "0000b6000000RS-a", + stcy_2 = "e30000000072RXY-a", + std_2 = "000060000000RX-a", + stdy_2 = "ed0000000067RXY-a", + ste_2 = "000070000000RX-a", + stey_2 = "ed0000000066RXY-a", + stfh_2 = "e300000000cbRXY-a", + stfl_1 = "0000b2b10000S", + stg_2 = "e30000000024RXY-a", + stgrl_2 = "c40b00000000RIL-b", + sth_2 = "000040000000RX-a", + sthh_2 = "e300000000c7RXY-a", + sthrl_2 = "c40700000000RIL-b", + sthy_2 = "e30000000070RXY-a", + stm_3 = "000090000000RS-a", + stmg_3 = "eb0000000024RSY-a", + stmh_3 = "eb0000000026RSY-a", + stmy_3 = "eb0000000090RSY-a", + stoc_3 = "eb00000000f3RSY-b", + stocg_3 = "eb00000000e3RSY-b", + stpq_2 = "e3000000008eRXY-a", + strl_2 = "c40f00000000RIL-b", + strv_2 = "e3000000003eRXY-a", + strvg_2 = "e3000000002fRXY-a", + strvh_2 = "e3000000003fRXY-a", + stura_2 = "0000b2460000RRE", + sturg_2 = "0000b9250000RRE", + sty_2 = "e30000000050RXY-a", + su_2 = "00007f000000RX-a", + sur_2 = "000000003f00RR", + svc_1 = "000000000a00I", + sw_2 = "00006f000000RX-a", + swr_2 = "000000002f00RR", + sxbr_2 = "0000b34b0000RRE", + sxr_2 = "000000003700RR", + sy_2 = "e3000000005bRXY-a", + tar_2 = "0000b24c0000RRE", + tb_2 = "0000b22c0000RRE", + thder_2 = "0000b3580000RRE", + thdr_2 = "0000b3590000RRE", + tm_2 = "000091000000SI", + tmhh_2 = "0000a7020000RI-a", + tmhl_2 = "0000a7030000RI-a", + tmlh_2 = "0000a7000000RI-a", + tmll_2 = "0000a7010000RI-a", + tmy_2 = "eb0000000051SIY", + tr_2 = "dc0000000000SS-a", + trace_3 = "000099000000RS-a", + tracg_3 = "eb000000000fRSY-a", + tre_2 = "0000b2a50000RRE", + trt_2 = "dd0000000000SS-a", + trtr_2 = "d00000000000SS-a", + unpka_2 = "ea0000000000SS-a", + unpku_2 = "e20000000000SS-a", + x_2 = "000057000000RX-a", + xc_2 = "d70000000000SS-a", + xg_2 = "e30000000082RXY-a", + xgr_2 = "0000b9820000RRE", + xi_2 = "000097000000SI", + xihf_2 = "c00600000000RIL-a", + xilf_2 = "c00700000000RIL-a", + xr_2 = "000000001700RR", + xy_2 = "e30000000057RXY-a", +} +for cond, c in pairs(map_cond) do + -- Extended mnemonics for branches. + -- TODO: replace 'B' with correct encoding. + -- brc + map_op["j"..cond.."_1"] = "0000"..tohex(0xa7040000+shl(c, 20)).."RI-c" + -- brcl + map_op["jg"..cond.."_1"] = tohex(0xc0040000+shl(c, 20)).."0000".."RIL-c" + -- bc + map_op["b"..cond.."_1"] = "0000"..tohex(0x47000000+shl(c, 20)).."RX-b" + -- bcr + map_op["b"..cond.."r_1"] = "0000"..tohex(0x0700+shl(c, 4)).."RR" +end +------------------------------------------------------------------------------ +-- Handle opcodes defined with template strings. +local function parse_template(params, template, nparams, pos) + -- Read the template in 16-bit chunks. + -- Leading halfword zeroes should not be written out. + local op0 = tonumber(sub(template, 1, 4), 16) + local op1 = tonumber(sub(template, 5, 8), 16) + local op2 = tonumber(sub(template, 9, 12), 16) + + -- Process each character. + local p = sub(template, 13) + if p == "I" then + local imm_val, a = parse_imm8(params[1]) + op2 = op2 + imm_val + wputhw(op2) + if a then a() end + elseif p == "RI-a" then + op1 = op1 + shl(parse_reg(params[1]), 4) + wputhw(op1) + parse_imm16(params[2]) + elseif p == "RI-b" then + op1 = op1 + shl(parse_reg(params[1]), 4) + wputhw(op1) + local mode, n, s = parse_label(params[2]) + waction("REL_"..mode, n, s) + elseif p == "RI-c" then + if #params > 1 then + op1 = op1 + shl(parse_num(params[1]), 4) + end + wputhw(op1) + local mode, n, s = parse_label(params[#params]) + waction("REL_"..mode, n, s) + elseif p == "RIE-e" then + op0 = op0 + shl(parse_reg(params[1]), 4) + parse_reg(params[2]) + wputhw1(op0) + local mode, n, s = parse_label(params[3]) + waction("REL_"..mode, n, s) + wputhw(op2) + elseif p == "RIL-a" then + op0 = op0 + shl(parse_reg(params[1]), 4) + wputhw(op0); + parse_imm32(params[2]) + elseif p == "RIL-b" then + op0 = op0 + shl(parse_reg(params[1]), 4) + wputhw(op0) + local mode, n, s = parse_label(params[2]) + waction("REL_"..mode, n, s) + elseif p == "RIL-c" then + if #params > 1 then + op0 = op0 + shl(parse_num(params[1]), 4) + end + wputhw(op0) + local mode, n, s = parse_label(params[#params]) + waction("REL_"..mode, n, s) + elseif p == "RR" then + if #params > 1 then + op2 = op2 + shl(parse_reg(params[1]), 4) + end + op2 = op2 + parse_reg(params[#params]) + wputhw(op2) + elseif p == "RRD" then + wputhw(op1) + op2 = op2 + shl(parse_reg(params[1]), 12) + shl(parse_reg(params[2]), 4) + parse_reg(params[3]) + wputhw(op2) + elseif p == "RRE" then + op2 = op2 + shl(parse_reg(params[1]), 4) + parse_reg(params[2]) + wputhw(op1); wputhw(op2) + elseif p == "RRF-b" then + wputhw(op1) + op2 = op2 + shl(parse_reg(params[1]), 4) + shl(parse_reg(params[2]), 12) + parse_reg(params[3]) + shl(parse_mask(params[4]), 8) + wputhw(op2) + elseif p == "RRF-e" then + wputhw(op1) + op2 = op2 + shl(parse_reg(params[1]), 4) + shl(parse_mask(params[2]), 12) + parse_reg(params[3]) + if params[4] then + op2 = op2 + shl(parse_mask2(params[4]), 8) + end + wputhw(op2) + elseif p == "RS-a" then + if (params[3]) then + local d, b, a = parse_mem_b(params[3]) + op1 = op1 + shl(parse_reg(params[1]), 4) + parse_reg(params[2]) + op2 = op2 + shl(b, 12) + d + else + local d, b, a = parse_mem_b(params[2]) + op1 = op1 + shl(parse_reg(params[1]), 4) + op2 = op2 + shl(b, 12) + d + end + wputhw(op1); wputhw(op2) + if a then a() end + elseif p == "RS-b" then + local m = parse_mask(params[2]) + local d, b, a = parse_mem_b(params[3]) + op1 = op1 + shl(parse_reg(params[1]), 4) + m + op2 = op2 + shl(b, 12) + d + wputhw(op1); wputhw(op2) + if a then a() end + elseif p == "RSI" then + op1 = op1 + shl(parse_reg(params[1]), 4) + parse_reg(params[2]) + wputhw(op1) + local mode, n, s = parse_label(params[3]) + waction("REL_"..mode, n, s) + elseif p == "RSY-a" then + local d, b, a = parse_mem_by(params[3]) + op0 = op0 + shl(parse_reg(params[1]), 4) + parse_reg(params[2]) + op1 = op1 + shl(b, 12) + band(d, 0xfff) + op2 = op2 + band(shr(d, 4), 0xff00) + wputhw(op0); wputhw(op1); wputhw(op2) + if a then a() end -- a() emits action. + elseif p == "RX-a" then + local d, x, b, a = parse_mem_bx(params[2]) + op1 = op1 + shl(parse_reg(params[1]), 4) + x + op2 = op2 + shl(b, 12) + d + wputhw(op1); wputhw(op2) + if a then a() end + elseif p == "RX-b" then + local d, x, b, a = parse_mem_bx(params[#params]) + if #params > 1 then + op1 = op1 + shl(parse_num(params[1]), 4) + end + op1 = op1 + x + op2 = op2 + shl(b, 12) + d + wputhw(op1); wputhw(op2) + if a then a() end + elseif p == "RXE" then + local d, x, b, a = parse_mem_bx(params[2]) + op0 = op0 + shl(parse_reg(params[1]), 4) + x + op1 = op1 + shl(b, 12) + d + wputhw(op0); wputhw(op1) + if a then a() end + wputhw(op2); + elseif p == "RXF" then + local d, x, b, a = parse_mem_bx(params[3]) + op0 = op0 + shl(parse_reg(params[2]), 4) + x + op1 = op1 + shl(b, 12) + d + wputhw(op0); wputhw(op1) + if a then a() end + op2 = op2 + shl(parse_reg(params[1]), 12) + wputhw(op2) + elseif p == "RXY-a" then + local d, x, b, a = parse_mem_bxy(params[2]) + op0 = op0 + shl(parse_reg(params[1]), 4) + x + op1 = op1 + shl(b, 12) + band(d, 0xfff) + op2 = op2 + band(shr(d, 4), 0xff00) + wputhw(op0); wputhw(op1); wputhw(op2) + if a then a() end + elseif p == "S" then + wputhw(op1); + local d, b, a = parse_mem_b(params[1]) + op2 = op2 + shl(b, 12) + d + wputhw(op2) + if a then a() end + elseif p == "SI" then + local imm_val, a = parse_imm8(params[2]) + op1 = op1 + imm_val + wputhw(op1) + if a then a() end + local d, b, a = parse_mem_b(params[1]) + op2 = op2 + shl(b, 12) + d + wputhw(op2) + if a then a() end + elseif p == "SIL" then + wputhw(op0) + local d, b, a = parse_mem_b(params[1]) + op1 = op1 + shl(b, 12) + d + wputhw(op1) + if a then a() end + parse_imm16(params[2]) + elseif p == "SIY" then + local imm8, iact = parse_imm8(params[2]) + op0 = op0 + shl(imm8, 8) + wputhw(op0) + if iact then iact() end + local d, b, a = parse_mem_by(params[1]) + op1 = op1 + shl(b, 12) + band(d, 0xfff) + op2 = op2 + band(shr(d, 4), 0xff00) + wputhw(op1); wputhw(op2) + if a then a() end + elseif p == "SS-a" then + local d1, l1, b1, d1a, l1a = parse_mem_lb(params[1]) + local d2, b2, d2a = parse_mem_b(params[2]) + op0 = op0 + l1 + op1 = op1 + shl(b1, 12) + d1 + op2 = op2 + shl(b2, 12) + d2 + wputhw(op0) + if l1a then l1a() end + wputhw(op1) + if d1a then d1a() end + wputhw(op2) + if d2a then d2a() end + elseif p == "SS-b" then + local high_l = true + local d1, l1, b1, d1a, l1a = parse_mem_l2b(params[1], high_l) + high_l = false + local d2, l2, b2, d2a, l2a = parse_mem_l2b(params[2], high_l) + op0 = op0 + shl(l1, 4) + l2 + op1 = op1 + shl(b1, 12) + d1 + op2 = op2 + shl(b2, 12) + d2 + wputhw(op0) + if l1a then l1a() end + if l2a then l2a() end + wputhw(op1) + if d1a then d1a() end + wputhw(op2) + if d2a then d2a() end + else + werror("unrecognized encoding") + end +end + +function op_template(params, template, nparams) + if not params then return template:gsub("%x%x%x%x%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 5 positions. + if secpos+5 > maxsecpos then wflush() end + local lpos, apos, spos = #actlist, #actargs, secpos + local ok, err + for t in gmatch(template, "[^|]+") do + ok, err = pcall(parse_template, params, t, nparams) + 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 halfword 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 +------------------------------------------------------------------------------