aarch64.js (27384B)
1 // This file is part of AsmJit project <https://asmjit.com> 2 // 3 // See <asmjit/core.h> or LICENSE.md for license and copyright information 4 // SPDX-License-Identifier: Zlib 5 6 (function($scope, $as) { 7 "use strict"; 8 9 function FAIL(msg) { throw new Error("[AArch64] " + msg); } 10 11 // Import 12 // ====== 13 14 const base = $scope.base ? $scope.base : require("./base.js"); 15 const exp = $scope.exp ? $scope.exp : require("./exp.js") 16 17 const dict = base.dict; 18 const NONE = base.NONE; 19 const Parsing = base.Parsing; 20 const MapUtils = base.MapUtils; 21 22 // Export 23 // ====== 24 25 const arm = $scope[$as] = dict(); 26 27 // Database 28 // ======== 29 30 arm.dbName = "isa_aarch64.json"; 31 32 // asmdb.aarch64.Utils 33 // =================== 34 35 // Can be used to assign the number of bits each part of the opcode occupies. 36 // NOTE: THUMB instructions that use halfword must always specify the width 37 // of all registers as many instructions accept only LO (r0..r7) registers. 38 const FieldInfo = { 39 "P" : { "bits": 1 }, 40 "U" : { "bits": 1 }, 41 "W" : { "bits": 1 }, 42 "S" : { "bits": 1 }, 43 "R" : { "bits": 1 }, 44 "H" : { "bits": 1 }, 45 "F" : { "bits": 1 }, 46 "post" : { "bits": 1 }, 47 "!post" : { "bits": 1 }, 48 "op" : { "bits": 1 }, // TODO: This should be fixed. 49 "s" : { "bits": 1 }, 50 "sz" : { "bits": 2 }, 51 "msz" : { "bits": 2 }, 52 "sop" : { "bits": 2 }, 53 "cond" : { "bits": 4 }, 54 "nzcv" : { "bits": 4 }, 55 "cmode" : { "bits": 4 }, 56 "CRn" : { "bits": 4 }, 57 "CRm" : { "bits": 4 }, 58 59 "Rx" : { "bits": 5, "read": true , "write": true }, 60 "Rx2" : { "bits": 5, "read": true , "write": true }, 61 "Rdn" : { "bits": 5, "read": true , "write": true }, 62 "Rd" : { "bits": 5, "read": false, "write": true }, 63 "Rd2" : { "bits": 5, "read": false, "write": true }, 64 "Rs" : { "bits": 5, "read": true , "write": false }, 65 "Rs2" : { "bits": 5, "read": true , "write": false }, 66 "Rn" : { "bits": 5, "read": true , "write": false }, 67 "Rm" : { "bits": 5, "read": true , "write": false }, 68 "Ra" : { "bits": 5, "read": true , "write": false }, 69 "Rt" : { "bits": 5, "read": true , "write": false }, 70 "Rt2" : { "bits": 5, "read": true , "write": false }, 71 72 "Wx" : { "bits": 5, "read": true , "write": true }, 73 "Wx2" : { "bits": 5, "read": true , "write": true }, 74 "Wdn" : { "bits": 5, "read": true , "write": true }, 75 "Wd" : { "bits": 5, "read": false, "write": true }, 76 "Wd2" : { "bits": 5, "read": false, "write": true }, 77 "Ws" : { "bits": 5, "read": true , "write": false }, 78 "Ws2" : { "bits": 5, "read": true , "write": false }, 79 "Wn" : { "bits": 5, "read": true , "write": false }, 80 "Wm" : { "bits": 5, "read": true , "write": false }, 81 "Wa" : { "bits": 5, "read": true , "write": false }, 82 "Wt" : { "bits": 5, "read": true , "write": false }, 83 "Wt2" : { "bits": 5, "read": true , "write": false }, 84 85 "Xx" : { "bits": 5, "read": true , "write": true }, 86 "Xx2" : { "bits": 5, "read": true , "write": true }, 87 "Xdn" : { "bits": 5, "read": true , "write": true }, 88 "Xd" : { "bits": 5, "read": false, "write": true }, 89 "Xd2" : { "bits": 5, "read": false, "write": true }, 90 "Xs" : { "bits": 5, "read": true , "write": false }, 91 "Xs2" : { "bits": 5, "read": true , "write": false }, 92 "Xn" : { "bits": 5, "read": true , "write": false }, 93 "Xm" : { "bits": 5, "read": true , "write": false }, 94 "Xa" : { "bits": 5, "read": true , "write": false }, 95 "Xt" : { "bits": 5, "read": true , "write": false }, 96 "Xt2" : { "bits": 5, "read": true , "write": false }, 97 98 "Bx" : { "bits": 5, "read": true , "write": true }, 99 "Bx2" : { "bits": 5, "read": true , "write": true }, 100 "Bdn" : { "bits": 5, "read": true , "write": true }, 101 "Bd" : { "bits": 5, "read": false, "write": true }, 102 "Bd2" : { "bits": 5, "read": false, "write": true }, 103 "Bs" : { "bits": 5, "read": true , "write": false }, 104 "Bs2" : { "bits": 5, "read": true , "write": false }, 105 "Bn" : { "bits": 5, "read": true , "write": false }, 106 "Bm" : { "bits": 5, "read": true , "write": false }, 107 "Ba" : { "bits": 5, "read": true , "write": false }, 108 109 "Hx" : { "bits": 5, "read": true , "write": true }, 110 "Hx2" : { "bits": 5, "read": true , "write": true }, 111 "Hdn" : { "bits": 5, "read": true , "write": true }, 112 "Hd" : { "bits": 5, "read": false, "write": true }, 113 "Hd2" : { "bits": 5, "read": false, "write": true }, 114 "Hs" : { "bits": 5, "read": true , "write": false }, 115 "Hs2" : { "bits": 5, "read": true , "write": false }, 116 "Hn" : { "bits": 5, "read": true , "write": false }, 117 "Hm" : { "bits": 5, "read": true , "write": false }, 118 "Ha" : { "bits": 5, "read": true , "write": false }, 119 120 "Sx" : { "bits": 5, "read": true , "write": true }, 121 "Sx2" : { "bits": 5, "read": true , "write": true }, 122 "Sdn" : { "bits": 5, "read": true , "write": true }, 123 "Sd" : { "bits": 5, "read": false, "write": true }, 124 "Sd2" : { "bits": 5, "read": false, "write": true }, 125 "Ss" : { "bits": 5, "read": true , "write": false }, 126 "Ss2" : { "bits": 5, "read": true , "write": false }, 127 "Sn" : { "bits": 5, "read": true , "write": false }, 128 "Sm" : { "bits": 5, "read": true , "write": false }, 129 "Sa" : { "bits": 5, "read": true , "write": false }, 130 131 "Dx" : { "bits": 5, "read": true , "write": true }, 132 "Dx2" : { "bits": 5, "read": true , "write": true }, 133 "Ddn" : { "bits": 5, "read": true , "write": true }, 134 "Dd" : { "bits": 5, "read": false, "write": true }, 135 "Dd2" : { "bits": 5, "read": false, "write": true }, 136 "Ds" : { "bits": 5, "read": true , "write": false }, 137 "Ds2" : { "bits": 5, "read": true , "write": false }, 138 "Dn" : { "bits": 5, "read": true , "write": false }, 139 "Dn2" : { "bits": 5, "read": true , "write": false }, 140 "Dm" : { "bits": 5, "read": true , "write": false }, 141 "Da" : { "bits": 5, "read": true , "write": false }, 142 143 "Qx" : { "bits": 5, "read": true , "write": true }, 144 "Qx2" : { "bits": 5, "read": true , "write": true }, 145 "Qdn" : { "bits": 5, "read": true , "write": true }, 146 "Qd" : { "bits": 5, "read": false, "write": true }, 147 "Qd2" : { "bits": 5, "read": false, "write": true }, 148 "Qs" : { "bits": 5, "read": true , "write": false }, 149 "Qs2" : { "bits": 5, "read": true , "write": false }, 150 "Qn" : { "bits": 5, "read": true , "write": false }, 151 "Qn2" : { "bits": 5, "read": true , "write": false }, 152 "Qm" : { "bits": 5, "read": true , "write": false }, 153 "Qa" : { "bits": 5, "read": true , "write": false }, 154 155 "Vx" : { "bits": 5, "read": true , "write": true }, 156 "Vx2" : { "bits": 5, "read": true , "write": true }, 157 "Vdn" : { "bits": 5, "read": true , "write": true }, 158 "Vd" : { "bits": 5, "read": false, "write": true }, 159 "Vd2" : { "bits": 5, "read": false, "write": true }, 160 "Vs" : { "bits": 5, "read": true , "write": false }, 161 "Vs2" : { "bits": 5, "read": true , "write": false }, 162 "Vn" : { "bits": 5, "read": true , "write": false }, 163 "Vm" : { "bits": 5, "read": true , "write": false }, 164 "Va" : { "bits": 5, "read": true , "write": false }, 165 166 "Zx" : { "bits": 5, "read": true , "write": true }, 167 "Zx2" : { "bits": 5, "read": true , "write": true }, 168 "Zda" : { "bits": 5, "read": true , "write": true }, 169 "Zdn" : { "bits": 5, "read": true , "write": true }, 170 "Zdn2" : { "bits": 5, "read": true , "write": true }, 171 "Zd" : { "bits": 5, "read": false, "write": true }, 172 "Zd2" : { "bits": 5, "read": false, "write": true }, 173 "Zs" : { "bits": 5, "read": true , "write": false }, 174 "Zs2" : { "bits": 5, "read": true , "write": false }, 175 "Zn" : { "bits": 5, "read": true , "write": false }, 176 "Zm" : { "bits": 5, "read": true , "write": false }, 177 "Zk" : { "bits": 5, "read": true , "write": false }, 178 "Za" : { "bits": 5, "read": true , "write": false }, 179 180 "Pdn" : { "bits": 4, "read": true , "write": true }, 181 "Pdm" : { "bits": 4, "read": true , "write": true }, 182 "Pd" : { "bits": 4, "read": false, "write": true }, 183 "Ps" : { "bits": 4, "read": true , "write": false }, 184 "Pn" : { "bits": 4, "read": true , "write": false }, 185 "Pm" : { "bits": 4, "read": true , "write": false }, 186 "Pg" : { "bits": 4, "read": true , "write": false } 187 }; 188 189 arm.FieldInfo = FieldInfo; 190 191 // AArch64 utilities. 192 class Utils { 193 static splitInstructionSignature(s) { 194 const names = s.match(/^[\w\|]+/)[0]; 195 s = s.substring(names.length); 196 197 const opOffset = s.indexOf(" ") 198 const suffix = s.substring(0, opOffset).trim(); 199 const operands = opOffset === -1 ? "" : s.substring(opOffset + 1).trim(); 200 201 return { 202 names: names.split("|").map((base)=>{ return base + suffix}), 203 operands: operands 204 } 205 } 206 207 static parseShiftOrExtendOp(s) { 208 const space = s.indexOf(" "); 209 if (space === -1) 210 return ""; 211 212 const ops = s.substring(0, space).trim(); 213 for (let op of ops.split("|")) 214 if (!/^(sop|extend|lsl|lsr|asr|uxtw|sxtw|sxtx|mul)$/.test(op)) 215 return ""; 216 217 return ops; 218 } 219 } 220 arm.Utils = Utils; 221 222 function normalizeNumber(n) { 223 return n < 0 ? 0x100000000 + n : n; 224 } 225 226 function decomposeOperand(s) { 227 let type = null; 228 let element = null; 229 let consecutive = 0; 230 let maskType = ""; 231 232 const elementM = s.match(/\[#(\w+)\]$/); 233 if (elementM) { 234 element = elementM[1]; 235 s = s.substring(0, s.length - elementM[0].length); 236 } 237 238 const typeM = s.match(/\.(\w+)$/); 239 if (typeM) { 240 type = typeM[1]; 241 s = s.substring(0, s.length - typeM[0].length); 242 } 243 244 const maskM = s.match(/\/(M|Z|MZ)$/); 245 if (maskM) { 246 maskType = maskM[1]; 247 s = s.substring(0, s.length - maskM[0].length); 248 } 249 250 if (s.endsWith("++")) { 251 consecutive = 2; 252 s = s.substring(0, s.length - 2); 253 } 254 else if (s.endsWith("+")) { 255 consecutive = 1; 256 s = s.substring(0, s.length - 1); 257 } 258 259 let m = s.match(/==|\!=|>=|<=|\*/); 260 let restrict = false; 261 262 if (m) { 263 restrict = s.substring(m.index); 264 s = s.substring(0, m.index); 265 } 266 267 return { 268 data : s, 269 maskType : maskType, 270 type : type, 271 element : element, 272 restrict : restrict, 273 consecutive: consecutive 274 }; 275 } 276 277 function splitOpcodeFields(s) { 278 const arr = s.split("|"); 279 const out = []; 280 281 for (let i = 0; i < arr.length; i++) { 282 const val = arr[i]; 283 if (/^[0-1A-Z]{2,}$/.test(val)) 284 out.push.apply(out, val.match(/([0-1]+)|[A-Z]/g)); 285 else 286 out.push(val); 287 } 288 289 return out.map((field)=>{return field.trim(); }); 290 } 291 292 // asmdb.aarch64.Operand 293 // ===================== 294 295 // ARM operand. 296 class Operand extends base.Operand { 297 constructor(def) { 298 super(); 299 this.data = def; 300 301 // Register. 302 this.sp = ""; // GP register stack access: ["", "WSP" or "SP"]. 303 this.mask = ""; // Masking specifier. 304 } 305 306 hasMemModes() { 307 return Object.keys(this.memModes).length !== 0; 308 } 309 310 get name() { 311 switch (this.type) { 312 case "reg": return this.reg; 313 case "mem": return this.mem; 314 case "imm": return this.imm; 315 case "rel": return this.rel; 316 default : return ""; 317 } 318 } 319 320 get scale() { 321 if (this.restrict && this.restrict.startsWith("*")) 322 return parseInt(this.restrict.substring(1), 10); 323 else 324 return 0; 325 } 326 } 327 arm.Operand = Operand; 328 329 // asmdb.aarch64.Instruction 330 // ========================= 331 332 function patternFromOperand(key) { return key; } 333 334 // ARM instruction. 335 class Instruction extends base.Instruction { 336 constructor(db, data) { 337 super(db, data); 338 339 this.name = data.name; 340 this.it = dict(); // THUMB's 'it' flags. 341 this.apsr = dict(); 342 this.fpcsr = dict(); 343 this.calc = dict(); // Calculations required to generate opcode. 344 this.immCond = []; // Immediate value conditions (array of conditions). 345 346 this._assignOperands(data.operands); 347 this._assignOpcode(data.op); 348 349 for (let k in data) { 350 if (k === "name" || k == "op" || k === "operands") 351 continue; 352 this._assignAttribute(k, data[k]); 353 } 354 355 this._updateOperandsInfo(); 356 this._postProcess(); 357 } 358 359 _assignAttribute(key, value) { 360 switch (key) { 361 case "it": 362 for (let it of value.split(" ")) 363 this.it[it.trim()] = true; 364 break; 365 366 case "apsr": 367 case "fpcsr": 368 this._assignAttributeKeyValue(key, value); 369 break; 370 371 case "imm": 372 this.imm = exp.parse(value); 373 break; 374 375 case "calc": 376 for (let calcKey in value) 377 this.calc[calcKey] = exp.parse(value[calcKey]); 378 break; 379 380 default: 381 super._assignAttribute(key, value); 382 } 383 } 384 385 _assignAttributeKeyValue(name, content) { 386 const attributes = content.trim().split(/[ ]+/); 387 388 for (let i = 0; i < attributes.length; i++) { 389 const attr = attributes[i].trim(); 390 if (!attr) 391 continue; 392 393 const eq = attr.indexOf("="); 394 let key = eq === -1 ? attr : attr.substring(0, eq); 395 let val = eq === -1 ? true : attr.substring(eq + 1); 396 397 // If the key contains "|" it's a definition of multiple attributes. 398 if (key.indexOf("|") !== -1) { 399 const dot = key.indexOf("."); 400 401 const base = dot === -1 ? "" : key.substring(0, dot + 1); 402 const keys = (dot === -1 ? key : key.substring(dot + 1)).split("|"); 403 404 for (let j = 0; j < keys.length; j++) 405 this[name][base + keys[j]] = val; 406 } 407 else { 408 this[name][key] = val; 409 } 410 } 411 } 412 413 _assignOperands(s) { 414 if (!s) return; 415 416 // Split into individual operands and push them to `operands`. 417 const arr = base.Parsing.splitOperands(s); 418 for (let i = 0; i < arr.length; i++) { 419 let def = arr[i].trim(); 420 const op = new Operand(def); 421 422 const sp = def.match(/^(\w+)\|(SP|WSP)$/); 423 if (sp) { 424 def = sp[1]; 425 op.sp = sp[2]; 426 } 427 428 const consecutive = def.match(/(\d+)x\{(.*)\}([+]?[+]?)/); 429 if (consecutive) 430 def = consecutive[2]; 431 432 op.sign = false; 433 op.element = null; 434 op.shiftOp = ""; 435 op.shiftImm = null; 436 op.shiftCond = ""; 437 438 // Handle {optional} attribute. 439 if (Parsing.isOptional(def)) { 440 op.optional = true; 441 def = Parsing.clearOptional(def); 442 } 443 444 // Handle commutativity <-> symbol. 445 if (Parsing.isCommutative(def)) { 446 op.commutative = true; 447 def = Parsing.clearCommutative(def); 448 } 449 450 // Handle shift operation. 451 let shiftOp = Utils.parseShiftOrExtendOp(def); 452 if (shiftOp) { 453 op.shiftOp = shiftOp; 454 def = def.substring(shiftOp.length + 1); 455 } 456 457 if (def.startsWith("[")) { 458 op.type = "mem"; 459 op.memModes = dict(); 460 461 op.base = null; 462 op.index = null; 463 op.offset = null; 464 465 let mem = def; 466 let didHaveMemMode = false; 467 468 for (;;) { 469 if (mem.endsWith("!")) { 470 op.memModes.preIndex = true; 471 mem = mem.substring(0, mem.length - 1); 472 473 didHaveMemMode = true; 474 break; 475 } 476 477 if (mem.endsWith("@")) { 478 op.memModes.postIndex = true; 479 mem = mem.substring(0, mem.length - 1); 480 481 didHaveMemMode = true; 482 break; 483 } 484 485 if (mem.endsWith("{!}")) { 486 op.memModes.offset = true; 487 op.memModes.preIndex = true; 488 mem = mem.substring(0, mem.length - 3); 489 490 didHaveMemMode = true; 491 continue; 492 } 493 494 if (mem.endsWith("{@}")) { 495 op.memModes.offset = true; 496 op.memModes.postIndex = true; 497 mem = mem.substring(0, mem.length - 3); 498 499 didHaveMemMode = true; 500 continue; 501 } 502 503 break; 504 } 505 506 if (!mem.endsWith("]")) 507 FAIL(`Unknown memory operand '${mem}' in '${def}'`); 508 509 let parts = mem.substring(1, mem.length - 1).split(",").map(function(s) { return s.trim() }); 510 for (let i = 0; i < parts.length; i++) { 511 const part = parts[i]; 512 513 const m = part.match(/^\{(([a-z]+)(\|[a-z]+)*)\s+#(\w+)\s*(\*\s*\d+\s*)?\}$/); 514 if (m) { 515 op.shiftOp = m[1]; 516 op.shiftImm = m[2]; 517 if (m[3]) 518 op.shiftCond = m[3] 519 continue; 520 } 521 522 if (i === 0) { 523 op.base = dict(); 524 op.base.field = part; 525 op.base.exp = null; 526 527 const m = part.match(/^([A-Za-z]\w*(?:\.\w+)?)/); 528 if (m && m[1].length < part.length) { 529 op.base.exp = exp.parse(part); 530 op.base.field = m[1]; 531 } 532 } 533 else if (part.startsWith("#")) { 534 let p = part.substring(1); 535 let u = "1"; 536 537 let offExp = null; 538 let offMul = 1; 539 540 if (p.startsWith("+/-")) { 541 u = "U"; 542 p = p.substring(3); 543 } 544 545 const expMatch = p.match(/^([A-Za-z]\w*)==/); 546 if (expMatch) { 547 offExp = exp.parse(p); 548 p = p.substring(0, expMatch[1].length); 549 } 550 551 const mulMatch = p.match(/\s*\*\s*(\d+)$/); 552 if (mulMatch) { 553 offMul = parseInt(mulMatch[1]); 554 p = p.substring(0, mulMatch.index); 555 } 556 557 op.offset = dict(); 558 op.offset.field = p; 559 op.offset.u = u; 560 op.offset.exp = offExp; 561 op.offset.mul = offMul; 562 } 563 else { 564 let p = part; 565 let u = "1"; 566 567 if (p.startsWith("+/-")) { 568 u = "U"; 569 p = p.substring(3); 570 } 571 572 op.index = dict(); 573 op.index.field = p; 574 op.index.u = u; 575 576 const m = p.match(/^([A-Za-z\|]\w*(?:\.\w+)?)/); 577 if (m && m[1].length < p.length) { 578 op.index.exp = exp.parse(p); 579 op.index.field = m[1]; 580 } 581 } 582 } 583 584 if (!op.hasMemModes() && (op.offset || op.index)) 585 op.memModes.offset = true; 586 587 op.mem = mem; 588 } 589 else if (def.startsWith("#")) { 590 const obj = decomposeOperand(def); 591 const imm = obj.data; 592 593 op.type = "imm"; 594 op.imm = imm.substring(1); // Immediate operand name. 595 op.immSize = 0; // Immediate size in bits. 596 op.restrict = obj.restrict; // Immediate condition. 597 } 598 else { 599 // Some instructions use Reg! to specify that the register increments. 600 if (def.endsWith("!")) { 601 def = def.substring(0, def.length - 1) 602 op.regInc = true 603 } 604 605 const obj = decomposeOperand(def); 606 const reg = obj.data; 607 608 const type = reg.substring(0, 1).toLowerCase(); 609 const info = FieldInfo[reg]; 610 611 if (!info) 612 FAIL(`Unknown register operand '${reg}' in '${def}'`); 613 614 op.type = info.list ? "reg-list" : "reg"; 615 op.reg = reg; // Register name (as specified in manual). 616 op.regType = type; // Register type. 617 op.regList = !!info.list; // Register list. 618 op.maskType = obj.maskType; // Mask type. 619 op.elementType = obj.type // Element type or t, ta, tb. 620 op.read = info.read; // Register access (read). 621 op.write = info.write; // Register access (write). 622 op.element = obj.element; // Register element[] access. 623 op.restrict = obj.restrict; // Register condition. 624 op.consecutive = obj.consecutive; 625 } 626 627 this.operands.push(op); 628 629 if (consecutive) { 630 const count = parseInt(consecutive[1]); 631 for (let n = 2; n <= count; n++) { 632 const def = consecutive[3].replace(op.reg, op.reg + n); 633 const opN = new Operand(def); 634 opN.type = "reg"; 635 opN.reg = op.reg + n; 636 opN.regType = op.regType; 637 opN.read = op.read; 638 opN.write = op.write; 639 opN.element = op.element; 640 opN.consecutive = consecutive[3].length; 641 opN.artificial = true; 642 this.operands.push(opN); 643 } 644 } 645 } 646 } 647 648 _assignOpcode(s) { 649 this.opcodeString = s; 650 651 let opcodeIndex = 0; 652 let opcodeValue = 0; 653 654 let patternMap = {}; 655 656 // Split opcode into its fields. 657 const arr = splitOpcodeFields(s); 658 const dup = dict(); 659 660 const fields = this.fields; 661 const pattern = []; 662 663 const fieldMap = Object.create(null); 664 for (let field of arr) { 665 fieldMap[field] = true; 666 } 667 668 for (let i = arr.length - 1; i >= 0; i--) { 669 let key = arr[i].trim(); 670 let m; 671 672 if (/^[0-1]+$/.test(key)) { 673 // This part of the opcode is RAW bits, they contribute to the `opcodeValue`. 674 opcodeValue |= parseInt(key, 2) << opcodeIndex; 675 opcodeIndex += key.length; 676 pattern.unshift("_".repeat(key.length)); 677 } 678 else { 679 pattern.unshift(patternFromOperand(key)); 680 patternMap[patternFromOperand(key)] = true; 681 682 let size = 0; 683 let mask = 0; 684 let bits = 0; 685 let from = -1; 686 687 let lbit = key.startsWith("'"); 688 let hbit = key.endsWith("'"); 689 690 if ((m = key.match(/\[\s*(\d+)\s*\:\s*(\d+)\s*\]$/))) { 691 const a = parseInt(m[1], 10); 692 const b = parseInt(m[2], 10); 693 if (a < b) 694 FAIL(`Invalid bit range '${key}' in opcode '${s}'`); 695 from = b; 696 size = a - b + 1; 697 mask = ((1 << size) - 1) << b; 698 key = key.substring(0, m.index).trim(); 699 } 700 else if ((m = key.match(/\[\s*(\d+)\s*\]$/))) { 701 from = parseInt(m[1], 10); 702 size = 1; 703 mask = 1 << from; 704 key = key.substring(0, m.index).trim(); 705 } 706 else if ((m = key.match(/\:\s*(\d+)$/))) { 707 size = parseInt(m[1], 10); 708 bits = size; 709 key = key.substring(0, m.index).trim(); 710 } 711 else { 712 const key_ = key; 713 714 if (lbit || hbit) { 715 from = 0; 716 717 if (lbit && hbit) 718 FAIL(`Couldn't recognize the format of '${key}' in opcode '${s}'`); 719 720 if (lbit) { 721 key = key.substring(1); 722 } 723 724 if (hbit) { 725 key = key.substring(0, key.length - 1); 726 from = 4; 727 } 728 729 size = 1; 730 } 731 else if (FieldInfo[key]) { 732 // Sizes of some standard fields can be assigned automatically. 733 size = FieldInfo[key].bits; 734 bits = size; 735 736 if (fieldMap["'" + key]) 737 from = 1; 738 } 739 else if (key.length === 1) { 740 // Sizes of one-letter fields (like 'U', 'F', etc...) is 1 if not specified. 741 size = 1; 742 bits = 1; 743 } 744 else { 745 FAIL(`Couldn't recognize the size of '${key}' in opcode '${s}'`); 746 } 747 748 if (dup[key_] === true) { 749 bits = 0; 750 lbit = 0; 751 hbit = 0; 752 } 753 else { 754 dup[key_] = true; 755 } 756 } 757 758 let field = fields[key]; 759 if (!field) { 760 field = { 761 index: opcodeIndex, 762 values: [], 763 bits: 0, 764 mask: 0, 765 lbit: 0, 766 hbit: 0 // Only 1 if a single quote (') was used. 767 } 768 fields[key] = field; 769 } 770 771 if (from === -1) 772 from = field.bits; 773 774 field.mask |= mask; 775 field.bits += bits; 776 field.lbit += lbit; 777 field.hbit += hbit; 778 field.values.push({ 779 index: opcodeIndex, 780 from: from, 781 size: size 782 }); 783 784 opcodeIndex += size; 785 } 786 } 787 788 for (let i = 0; i < pattern.length; i++) 789 if (pattern[i] === 'U') 790 pattern[i] = "_"; 791 792 // Normalize all fields. 793 for (let key in fields) { 794 const field = fields[key]; 795 796 // There should be either number of bits or mask, there shouldn't be both. 797 if (!field.bits && !field.mask) 798 FAIL(`Part '${key}' of opcode '${s}' contains neither size nor mask`); 799 800 if (field.bits && field.mask) 801 FAIL(`Part '${key}' of opcode '${s}' contains both size and mask`); 802 803 if (field.bits) 804 field.mask = ((1 << field.bits) - 1); 805 else if (field.mask) 806 field.bits = 32 - Math.clz32(field.mask); 807 808 // Handle field that used single-quote. 809 if (field.lbit) { 810 field.mask = (field.mask << 1) | 0x1; 811 field.bits++; 812 } 813 814 if (field.hbit) { 815 field.mask |= 1 << field.bits; 816 field.bits++; 817 } 818 819 const op = this.operandByName(key); 820 if (op && op.isImm()) 821 op.immSize = field.bits; 822 } 823 824 // Check if the opcode value has the correct number of bits. 825 if (opcodeIndex !== 32) 826 FAIL(`The number of bits '${opcodeIndex}' used by the opcode '${s}' doesn't match 32`); 827 this.opcodeValue = normalizeNumber(opcodeValue); 828 } 829 830 _assignSpecificAttribute(key, value) { 831 switch (key) { 832 case "it": { 833 const values = String(value).split("|"); 834 for (let i = 0; i < values.length; i++) { 835 const value = values[i]; 836 switch (value) { 837 case "in" : this.it.IN = true; break; 838 case "out" : this.it.OUT = true; break; 839 case "any" : this.it.IN = true; 840 this.it.OUT = true; break; 841 case "last": this.it.LAST = true; break; 842 case "def" : this.it.DEF = true; break; 843 default: 844 this.report(`${this.name}: Unhandled IT value '${value}'`); 845 } 846 } 847 return true; 848 } 849 } 850 851 return false; 852 } 853 854 _postProcess() {} 855 856 operandByName(name) { 857 const operands = this.operands; 858 for (let i = 0; i < operands.length; i++) { 859 const op = operands[i]; 860 if (op.name === name) 861 return op; 862 } 863 return null; 864 } 865 } 866 arm.Instruction = Instruction; 867 868 // asmdb.aarch64.ISA 869 // ================= 870 871 function mergeGroupData(data, group) { 872 for (let k in group) { 873 switch (k) { 874 case "group": 875 case "data": 876 break; 877 878 case "ext": 879 data[k] = (data[k] ? data[k] + " " : "") + group[k]; 880 break; 881 882 default: 883 if (data[k] === undefined) 884 data[k] = group[k] 885 break; 886 } 887 } 888 } 889 890 class ISA extends base.ISA { 891 constructor(data) { 892 super(data); 893 this.addData(data || NONE); 894 } 895 896 _addInstructions(groups) { 897 for (let group of groups) { 898 for (let instructions of group.data) { 899 const sgn = Utils.splitInstructionSignature(instructions.inst); 900 const data = MapUtils.cloneExcept(instructions, { "inst": true }); 901 902 mergeGroupData(data, group) 903 904 for (let j = 0; j < sgn.names.length; j++) { 905 data.name = sgn.names[j]; 906 data.operands = sgn.operands; 907 if (j > 0) 908 data.aliasOf = sgn.names[0]; 909 this._addInstruction(new Instruction(this, data)); 910 } 911 } 912 } 913 914 return this; 915 } 916 } 917 arm.ISA = ISA; 918 919 }).apply(this, typeof module === "object" && module && module.exports 920 ? [module, "exports"] : [this.asmdb || (this.asmdb = {}), "aarch64"]);