diff options
Diffstat (limited to '3rdparty/asmjit/db/aarch64.js')
| -rw-r--r-- | 3rdparty/asmjit/db/aarch64.js | 920 |
1 files changed, 920 insertions, 0 deletions
diff --git a/3rdparty/asmjit/db/aarch64.js b/3rdparty/asmjit/db/aarch64.js new file mode 100644 index 00000000000..af3b623c1af --- /dev/null +++ b/3rdparty/asmjit/db/aarch64.js @@ -0,0 +1,920 @@ +// This file is part of AsmJit project <https://asmjit.com> +// +// See <asmjit/core.h> or LICENSE.md for license and copyright information +// SPDX-License-Identifier: Zlib + +(function($scope, $as) { +"use strict"; + +function FAIL(msg) { throw new Error("[AArch64] " + msg); } + +// Import +// ====== + +const base = $scope.base ? $scope.base : require("./base.js"); +const exp = $scope.exp ? $scope.exp : require("./exp.js") + +const dict = base.dict; +const NONE = base.NONE; +const Parsing = base.Parsing; +const MapUtils = base.MapUtils; + +// Export +// ====== + +const arm = $scope[$as] = dict(); + +// Database +// ======== + +arm.dbName = "isa_aarch64.json"; + +// asmdb.aarch64.Utils +// =================== + +// Can be used to assign the number of bits each part of the opcode occupies. +// NOTE: THUMB instructions that use halfword must always specify the width +// of all registers as many instructions accept only LO (r0..r7) registers. +const FieldInfo = { + "P" : { "bits": 1 }, + "U" : { "bits": 1 }, + "W" : { "bits": 1 }, + "S" : { "bits": 1 }, + "R" : { "bits": 1 }, + "H" : { "bits": 1 }, + "F" : { "bits": 1 }, + "post" : { "bits": 1 }, + "!post" : { "bits": 1 }, + "op" : { "bits": 1 }, // TODO: This should be fixed. + "s" : { "bits": 1 }, + "sz" : { "bits": 2 }, + "msz" : { "bits": 2 }, + "sop" : { "bits": 2 }, + "cond" : { "bits": 4 }, + "nzcv" : { "bits": 4 }, + "cmode" : { "bits": 4 }, + "CRn" : { "bits": 4 }, + "CRm" : { "bits": 4 }, + + "Rx" : { "bits": 5, "read": true , "write": true }, + "Rx2" : { "bits": 5, "read": true , "write": true }, + "Rdn" : { "bits": 5, "read": true , "write": true }, + "Rd" : { "bits": 5, "read": false, "write": true }, + "Rd2" : { "bits": 5, "read": false, "write": true }, + "Rs" : { "bits": 5, "read": true , "write": false }, + "Rs2" : { "bits": 5, "read": true , "write": false }, + "Rn" : { "bits": 5, "read": true , "write": false }, + "Rm" : { "bits": 5, "read": true , "write": false }, + "Ra" : { "bits": 5, "read": true , "write": false }, + "Rt" : { "bits": 5, "read": true , "write": false }, + "Rt2" : { "bits": 5, "read": true , "write": false }, + + "Wx" : { "bits": 5, "read": true , "write": true }, + "Wx2" : { "bits": 5, "read": true , "write": true }, + "Wdn" : { "bits": 5, "read": true , "write": true }, + "Wd" : { "bits": 5, "read": false, "write": true }, + "Wd2" : { "bits": 5, "read": false, "write": true }, + "Ws" : { "bits": 5, "read": true , "write": false }, + "Ws2" : { "bits": 5, "read": true , "write": false }, + "Wn" : { "bits": 5, "read": true , "write": false }, + "Wm" : { "bits": 5, "read": true , "write": false }, + "Wa" : { "bits": 5, "read": true , "write": false }, + "Wt" : { "bits": 5, "read": true , "write": false }, + "Wt2" : { "bits": 5, "read": true , "write": false }, + + "Xx" : { "bits": 5, "read": true , "write": true }, + "Xx2" : { "bits": 5, "read": true , "write": true }, + "Xdn" : { "bits": 5, "read": true , "write": true }, + "Xd" : { "bits": 5, "read": false, "write": true }, + "Xd2" : { "bits": 5, "read": false, "write": true }, + "Xs" : { "bits": 5, "read": true , "write": false }, + "Xs2" : { "bits": 5, "read": true , "write": false }, + "Xn" : { "bits": 5, "read": true , "write": false }, + "Xm" : { "bits": 5, "read": true , "write": false }, + "Xa" : { "bits": 5, "read": true , "write": false }, + "Xt" : { "bits": 5, "read": true , "write": false }, + "Xt2" : { "bits": 5, "read": true , "write": false }, + + "Bx" : { "bits": 5, "read": true , "write": true }, + "Bx2" : { "bits": 5, "read": true , "write": true }, + "Bdn" : { "bits": 5, "read": true , "write": true }, + "Bd" : { "bits": 5, "read": false, "write": true }, + "Bd2" : { "bits": 5, "read": false, "write": true }, + "Bs" : { "bits": 5, "read": true , "write": false }, + "Bs2" : { "bits": 5, "read": true , "write": false }, + "Bn" : { "bits": 5, "read": true , "write": false }, + "Bm" : { "bits": 5, "read": true , "write": false }, + "Ba" : { "bits": 5, "read": true , "write": false }, + + "Hx" : { "bits": 5, "read": true , "write": true }, + "Hx2" : { "bits": 5, "read": true , "write": true }, + "Hdn" : { "bits": 5, "read": true , "write": true }, + "Hd" : { "bits": 5, "read": false, "write": true }, + "Hd2" : { "bits": 5, "read": false, "write": true }, + "Hs" : { "bits": 5, "read": true , "write": false }, + "Hs2" : { "bits": 5, "read": true , "write": false }, + "Hn" : { "bits": 5, "read": true , "write": false }, + "Hm" : { "bits": 5, "read": true , "write": false }, + "Ha" : { "bits": 5, "read": true , "write": false }, + + "Sx" : { "bits": 5, "read": true , "write": true }, + "Sx2" : { "bits": 5, "read": true , "write": true }, + "Sdn" : { "bits": 5, "read": true , "write": true }, + "Sd" : { "bits": 5, "read": false, "write": true }, + "Sd2" : { "bits": 5, "read": false, "write": true }, + "Ss" : { "bits": 5, "read": true , "write": false }, + "Ss2" : { "bits": 5, "read": true , "write": false }, + "Sn" : { "bits": 5, "read": true , "write": false }, + "Sm" : { "bits": 5, "read": true , "write": false }, + "Sa" : { "bits": 5, "read": true , "write": false }, + + "Dx" : { "bits": 5, "read": true , "write": true }, + "Dx2" : { "bits": 5, "read": true , "write": true }, + "Ddn" : { "bits": 5, "read": true , "write": true }, + "Dd" : { "bits": 5, "read": false, "write": true }, + "Dd2" : { "bits": 5, "read": false, "write": true }, + "Ds" : { "bits": 5, "read": true , "write": false }, + "Ds2" : { "bits": 5, "read": true , "write": false }, + "Dn" : { "bits": 5, "read": true , "write": false }, + "Dn2" : { "bits": 5, "read": true , "write": false }, + "Dm" : { "bits": 5, "read": true , "write": false }, + "Da" : { "bits": 5, "read": true , "write": false }, + + "Qx" : { "bits": 5, "read": true , "write": true }, + "Qx2" : { "bits": 5, "read": true , "write": true }, + "Qdn" : { "bits": 5, "read": true , "write": true }, + "Qd" : { "bits": 5, "read": false, "write": true }, + "Qd2" : { "bits": 5, "read": false, "write": true }, + "Qs" : { "bits": 5, "read": true , "write": false }, + "Qs2" : { "bits": 5, "read": true , "write": false }, + "Qn" : { "bits": 5, "read": true , "write": false }, + "Qn2" : { "bits": 5, "read": true , "write": false }, + "Qm" : { "bits": 5, "read": true , "write": false }, + "Qa" : { "bits": 5, "read": true , "write": false }, + + "Vx" : { "bits": 5, "read": true , "write": true }, + "Vx2" : { "bits": 5, "read": true , "write": true }, + "Vdn" : { "bits": 5, "read": true , "write": true }, + "Vd" : { "bits": 5, "read": false, "write": true }, + "Vd2" : { "bits": 5, "read": false, "write": true }, + "Vs" : { "bits": 5, "read": true , "write": false }, + "Vs2" : { "bits": 5, "read": true , "write": false }, + "Vn" : { "bits": 5, "read": true , "write": false }, + "Vm" : { "bits": 5, "read": true , "write": false }, + "Va" : { "bits": 5, "read": true , "write": false }, + + "Zx" : { "bits": 5, "read": true , "write": true }, + "Zx2" : { "bits": 5, "read": true , "write": true }, + "Zda" : { "bits": 5, "read": true , "write": true }, + "Zdn" : { "bits": 5, "read": true , "write": true }, + "Zdn2" : { "bits": 5, "read": true , "write": true }, + "Zd" : { "bits": 5, "read": false, "write": true }, + "Zd2" : { "bits": 5, "read": false, "write": true }, + "Zs" : { "bits": 5, "read": true , "write": false }, + "Zs2" : { "bits": 5, "read": true , "write": false }, + "Zn" : { "bits": 5, "read": true , "write": false }, + "Zm" : { "bits": 5, "read": true , "write": false }, + "Zk" : { "bits": 5, "read": true , "write": false }, + "Za" : { "bits": 5, "read": true , "write": false }, + + "Pdn" : { "bits": 4, "read": true , "write": true }, + "Pdm" : { "bits": 4, "read": true , "write": true }, + "Pd" : { "bits": 4, "read": false, "write": true }, + "Ps" : { "bits": 4, "read": true , "write": false }, + "Pn" : { "bits": 4, "read": true , "write": false }, + "Pm" : { "bits": 4, "read": true , "write": false }, + "Pg" : { "bits": 4, "read": true , "write": false } +}; + +arm.FieldInfo = FieldInfo; + +// AArch64 utilities. +class Utils { + static splitInstructionSignature(s) { + const names = s.match(/^[\w\|]+/)[0]; + s = s.substring(names.length); + + const opOffset = s.indexOf(" ") + const suffix = s.substring(0, opOffset).trim(); + const operands = opOffset === -1 ? "" : s.substring(opOffset + 1).trim(); + + return { + names: names.split("|").map((base)=>{ return base + suffix}), + operands: operands + } + } + + static parseShiftOrExtendOp(s) { + const space = s.indexOf(" "); + if (space === -1) + return ""; + + const ops = s.substring(0, space).trim(); + for (let op of ops.split("|")) + if (!/^(sop|extend|lsl|lsr|asr|uxtw|sxtw|sxtx|mul)$/.test(op)) + return ""; + + return ops; + } +} +arm.Utils = Utils; + +function normalizeNumber(n) { + return n < 0 ? 0x100000000 + n : n; +} + +function decomposeOperand(s) { + let type = null; + let element = null; + let consecutive = 0; + let maskType = ""; + + const elementM = s.match(/\[#(\w+)\]$/); + if (elementM) { + element = elementM[1]; + s = s.substring(0, s.length - elementM[0].length); + } + + const typeM = s.match(/\.(\w+)$/); + if (typeM) { + type = typeM[1]; + s = s.substring(0, s.length - typeM[0].length); + } + + const maskM = s.match(/\/(M|Z|MZ)$/); + if (maskM) { + maskType = maskM[1]; + s = s.substring(0, s.length - maskM[0].length); + } + + if (s.endsWith("++")) { + consecutive = 2; + s = s.substring(0, s.length - 2); + } + else if (s.endsWith("+")) { + consecutive = 1; + s = s.substring(0, s.length - 1); + } + + let m = s.match(/==|\!=|>=|<=|\*/); + let restrict = false; + + if (m) { + restrict = s.substring(m.index); + s = s.substring(0, m.index); + } + + return { + data : s, + maskType : maskType, + type : type, + element : element, + restrict : restrict, + consecutive: consecutive + }; +} + +function splitOpcodeFields(s) { + const arr = s.split("|"); + const out = []; + + for (let i = 0; i < arr.length; i++) { + const val = arr[i]; + if (/^[0-1A-Z]{2,}$/.test(val)) + out.push.apply(out, val.match(/([0-1]+)|[A-Z]/g)); + else + out.push(val); + } + + return out.map((field)=>{return field.trim(); }); +} + +// asmdb.aarch64.Operand +// ===================== + +// ARM operand. +class Operand extends base.Operand { + constructor(def) { + super(); + this.data = def; + + // Register. + this.sp = ""; // GP register stack access: ["", "WSP" or "SP"]. + this.mask = ""; // Masking specifier. + } + + hasMemModes() { + return Object.keys(this.memModes).length !== 0; + } + + get name() { + switch (this.type) { + case "reg": return this.reg; + case "mem": return this.mem; + case "imm": return this.imm; + case "rel": return this.rel; + default : return ""; + } + } + + get scale() { + if (this.restrict && this.restrict.startsWith("*")) + return parseInt(this.restrict.substring(1), 10); + else + return 0; + } +} +arm.Operand = Operand; + +// asmdb.aarch64.Instruction +// ========================= + +function patternFromOperand(key) { return key; } + +// ARM instruction. +class Instruction extends base.Instruction { + constructor(db, data) { + super(db, data); + + this.name = data.name; + this.it = dict(); // THUMB's 'it' flags. + this.apsr = dict(); + this.fpcsr = dict(); + this.calc = dict(); // Calculations required to generate opcode. + this.immCond = []; // Immediate value conditions (array of conditions). + + this._assignOperands(data.operands); + this._assignOpcode(data.op); + + for (let k in data) { + if (k === "name" || k == "op" || k === "operands") + continue; + this._assignAttribute(k, data[k]); + } + + this._updateOperandsInfo(); + this._postProcess(); + } + + _assignAttribute(key, value) { + switch (key) { + case "it": + for (let it of value.split(" ")) + this.it[it.trim()] = true; + break; + + case "apsr": + case "fpcsr": + this._assignAttributeKeyValue(key, value); + break; + + case "imm": + this.imm = exp.parse(value); + break; + + case "calc": + for (let calcKey in value) + this.calc[calcKey] = exp.parse(value[calcKey]); + break; + + default: + super._assignAttribute(key, value); + } + } + + _assignAttributeKeyValue(name, content) { + const attributes = content.trim().split(/[ ]+/); + + for (let i = 0; i < attributes.length; i++) { + const attr = attributes[i].trim(); + if (!attr) + continue; + + const eq = attr.indexOf("="); + let key = eq === -1 ? attr : attr.substring(0, eq); + let val = eq === -1 ? true : attr.substring(eq + 1); + + // If the key contains "|" it's a definition of multiple attributes. + if (key.indexOf("|") !== -1) { + const dot = key.indexOf("."); + + const base = dot === -1 ? "" : key.substring(0, dot + 1); + const keys = (dot === -1 ? key : key.substring(dot + 1)).split("|"); + + for (let j = 0; j < keys.length; j++) + this[name][base + keys[j]] = val; + } + else { + this[name][key] = val; + } + } + } + + _assignOperands(s) { + if (!s) return; + + // Split into individual operands and push them to `operands`. + const arr = base.Parsing.splitOperands(s); + for (let i = 0; i < arr.length; i++) { + let def = arr[i].trim(); + const op = new Operand(def); + + const sp = def.match(/^(\w+)\|(SP|WSP)$/); + if (sp) { + def = sp[1]; + op.sp = sp[2]; + } + + const consecutive = def.match(/(\d+)x\{(.*)\}([+]?[+]?)/); + if (consecutive) + def = consecutive[2]; + + op.sign = false; + op.element = null; + op.shiftOp = ""; + op.shiftImm = null; + op.shiftCond = ""; + + // Handle {optional} attribute. + if (Parsing.isOptional(def)) { + op.optional = true; + def = Parsing.clearOptional(def); + } + + // Handle commutativity <-> symbol. + if (Parsing.isCommutative(def)) { + op.commutative = true; + def = Parsing.clearCommutative(def); + } + + // Handle shift operation. + let shiftOp = Utils.parseShiftOrExtendOp(def); + if (shiftOp) { + op.shiftOp = shiftOp; + def = def.substring(shiftOp.length + 1); + } + + if (def.startsWith("[")) { + op.type = "mem"; + op.memModes = dict(); + + op.base = null; + op.index = null; + op.offset = null; + + let mem = def; + let didHaveMemMode = false; + + for (;;) { + if (mem.endsWith("!")) { + op.memModes.preIndex = true; + mem = mem.substring(0, mem.length - 1); + + didHaveMemMode = true; + break; + } + + if (mem.endsWith("@")) { + op.memModes.postIndex = true; + mem = mem.substring(0, mem.length - 1); + + didHaveMemMode = true; + break; + } + + if (mem.endsWith("{!}")) { + op.memModes.offset = true; + op.memModes.preIndex = true; + mem = mem.substring(0, mem.length - 3); + + didHaveMemMode = true; + continue; + } + + if (mem.endsWith("{@}")) { + op.memModes.offset = true; + op.memModes.postIndex = true; + mem = mem.substring(0, mem.length - 3); + + didHaveMemMode = true; + continue; + } + + break; + } + + if (!mem.endsWith("]")) + FAIL(`Unknown memory operand '${mem}' in '${def}'`); + + let parts = mem.substring(1, mem.length - 1).split(",").map(function(s) { return s.trim() }); + for (let i = 0; i < parts.length; i++) { + const part = parts[i]; + + const m = part.match(/^\{(([a-z]+)(\|[a-z]+)*)\s+#(\w+)\s*(\*\s*\d+\s*)?\}$/); + if (m) { + op.shiftOp = m[1]; + op.shiftImm = m[2]; + if (m[3]) + op.shiftCond = m[3] + continue; + } + + if (i === 0) { + op.base = dict(); + op.base.field = part; + op.base.exp = null; + + const m = part.match(/^([A-Za-z]\w*(?:\.\w+)?)/); + if (m && m[1].length < part.length) { + op.base.exp = exp.parse(part); + op.base.field = m[1]; + } + } + else if (part.startsWith("#")) { + let p = part.substring(1); + let u = "1"; + + let offExp = null; + let offMul = 1; + + if (p.startsWith("+/-")) { + u = "U"; + p = p.substring(3); + } + + const expMatch = p.match(/^([A-Za-z]\w*)==/); + if (expMatch) { + offExp = exp.parse(p); + p = p.substring(0, expMatch[1].length); + } + + const mulMatch = p.match(/\s*\*\s*(\d+)$/); + if (mulMatch) { + offMul = parseInt(mulMatch[1]); + p = p.substring(0, mulMatch.index); + } + + op.offset = dict(); + op.offset.field = p; + op.offset.u = u; + op.offset.exp = offExp; + op.offset.mul = offMul; + } + else { + let p = part; + let u = "1"; + + if (p.startsWith("+/-")) { + u = "U"; + p = p.substring(3); + } + + op.index = dict(); + op.index.field = p; + op.index.u = u; + + const m = p.match(/^([A-Za-z\|]\w*(?:\.\w+)?)/); + if (m && m[1].length < p.length) { + op.index.exp = exp.parse(p); + op.index.field = m[1]; + } + } + } + + if (!op.hasMemModes() && (op.offset || op.index)) + op.memModes.offset = true; + + op.mem = mem; + } + else if (def.startsWith("#")) { + const obj = decomposeOperand(def); + const imm = obj.data; + + op.type = "imm"; + op.imm = imm.substring(1); // Immediate operand name. + op.immSize = 0; // Immediate size in bits. + op.restrict = obj.restrict; // Immediate condition. + } + else { + // Some instructions use Reg! to specify that the register increments. + if (def.endsWith("!")) { + def = def.substring(0, def.length - 1) + op.regInc = true + } + + const obj = decomposeOperand(def); + const reg = obj.data; + + const type = reg.substring(0, 1).toLowerCase(); + const info = FieldInfo[reg]; + + if (!info) + FAIL(`Unknown register operand '${reg}' in '${def}'`); + + op.type = info.list ? "reg-list" : "reg"; + op.reg = reg; // Register name (as specified in manual). + op.regType = type; // Register type. + op.regList = !!info.list; // Register list. + op.maskType = obj.maskType; // Mask type. + op.elementType = obj.type // Element type or t, ta, tb. + op.read = info.read; // Register access (read). + op.write = info.write; // Register access (write). + op.element = obj.element; // Register element[] access. + op.restrict = obj.restrict; // Register condition. + op.consecutive = obj.consecutive; + } + + this.operands.push(op); + + if (consecutive) { + const count = parseInt(consecutive[1]); + for (let n = 2; n <= count; n++) { + const def = consecutive[3].replace(op.reg, op.reg + n); + const opN = new Operand(def); + opN.type = "reg"; + opN.reg = op.reg + n; + opN.regType = op.regType; + opN.read = op.read; + opN.write = op.write; + opN.element = op.element; + opN.consecutive = consecutive[3].length; + opN.artificial = true; + this.operands.push(opN); + } + } + } + } + + _assignOpcode(s) { + this.opcodeString = s; + + let opcodeIndex = 0; + let opcodeValue = 0; + + let patternMap = {}; + + // Split opcode into its fields. + const arr = splitOpcodeFields(s); + const dup = dict(); + + const fields = this.fields; + const pattern = []; + + const fieldMap = Object.create(null); + for (let field of arr) { + fieldMap[field] = true; + } + + for (let i = arr.length - 1; i >= 0; i--) { + let key = arr[i].trim(); + let m; + + if (/^[0-1]+$/.test(key)) { + // This part of the opcode is RAW bits, they contribute to the `opcodeValue`. + opcodeValue |= parseInt(key, 2) << opcodeIndex; + opcodeIndex += key.length; + pattern.unshift("_".repeat(key.length)); + } + else { + pattern.unshift(patternFromOperand(key)); + patternMap[patternFromOperand(key)] = true; + + let size = 0; + let mask = 0; + let bits = 0; + let from = -1; + + let lbit = key.startsWith("'"); + let hbit = key.endsWith("'"); + + if ((m = key.match(/\[\s*(\d+)\s*\:\s*(\d+)\s*\]$/))) { + const a = parseInt(m[1], 10); + const b = parseInt(m[2], 10); + if (a < b) + FAIL(`Invalid bit range '${key}' in opcode '${s}'`); + from = b; + size = a - b + 1; + mask = ((1 << size) - 1) << b; + key = key.substring(0, m.index).trim(); + } + else if ((m = key.match(/\[\s*(\d+)\s*\]$/))) { + from = parseInt(m[1], 10); + size = 1; + mask = 1 << from; + key = key.substring(0, m.index).trim(); + } + else if ((m = key.match(/\:\s*(\d+)$/))) { + size = parseInt(m[1], 10); + bits = size; + key = key.substring(0, m.index).trim(); + } + else { + const key_ = key; + + if (lbit || hbit) { + from = 0; + + if (lbit && hbit) + FAIL(`Couldn't recognize the format of '${key}' in opcode '${s}'`); + + if (lbit) { + key = key.substring(1); + } + + if (hbit) { + key = key.substring(0, key.length - 1); + from = 4; + } + + size = 1; + } + else if (FieldInfo[key]) { + // Sizes of some standard fields can be assigned automatically. + size = FieldInfo[key].bits; + bits = size; + + if (fieldMap["'" + key]) + from = 1; + } + else if (key.length === 1) { + // Sizes of one-letter fields (like 'U', 'F', etc...) is 1 if not specified. + size = 1; + bits = 1; + } + else { + FAIL(`Couldn't recognize the size of '${key}' in opcode '${s}'`); + } + + if (dup[key_] === true) { + bits = 0; + lbit = 0; + hbit = 0; + } + else { + dup[key_] = true; + } + } + + let field = fields[key]; + if (!field) { + field = { + index: opcodeIndex, + values: [], + bits: 0, + mask: 0, + lbit: 0, + hbit: 0 // Only 1 if a single quote (') was used. + } + fields[key] = field; + } + + if (from === -1) + from = field.bits; + + field.mask |= mask; + field.bits += bits; + field.lbit += lbit; + field.hbit += hbit; + field.values.push({ + index: opcodeIndex, + from: from, + size: size + }); + + opcodeIndex += size; + } + } + + for (let i = 0; i < pattern.length; i++) + if (pattern[i] === 'U') + pattern[i] = "_"; + + // Normalize all fields. + for (let key in fields) { + const field = fields[key]; + + // There should be either number of bits or mask, there shouldn't be both. + if (!field.bits && !field.mask) + FAIL(`Part '${key}' of opcode '${s}' contains neither size nor mask`); + + if (field.bits && field.mask) + FAIL(`Part '${key}' of opcode '${s}' contains both size and mask`); + + if (field.bits) + field.mask = ((1 << field.bits) - 1); + else if (field.mask) + field.bits = 32 - Math.clz32(field.mask); + + // Handle field that used single-quote. + if (field.lbit) { + field.mask = (field.mask << 1) | 0x1; + field.bits++; + } + + if (field.hbit) { + field.mask |= 1 << field.bits; + field.bits++; + } + + const op = this.operandByName(key); + if (op && op.isImm()) + op.immSize = field.bits; + } + + // Check if the opcode value has the correct number of bits. + if (opcodeIndex !== 32) + FAIL(`The number of bits '${opcodeIndex}' used by the opcode '${s}' doesn't match 32`); + this.opcodeValue = normalizeNumber(opcodeValue); + } + + _assignSpecificAttribute(key, value) { + switch (key) { + case "it": { + const values = String(value).split("|"); + for (let i = 0; i < values.length; i++) { + const value = values[i]; + switch (value) { + case "in" : this.it.IN = true; break; + case "out" : this.it.OUT = true; break; + case "any" : this.it.IN = true; + this.it.OUT = true; break; + case "last": this.it.LAST = true; break; + case "def" : this.it.DEF = true; break; + default: + this.report(`${this.name}: Unhandled IT value '${value}'`); + } + } + return true; + } + } + + return false; + } + + _postProcess() {} + + operandByName(name) { + const operands = this.operands; + for (let i = 0; i < operands.length; i++) { + const op = operands[i]; + if (op.name === name) + return op; + } + return null; + } +} +arm.Instruction = Instruction; + +// asmdb.aarch64.ISA +// ================= + +function mergeGroupData(data, group) { + for (let k in group) { + switch (k) { + case "group": + case "data": + break; + + case "ext": + data[k] = (data[k] ? data[k] + " " : "") + group[k]; + break; + + default: + if (data[k] === undefined) + data[k] = group[k] + break; + } + } +} + +class ISA extends base.ISA { + constructor(data) { + super(data); + this.addData(data || NONE); + } + + _addInstructions(groups) { + for (let group of groups) { + for (let instructions of group.data) { + const sgn = Utils.splitInstructionSignature(instructions.inst); + const data = MapUtils.cloneExcept(instructions, { "inst": true }); + + mergeGroupData(data, group) + + for (let j = 0; j < sgn.names.length; j++) { + data.name = sgn.names[j]; + data.operands = sgn.operands; + if (j > 0) + data.aliasOf = sgn.names[0]; + this._addInstruction(new Instruction(this, data)); + } + } + } + + return this; + } +} +arm.ISA = ISA; + +}).apply(this, typeof module === "object" && module && module.exports + ? [module, "exports"] : [this.asmdb || (this.asmdb = {}), "aarch64"]); |
