Mercurial
comparison third_party/luajit/src/jit/dis_arm64.lua @ 178:94705b5986b3
[ThirdParty] Added WRK and luajit for load testing.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Thu, 22 Jan 2026 20:10:30 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 177:24fe8ff94056 | 178:94705b5986b3 |
|---|---|
| 1 ---------------------------------------------------------------------------- | |
| 2 -- LuaJIT ARM64 disassembler module. | |
| 3 -- | |
| 4 -- Copyright (C) 2005-2023 Mike Pall. All rights reserved. | |
| 5 -- Released under the MIT license. See Copyright Notice in luajit.h | |
| 6 -- | |
| 7 -- Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com. | |
| 8 -- Sponsored by Cisco Systems, Inc. | |
| 9 ---------------------------------------------------------------------------- | |
| 10 -- This is a helper module used by the LuaJIT machine code dumper module. | |
| 11 -- | |
| 12 -- It disassembles most user-mode AArch64 instructions. | |
| 13 -- NYI: Advanced SIMD and VFP instructions. | |
| 14 ------------------------------------------------------------------------------ | |
| 15 | |
| 16 local type = type | |
| 17 local sub, byte, format = string.sub, string.byte, string.format | |
| 18 local match, gmatch, gsub = string.match, string.gmatch, string.gsub | |
| 19 local concat = table.concat | |
| 20 local bit = require("bit") | |
| 21 local band, bor, bxor, tohex = bit.band, bit.bor, bit.bxor, bit.tohex | |
| 22 local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift | |
| 23 local ror = bit.ror | |
| 24 | |
| 25 ------------------------------------------------------------------------------ | |
| 26 -- Opcode maps | |
| 27 ------------------------------------------------------------------------------ | |
| 28 | |
| 29 local map_adr = { -- PC-relative addressing. | |
| 30 shift = 31, mask = 1, | |
| 31 [0] = "adrDBx", "adrpDBx" | |
| 32 } | |
| 33 | |
| 34 local map_addsubi = { -- Add/subtract immediate. | |
| 35 shift = 29, mask = 3, | |
| 36 [0] = "add|movDNIg", "adds|cmnD0NIg", "subDNIg", "subs|cmpD0NIg", | |
| 37 } | |
| 38 | |
| 39 local map_logi = { -- Logical immediate. | |
| 40 shift = 31, mask = 1, | |
| 41 [0] = { | |
| 42 shift = 22, mask = 1, | |
| 43 [0] = { | |
| 44 shift = 29, mask = 3, | |
| 45 [0] = "andDNig", "orr|movDN0ig", "eorDNig", "ands|tstD0Nig" | |
| 46 }, | |
| 47 false -- unallocated | |
| 48 }, | |
| 49 { | |
| 50 shift = 29, mask = 3, | |
| 51 [0] = "andDNig", "orr|movDN0ig", "eorDNig", "ands|tstD0Nig" | |
| 52 } | |
| 53 } | |
| 54 | |
| 55 local map_movwi = { -- Move wide immediate. | |
| 56 shift = 31, mask = 1, | |
| 57 [0] = { | |
| 58 shift = 22, mask = 1, | |
| 59 [0] = { | |
| 60 shift = 29, mask = 3, | |
| 61 [0] = "movnDWRg", false, "movz|movDYRg", "movkDWRg" | |
| 62 }, false -- unallocated | |
| 63 }, | |
| 64 { | |
| 65 shift = 29, mask = 3, | |
| 66 [0] = "movnDWRg", false, "movz|movDYRg", "movkDWRg" | |
| 67 }, | |
| 68 } | |
| 69 | |
| 70 local map_bitf = { -- Bitfield. | |
| 71 shift = 31, mask = 1, | |
| 72 [0] = { | |
| 73 shift = 22, mask = 1, | |
| 74 [0] = { | |
| 75 shift = 29, mask = 3, | |
| 76 [0] = "sbfm|sbfiz|sbfx|asr|sxtw|sxth|sxtbDN12w", | |
| 77 "bfm|bfi|bfxilDN13w", | |
| 78 "ubfm|ubfiz|ubfx|lsr|lsl|uxth|uxtbDN12w" | |
| 79 } | |
| 80 }, | |
| 81 { | |
| 82 shift = 22, mask = 1, | |
| 83 { | |
| 84 shift = 29, mask = 3, | |
| 85 [0] = "sbfm|sbfiz|sbfx|asr|sxtw|sxth|sxtbDN12x", | |
| 86 "bfm|bfi|bfxilDN13x", | |
| 87 "ubfm|ubfiz|ubfx|lsr|lsl|uxth|uxtbDN12x" | |
| 88 } | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 local map_datai = { -- Data processing - immediate. | |
| 93 shift = 23, mask = 7, | |
| 94 [0] = map_adr, map_adr, map_addsubi, false, | |
| 95 map_logi, map_movwi, map_bitf, | |
| 96 { | |
| 97 shift = 15, mask = 0x1c0c1, | |
| 98 [0] = "extr|rorDNM4w", [0x10080] = "extr|rorDNM4x", | |
| 99 [0x10081] = "extr|rorDNM4x" | |
| 100 } | |
| 101 } | |
| 102 | |
| 103 local map_logsr = { -- Logical, shifted register. | |
| 104 shift = 31, mask = 1, | |
| 105 [0] = { | |
| 106 shift = 15, mask = 1, | |
| 107 [0] = { | |
| 108 shift = 29, mask = 3, | |
| 109 [0] = { | |
| 110 shift = 21, mask = 7, | |
| 111 [0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg", | |
| 112 "andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg" | |
| 113 }, | |
| 114 { | |
| 115 shift = 21, mask = 7, | |
| 116 [0] ="orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg", | |
| 117 "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg" | |
| 118 }, | |
| 119 { | |
| 120 shift = 21, mask = 7, | |
| 121 [0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg", | |
| 122 "eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg" | |
| 123 }, | |
| 124 { | |
| 125 shift = 21, mask = 7, | |
| 126 [0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg", | |
| 127 "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg" | |
| 128 } | |
| 129 }, | |
| 130 false -- unallocated | |
| 131 }, | |
| 132 { | |
| 133 shift = 29, mask = 3, | |
| 134 [0] = { | |
| 135 shift = 21, mask = 7, | |
| 136 [0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg", | |
| 137 "andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg" | |
| 138 }, | |
| 139 { | |
| 140 shift = 21, mask = 7, | |
| 141 [0] = "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg", | |
| 142 "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg" | |
| 143 }, | |
| 144 { | |
| 145 shift = 21, mask = 7, | |
| 146 [0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg", | |
| 147 "eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg" | |
| 148 }, | |
| 149 { | |
| 150 shift = 21, mask = 7, | |
| 151 [0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg", | |
| 152 "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg" | |
| 153 } | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 local map_assh = { | |
| 158 shift = 31, mask = 1, | |
| 159 [0] = { | |
| 160 shift = 15, mask = 1, | |
| 161 [0] = { | |
| 162 shift = 29, mask = 3, | |
| 163 [0] = { | |
| 164 shift = 22, mask = 3, | |
| 165 [0] = "addDNMSg", "addDNMSg", "addDNMSg", "addDNMg" | |
| 166 }, | |
| 167 { | |
| 168 shift = 22, mask = 3, | |
| 169 [0] = "adds|cmnD0NMSg", "adds|cmnD0NMSg", | |
| 170 "adds|cmnD0NMSg", "adds|cmnD0NMg" | |
| 171 }, | |
| 172 { | |
| 173 shift = 22, mask = 3, | |
| 174 [0] = "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0Mg" | |
| 175 }, | |
| 176 { | |
| 177 shift = 22, mask = 3, | |
| 178 [0] = "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg", | |
| 179 "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0Mzg" | |
| 180 }, | |
| 181 }, | |
| 182 false -- unallocated | |
| 183 }, | |
| 184 { | |
| 185 shift = 29, mask = 3, | |
| 186 [0] = { | |
| 187 shift = 22, mask = 3, | |
| 188 [0] = "addDNMSg", "addDNMSg", "addDNMSg", "addDNMg" | |
| 189 }, | |
| 190 { | |
| 191 shift = 22, mask = 3, | |
| 192 [0] = "adds|cmnD0NMSg", "adds|cmnD0NMSg", "adds|cmnD0NMSg", | |
| 193 "adds|cmnD0NMg" | |
| 194 }, | |
| 195 { | |
| 196 shift = 22, mask = 3, | |
| 197 [0] = "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0Mg" | |
| 198 }, | |
| 199 { | |
| 200 shift = 22, mask = 3, | |
| 201 [0] = "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg", | |
| 202 "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0Mzg" | |
| 203 } | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 local map_addsubsh = { -- Add/subtract, shifted register. | |
| 208 shift = 22, mask = 3, | |
| 209 [0] = map_assh, map_assh, map_assh | |
| 210 } | |
| 211 | |
| 212 local map_addsubex = { -- Add/subtract, extended register. | |
| 213 shift = 22, mask = 3, | |
| 214 [0] = { | |
| 215 shift = 29, mask = 3, | |
| 216 [0] = "addDNMXg", "adds|cmnD0NMXg", "subDNMXg", "subs|cmpD0NMzXg", | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 local map_addsubc = { -- Add/subtract, with carry. | |
| 221 shift = 10, mask = 63, | |
| 222 [0] = { | |
| 223 shift = 29, mask = 3, | |
| 224 [0] = "adcDNMg", "adcsDNMg", "sbc|ngcDN0Mg", "sbcs|ngcsDN0Mg", | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 local map_ccomp = { | |
| 229 shift = 4, mask = 1, | |
| 230 [0] = { | |
| 231 shift = 10, mask = 3, | |
| 232 [0] = { -- Conditional compare register. | |
| 233 shift = 29, mask = 3, | |
| 234 "ccmnNMVCg", false, "ccmpNMVCg", | |
| 235 }, | |
| 236 [2] = { -- Conditional compare immediate. | |
| 237 shift = 29, mask = 3, | |
| 238 "ccmnN5VCg", false, "ccmpN5VCg", | |
| 239 } | |
| 240 } | |
| 241 } | |
| 242 | |
| 243 local map_csel = { -- Conditional select. | |
| 244 shift = 11, mask = 1, | |
| 245 [0] = { | |
| 246 shift = 10, mask = 1, | |
| 247 [0] = { | |
| 248 shift = 29, mask = 3, | |
| 249 [0] = "cselDNMzCg", false, "csinv|cinv|csetmDNMcg", false, | |
| 250 }, | |
| 251 { | |
| 252 shift = 29, mask = 3, | |
| 253 [0] = "csinc|cinc|csetDNMcg", false, "csneg|cnegDNMcg", false, | |
| 254 } | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 local map_data1s = { -- Data processing, 1 source. | |
| 259 shift = 29, mask = 1, | |
| 260 [0] = { | |
| 261 shift = 31, mask = 1, | |
| 262 [0] = { | |
| 263 shift = 10, mask = 0x7ff, | |
| 264 [0] = "rbitDNg", "rev16DNg", "revDNw", false, "clzDNg", "clsDNg" | |
| 265 }, | |
| 266 { | |
| 267 shift = 10, mask = 0x7ff, | |
| 268 [0] = "rbitDNg", "rev16DNg", "rev32DNx", "revDNx", "clzDNg", "clsDNg" | |
| 269 } | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 local map_data2s = { -- Data processing, 2 sources. | |
| 274 shift = 29, mask = 1, | |
| 275 [0] = { | |
| 276 shift = 10, mask = 63, | |
| 277 false, "udivDNMg", "sdivDNMg", false, false, false, false, "lslDNMg", | |
| 278 "lsrDNMg", "asrDNMg", "rorDNMg" | |
| 279 } | |
| 280 } | |
| 281 | |
| 282 local map_data3s = { -- Data processing, 3 sources. | |
| 283 shift = 29, mask = 7, | |
| 284 [0] = { | |
| 285 shift = 21, mask = 7, | |
| 286 [0] = { | |
| 287 shift = 15, mask = 1, | |
| 288 [0] = "madd|mulDNMA0g", "msub|mnegDNMA0g" | |
| 289 } | |
| 290 }, false, false, false, | |
| 291 { | |
| 292 shift = 15, mask = 1, | |
| 293 [0] = { | |
| 294 shift = 21, mask = 7, | |
| 295 [0] = "madd|mulDNMA0g", "smaddl|smullDxNMwA0x", "smulhDNMx", false, | |
| 296 false, "umaddl|umullDxNMwA0x", "umulhDNMx" | |
| 297 }, | |
| 298 { | |
| 299 shift = 21, mask = 7, | |
| 300 [0] = "msub|mnegDNMA0g", "smsubl|smneglDxNMwA0x", false, false, | |
| 301 false, "umsubl|umneglDxNMwA0x" | |
| 302 } | |
| 303 } | |
| 304 } | |
| 305 | |
| 306 local map_datar = { -- Data processing, register. | |
| 307 shift = 28, mask = 1, | |
| 308 [0] = { | |
| 309 shift = 24, mask = 1, | |
| 310 [0] = map_logsr, | |
| 311 { | |
| 312 shift = 21, mask = 1, | |
| 313 [0] = map_addsubsh, map_addsubex | |
| 314 } | |
| 315 }, | |
| 316 { | |
| 317 shift = 21, mask = 15, | |
| 318 [0] = map_addsubc, false, map_ccomp, false, map_csel, false, | |
| 319 { | |
| 320 shift = 30, mask = 1, | |
| 321 [0] = map_data2s, map_data1s | |
| 322 }, | |
| 323 false, map_data3s, map_data3s, map_data3s, map_data3s, map_data3s, | |
| 324 map_data3s, map_data3s, map_data3s | |
| 325 } | |
| 326 } | |
| 327 | |
| 328 local map_lrl = { -- Load register, literal. | |
| 329 shift = 26, mask = 1, | |
| 330 [0] = { | |
| 331 shift = 30, mask = 3, | |
| 332 [0] = "ldrDwB", "ldrDxB", "ldrswDxB" | |
| 333 }, | |
| 334 { | |
| 335 shift = 30, mask = 3, | |
| 336 [0] = "ldrDsB", "ldrDdB" | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 local map_lsriind = { -- Load/store register, immediate pre/post-indexed. | |
| 341 shift = 30, mask = 3, | |
| 342 [0] = { | |
| 343 shift = 26, mask = 1, | |
| 344 [0] = { | |
| 345 shift = 22, mask = 3, | |
| 346 [0] = "strbDwzL", "ldrbDwzL", "ldrsbDxzL", "ldrsbDwzL" | |
| 347 } | |
| 348 }, | |
| 349 { | |
| 350 shift = 26, mask = 1, | |
| 351 [0] = { | |
| 352 shift = 22, mask = 3, | |
| 353 [0] = "strhDwzL", "ldrhDwzL", "ldrshDxzL", "ldrshDwzL" | |
| 354 } | |
| 355 }, | |
| 356 { | |
| 357 shift = 26, mask = 1, | |
| 358 [0] = { | |
| 359 shift = 22, mask = 3, | |
| 360 [0] = "strDwzL", "ldrDwzL", "ldrswDxzL" | |
| 361 }, | |
| 362 { | |
| 363 shift = 22, mask = 3, | |
| 364 [0] = "strDszL", "ldrDszL" | |
| 365 } | |
| 366 }, | |
| 367 { | |
| 368 shift = 26, mask = 1, | |
| 369 [0] = { | |
| 370 shift = 22, mask = 3, | |
| 371 [0] = "strDxzL", "ldrDxzL" | |
| 372 }, | |
| 373 { | |
| 374 shift = 22, mask = 3, | |
| 375 [0] = "strDdzL", "ldrDdzL" | |
| 376 } | |
| 377 } | |
| 378 } | |
| 379 | |
| 380 local map_lsriro = { | |
| 381 shift = 21, mask = 1, | |
| 382 [0] = { -- Load/store register immediate. | |
| 383 shift = 10, mask = 3, | |
| 384 [0] = { -- Unscaled immediate. | |
| 385 shift = 26, mask = 1, | |
| 386 [0] = { | |
| 387 shift = 30, mask = 3, | |
| 388 [0] = { | |
| 389 shift = 22, mask = 3, | |
| 390 [0] = "sturbDwK", "ldurbDwK" | |
| 391 }, | |
| 392 { | |
| 393 shift = 22, mask = 3, | |
| 394 [0] = "sturhDwK", "ldurhDwK" | |
| 395 }, | |
| 396 { | |
| 397 shift = 22, mask = 3, | |
| 398 [0] = "sturDwK", "ldurDwK" | |
| 399 }, | |
| 400 { | |
| 401 shift = 22, mask = 3, | |
| 402 [0] = "sturDxK", "ldurDxK" | |
| 403 } | |
| 404 } | |
| 405 }, map_lsriind, false, map_lsriind | |
| 406 }, | |
| 407 { -- Load/store register, register offset. | |
| 408 shift = 10, mask = 3, | |
| 409 [2] = { | |
| 410 shift = 26, mask = 1, | |
| 411 [0] = { | |
| 412 shift = 30, mask = 3, | |
| 413 [0] = { | |
| 414 shift = 22, mask = 3, | |
| 415 [0] = "strbDwO", "ldrbDwO", "ldrsbDxO", "ldrsbDwO" | |
| 416 }, | |
| 417 { | |
| 418 shift = 22, mask = 3, | |
| 419 [0] = "strhDwO", "ldrhDwO", "ldrshDxO", "ldrshDwO" | |
| 420 }, | |
| 421 { | |
| 422 shift = 22, mask = 3, | |
| 423 [0] = "strDwO", "ldrDwO", "ldrswDxO" | |
| 424 }, | |
| 425 { | |
| 426 shift = 22, mask = 3, | |
| 427 [0] = "strDxO", "ldrDxO" | |
| 428 } | |
| 429 }, | |
| 430 { | |
| 431 shift = 30, mask = 3, | |
| 432 [2] = { | |
| 433 shift = 22, mask = 3, | |
| 434 [0] = "strDsO", "ldrDsO" | |
| 435 }, | |
| 436 [3] = { | |
| 437 shift = 22, mask = 3, | |
| 438 [0] = "strDdO", "ldrDdO" | |
| 439 } | |
| 440 } | |
| 441 } | |
| 442 } | |
| 443 } | |
| 444 | |
| 445 local map_lsp = { -- Load/store register pair, offset. | |
| 446 shift = 22, mask = 1, | |
| 447 [0] = { | |
| 448 shift = 30, mask = 3, | |
| 449 [0] = { | |
| 450 shift = 26, mask = 1, | |
| 451 [0] = "stpDzAzwP", "stpDzAzsP", | |
| 452 }, | |
| 453 { | |
| 454 shift = 26, mask = 1, | |
| 455 "stpDzAzdP" | |
| 456 }, | |
| 457 { | |
| 458 shift = 26, mask = 1, | |
| 459 [0] = "stpDzAzxP" | |
| 460 } | |
| 461 }, | |
| 462 { | |
| 463 shift = 30, mask = 3, | |
| 464 [0] = { | |
| 465 shift = 26, mask = 1, | |
| 466 [0] = "ldpDzAzwP", "ldpDzAzsP", | |
| 467 }, | |
| 468 { | |
| 469 shift = 26, mask = 1, | |
| 470 [0] = "ldpswDAxP", "ldpDzAzdP" | |
| 471 }, | |
| 472 { | |
| 473 shift = 26, mask = 1, | |
| 474 [0] = "ldpDzAzxP" | |
| 475 } | |
| 476 } | |
| 477 } | |
| 478 | |
| 479 local map_ls = { -- Loads and stores. | |
| 480 shift = 24, mask = 0x31, | |
| 481 [0x10] = map_lrl, [0x30] = map_lsriro, | |
| 482 [0x20] = { | |
| 483 shift = 23, mask = 3, | |
| 484 map_lsp, map_lsp, map_lsp | |
| 485 }, | |
| 486 [0x21] = { | |
| 487 shift = 23, mask = 3, | |
| 488 map_lsp, map_lsp, map_lsp | |
| 489 }, | |
| 490 [0x31] = { | |
| 491 shift = 26, mask = 1, | |
| 492 [0] = { | |
| 493 shift = 30, mask = 3, | |
| 494 [0] = { | |
| 495 shift = 22, mask = 3, | |
| 496 [0] = "strbDwzU", "ldrbDwzU" | |
| 497 }, | |
| 498 { | |
| 499 shift = 22, mask = 3, | |
| 500 [0] = "strhDwzU", "ldrhDwzU" | |
| 501 }, | |
| 502 { | |
| 503 shift = 22, mask = 3, | |
| 504 [0] = "strDwzU", "ldrDwzU" | |
| 505 }, | |
| 506 { | |
| 507 shift = 22, mask = 3, | |
| 508 [0] = "strDxzU", "ldrDxzU" | |
| 509 } | |
| 510 }, | |
| 511 { | |
| 512 shift = 30, mask = 3, | |
| 513 [2] = { | |
| 514 shift = 22, mask = 3, | |
| 515 [0] = "strDszU", "ldrDszU" | |
| 516 }, | |
| 517 [3] = { | |
| 518 shift = 22, mask = 3, | |
| 519 [0] = "strDdzU", "ldrDdzU" | |
| 520 } | |
| 521 } | |
| 522 }, | |
| 523 } | |
| 524 | |
| 525 local map_datafp = { -- Data processing, SIMD and FP. | |
| 526 shift = 28, mask = 7, | |
| 527 { -- 001 | |
| 528 shift = 24, mask = 1, | |
| 529 [0] = { | |
| 530 shift = 21, mask = 1, | |
| 531 { | |
| 532 shift = 10, mask = 3, | |
| 533 [0] = { | |
| 534 shift = 12, mask = 1, | |
| 535 [0] = { | |
| 536 shift = 13, mask = 1, | |
| 537 [0] = { | |
| 538 shift = 14, mask = 1, | |
| 539 [0] = { | |
| 540 shift = 15, mask = 1, | |
| 541 [0] = { -- FP/int conversion. | |
| 542 shift = 31, mask = 1, | |
| 543 [0] = { | |
| 544 shift = 16, mask = 0xff, | |
| 545 [0x20] = "fcvtnsDwNs", [0x21] = "fcvtnuDwNs", | |
| 546 [0x22] = "scvtfDsNw", [0x23] = "ucvtfDsNw", | |
| 547 [0x24] = "fcvtasDwNs", [0x25] = "fcvtauDwNs", | |
| 548 [0x26] = "fmovDwNs", [0x27] = "fmovDsNw", | |
| 549 [0x28] = "fcvtpsDwNs", [0x29] = "fcvtpuDwNs", | |
| 550 [0x30] = "fcvtmsDwNs", [0x31] = "fcvtmuDwNs", | |
| 551 [0x38] = "fcvtzsDwNs", [0x39] = "fcvtzuDwNs", | |
| 552 [0x60] = "fcvtnsDwNd", [0x61] = "fcvtnuDwNd", | |
| 553 [0x62] = "scvtfDdNw", [0x63] = "ucvtfDdNw", | |
| 554 [0x64] = "fcvtasDwNd", [0x65] = "fcvtauDwNd", | |
| 555 [0x68] = "fcvtpsDwNd", [0x69] = "fcvtpuDwNd", | |
| 556 [0x70] = "fcvtmsDwNd", [0x71] = "fcvtmuDwNd", | |
| 557 [0x78] = "fcvtzsDwNd", [0x79] = "fcvtzuDwNd" | |
| 558 }, | |
| 559 { | |
| 560 shift = 16, mask = 0xff, | |
| 561 [0x20] = "fcvtnsDxNs", [0x21] = "fcvtnuDxNs", | |
| 562 [0x22] = "scvtfDsNx", [0x23] = "ucvtfDsNx", | |
| 563 [0x24] = "fcvtasDxNs", [0x25] = "fcvtauDxNs", | |
| 564 [0x28] = "fcvtpsDxNs", [0x29] = "fcvtpuDxNs", | |
| 565 [0x30] = "fcvtmsDxNs", [0x31] = "fcvtmuDxNs", | |
| 566 [0x38] = "fcvtzsDxNs", [0x39] = "fcvtzuDxNs", | |
| 567 [0x60] = "fcvtnsDxNd", [0x61] = "fcvtnuDxNd", | |
| 568 [0x62] = "scvtfDdNx", [0x63] = "ucvtfDdNx", | |
| 569 [0x64] = "fcvtasDxNd", [0x65] = "fcvtauDxNd", | |
| 570 [0x66] = "fmovDxNd", [0x67] = "fmovDdNx", | |
| 571 [0x68] = "fcvtpsDxNd", [0x69] = "fcvtpuDxNd", | |
| 572 [0x70] = "fcvtmsDxNd", [0x71] = "fcvtmuDxNd", | |
| 573 [0x78] = "fcvtzsDxNd", [0x79] = "fcvtzuDxNd" | |
| 574 } | |
| 575 } | |
| 576 }, | |
| 577 { -- FP data-processing, 1 source. | |
| 578 shift = 31, mask = 1, | |
| 579 [0] = { | |
| 580 shift = 22, mask = 3, | |
| 581 [0] = { | |
| 582 shift = 15, mask = 63, | |
| 583 [0] = "fmovDNf", "fabsDNf", "fnegDNf", | |
| 584 "fsqrtDNf", false, "fcvtDdNs", false, false, | |
| 585 "frintnDNf", "frintpDNf", "frintmDNf", "frintzDNf", | |
| 586 "frintaDNf", false, "frintxDNf", "frintiDNf", | |
| 587 }, | |
| 588 { | |
| 589 shift = 15, mask = 63, | |
| 590 [0] = "fmovDNf", "fabsDNf", "fnegDNf", | |
| 591 "fsqrtDNf", "fcvtDsNd", false, false, false, | |
| 592 "frintnDNf", "frintpDNf", "frintmDNf", "frintzDNf", | |
| 593 "frintaDNf", false, "frintxDNf", "frintiDNf", | |
| 594 } | |
| 595 } | |
| 596 } | |
| 597 }, | |
| 598 { -- FP compare. | |
| 599 shift = 31, mask = 1, | |
| 600 [0] = { | |
| 601 shift = 14, mask = 3, | |
| 602 [0] = { | |
| 603 shift = 23, mask = 1, | |
| 604 [0] = { | |
| 605 shift = 0, mask = 31, | |
| 606 [0] = "fcmpNMf", [8] = "fcmpNZf", | |
| 607 [16] = "fcmpeNMf", [24] = "fcmpeNZf", | |
| 608 } | |
| 609 } | |
| 610 } | |
| 611 } | |
| 612 }, | |
| 613 { -- FP immediate. | |
| 614 shift = 31, mask = 1, | |
| 615 [0] = { | |
| 616 shift = 5, mask = 31, | |
| 617 [0] = { | |
| 618 shift = 23, mask = 1, | |
| 619 [0] = "fmovDFf" | |
| 620 } | |
| 621 } | |
| 622 } | |
| 623 }, | |
| 624 { -- FP conditional compare. | |
| 625 shift = 31, mask = 1, | |
| 626 [0] = { | |
| 627 shift = 23, mask = 1, | |
| 628 [0] = { | |
| 629 shift = 4, mask = 1, | |
| 630 [0] = "fccmpNMVCf", "fccmpeNMVCf" | |
| 631 } | |
| 632 } | |
| 633 }, | |
| 634 { -- FP data-processing, 2 sources. | |
| 635 shift = 31, mask = 1, | |
| 636 [0] = { | |
| 637 shift = 23, mask = 1, | |
| 638 [0] = { | |
| 639 shift = 12, mask = 15, | |
| 640 [0] = "fmulDNMf", "fdivDNMf", "faddDNMf", "fsubDNMf", | |
| 641 "fmaxDNMf", "fminDNMf", "fmaxnmDNMf", "fminnmDNMf", | |
| 642 "fnmulDNMf" | |
| 643 } | |
| 644 } | |
| 645 }, | |
| 646 { -- FP conditional select. | |
| 647 shift = 31, mask = 1, | |
| 648 [0] = { | |
| 649 shift = 23, mask = 1, | |
| 650 [0] = "fcselDNMCf" | |
| 651 } | |
| 652 } | |
| 653 } | |
| 654 }, | |
| 655 { -- FP data-processing, 3 sources. | |
| 656 shift = 31, mask = 1, | |
| 657 [0] = { | |
| 658 shift = 15, mask = 1, | |
| 659 [0] = { | |
| 660 shift = 21, mask = 5, | |
| 661 [0] = "fmaddDNMAf", "fnmaddDNMAf" | |
| 662 }, | |
| 663 { | |
| 664 shift = 21, mask = 5, | |
| 665 [0] = "fmsubDNMAf", "fnmsubDNMAf" | |
| 666 } | |
| 667 } | |
| 668 } | |
| 669 } | |
| 670 } | |
| 671 | |
| 672 local map_br = { -- Branches, exception generating and system instructions. | |
| 673 shift = 29, mask = 7, | |
| 674 [0] = "bB", | |
| 675 { -- Compare & branch, immediate. | |
| 676 shift = 24, mask = 3, | |
| 677 [0] = "cbzDBg", "cbnzDBg", "tbzDTBw", "tbnzDTBw" | |
| 678 }, | |
| 679 { -- Conditional branch, immediate. | |
| 680 shift = 24, mask = 3, | |
| 681 [0] = { | |
| 682 shift = 4, mask = 1, | |
| 683 [0] = { | |
| 684 shift = 0, mask = 15, | |
| 685 [0] = "beqB", "bneB", "bhsB", "bloB", "bmiB", "bplB", "bvsB", "bvcB", | |
| 686 "bhiB", "blsB", "bgeB", "bltB", "bgtB", "bleB", "balB" | |
| 687 } | |
| 688 } | |
| 689 }, false, "blB", | |
| 690 { -- Compare & branch, immediate. | |
| 691 shift = 24, mask = 3, | |
| 692 [0] = "cbzDBg", "cbnzDBg", "tbzDTBx", "tbnzDTBx" | |
| 693 }, | |
| 694 { | |
| 695 shift = 24, mask = 3, | |
| 696 [0] = { -- Exception generation. | |
| 697 shift = 0, mask = 0xe0001f, | |
| 698 [0x200000] = "brkW" | |
| 699 }, | |
| 700 { -- System instructions. | |
| 701 shift = 0, mask = 0x3fffff, | |
| 702 [0x03201f] = "nop" | |
| 703 }, | |
| 704 { -- Unconditional branch, register. | |
| 705 shift = 0, mask = 0xfffc1f, | |
| 706 [0x1f0000] = "brNx", [0x3f0000] = "blrNx", | |
| 707 [0x5f0000] = "retNx" | |
| 708 }, | |
| 709 } | |
| 710 } | |
| 711 | |
| 712 local map_init = { | |
| 713 shift = 25, mask = 15, | |
| 714 [0] = false, false, false, false, map_ls, map_datar, map_ls, map_datafp, | |
| 715 map_datai, map_datai, map_br, map_br, map_ls, map_datar, map_ls, map_datafp | |
| 716 } | |
| 717 | |
| 718 ------------------------------------------------------------------------------ | |
| 719 | |
| 720 local map_regs = { x = {}, w = {}, d = {}, s = {} } | |
| 721 | |
| 722 for i=0,30 do | |
| 723 map_regs.x[i] = "x"..i | |
| 724 map_regs.w[i] = "w"..i | |
| 725 map_regs.d[i] = "d"..i | |
| 726 map_regs.s[i] = "s"..i | |
| 727 end | |
| 728 map_regs.x[31] = "sp" | |
| 729 map_regs.w[31] = "wsp" | |
| 730 map_regs.d[31] = "d31" | |
| 731 map_regs.s[31] = "s31" | |
| 732 | |
| 733 local map_cond = { | |
| 734 [0] = "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", | |
| 735 "hi", "ls", "ge", "lt", "gt", "le", "al", | |
| 736 } | |
| 737 | |
| 738 local map_shift = { [0] = "lsl", "lsr", "asr", } | |
| 739 | |
| 740 local map_extend = { | |
| 741 [0] = "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx", | |
| 742 } | |
| 743 | |
| 744 ------------------------------------------------------------------------------ | |
| 745 | |
| 746 -- Output a nicely formatted line with an opcode and operands. | |
| 747 local function putop(ctx, text, operands) | |
| 748 local pos = ctx.pos | |
| 749 local extra = "" | |
| 750 if ctx.rel then | |
| 751 local sym = ctx.symtab[ctx.rel] | |
| 752 if sym then | |
| 753 extra = "\t->"..sym | |
| 754 end | |
| 755 end | |
| 756 if ctx.hexdump > 0 then | |
| 757 ctx.out(format("%08x %s %-5s %s%s\n", | |
| 758 ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) | |
| 759 else | |
| 760 ctx.out(format("%08x %-5s %s%s\n", | |
| 761 ctx.addr+pos, text, concat(operands, ", "), extra)) | |
| 762 end | |
| 763 ctx.pos = pos + 4 | |
| 764 end | |
| 765 | |
| 766 -- Fallback for unknown opcodes. | |
| 767 local function unknown(ctx) | |
| 768 return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) | |
| 769 end | |
| 770 | |
| 771 local function match_reg(p, pat, regnum) | |
| 772 return map_regs[match(pat, p.."%w-([xwds])")][regnum] | |
| 773 end | |
| 774 | |
| 775 local function fmt_hex32(x) | |
| 776 if x < 0 then | |
| 777 return tohex(x) | |
| 778 else | |
| 779 return format("%x", x) | |
| 780 end | |
| 781 end | |
| 782 | |
| 783 local imm13_rep = { 0x55555555, 0x11111111, 0x01010101, 0x00010001, 0x00000001 } | |
| 784 | |
| 785 local function decode_imm13(op) | |
| 786 local imms = band(rshift(op, 10), 63) | |
| 787 local immr = band(rshift(op, 16), 63) | |
| 788 if band(op, 0x00400000) == 0 then | |
| 789 local len = 5 | |
| 790 if imms >= 56 then | |
| 791 if imms >= 60 then len = 1 else len = 2 end | |
| 792 elseif imms >= 48 then len = 3 elseif imms >= 32 then len = 4 end | |
| 793 local l = lshift(1, len)-1 | |
| 794 local s = band(imms, l) | |
| 795 local r = band(immr, l) | |
| 796 local imm = ror(rshift(-1, 31-s), r) | |
| 797 if len ~= 5 then imm = band(imm, lshift(1, l)-1) + rshift(imm, 31-l) end | |
| 798 imm = imm * imm13_rep[len] | |
| 799 local ix = fmt_hex32(imm) | |
| 800 if rshift(op, 31) ~= 0 then | |
| 801 return ix..tohex(imm) | |
| 802 else | |
| 803 return ix | |
| 804 end | |
| 805 else | |
| 806 local lo, hi = -1, 0 | |
| 807 if imms < 32 then lo = rshift(-1, 31-imms) else hi = rshift(-1, 63-imms) end | |
| 808 if immr ~= 0 then | |
| 809 lo, hi = ror(lo, immr), ror(hi, immr) | |
| 810 local x = immr == 32 and 0 or band(bxor(lo, hi), lshift(-1, 32-immr)) | |
| 811 lo, hi = bxor(lo, x), bxor(hi, x) | |
| 812 if immr >= 32 then lo, hi = hi, lo end | |
| 813 end | |
| 814 if hi ~= 0 then | |
| 815 return fmt_hex32(hi)..tohex(lo) | |
| 816 else | |
| 817 return fmt_hex32(lo) | |
| 818 end | |
| 819 end | |
| 820 end | |
| 821 | |
| 822 local function parse_immpc(op, name) | |
| 823 if name == "b" or name == "bl" then | |
| 824 return arshift(lshift(op, 6), 4) | |
| 825 elseif name == "adr" or name == "adrp" then | |
| 826 local immlo = band(rshift(op, 29), 3) | |
| 827 local immhi = lshift(arshift(lshift(op, 8), 13), 2) | |
| 828 return bor(immhi, immlo) | |
| 829 elseif name == "tbz" or name == "tbnz" then | |
| 830 return lshift(arshift(lshift(op, 13), 18), 2) | |
| 831 else | |
| 832 return lshift(arshift(lshift(op, 8), 13), 2) | |
| 833 end | |
| 834 end | |
| 835 | |
| 836 local function parse_fpimm8(op) | |
| 837 local sign = band(op, 0x100000) == 0 and 1 or -1 | |
| 838 local exp = bxor(rshift(arshift(lshift(op, 12), 5), 24), 0x80) - 131 | |
| 839 local frac = 16+band(rshift(op, 13), 15) | |
| 840 return sign * frac * 2^exp | |
| 841 end | |
| 842 | |
| 843 local function prefer_bfx(sf, uns, imms, immr) | |
| 844 if imms < immr or imms == 31 or imms == 63 then | |
| 845 return false | |
| 846 end | |
| 847 if immr == 0 then | |
| 848 if sf == 0 and (imms == 7 or imms == 15) then | |
| 849 return false | |
| 850 end | |
| 851 if sf ~= 0 and uns == 0 and (imms == 7 or imms == 15 or imms == 31) then | |
| 852 return false | |
| 853 end | |
| 854 end | |
| 855 return true | |
| 856 end | |
| 857 | |
| 858 -- Disassemble a single instruction. | |
| 859 local function disass_ins(ctx) | |
| 860 local pos = ctx.pos | |
| 861 local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) | |
| 862 local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0) | |
| 863 local operands = {} | |
| 864 local suffix = "" | |
| 865 local last, name, pat | |
| 866 local map_reg | |
| 867 ctx.op = op | |
| 868 ctx.rel = nil | |
| 869 last = nil | |
| 870 local opat | |
| 871 opat = map_init[band(rshift(op, 25), 15)] | |
| 872 while type(opat) ~= "string" do | |
| 873 if not opat then return unknown(ctx) end | |
| 874 opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._ | |
| 875 end | |
| 876 name, pat = match(opat, "^([a-z0-9]*)(.*)") | |
| 877 local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)") | |
| 878 if altname then pat = pat2 end | |
| 879 if sub(pat, 1, 1) == "." then | |
| 880 local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)") | |
| 881 suffix = suffix..s2 | |
| 882 pat = p2 | |
| 883 end | |
| 884 | |
| 885 local rt = match(pat, "[gf]") | |
| 886 if rt then | |
| 887 if rt == "g" then | |
| 888 map_reg = band(op, 0x80000000) ~= 0 and map_regs.x or map_regs.w | |
| 889 else | |
| 890 map_reg = band(op, 0x400000) ~= 0 and map_regs.d or map_regs.s | |
| 891 end | |
| 892 end | |
| 893 | |
| 894 local second0, immr | |
| 895 | |
| 896 for p in gmatch(pat, ".") do | |
| 897 local x = nil | |
| 898 if p == "D" then | |
| 899 local regnum = band(op, 31) | |
| 900 x = rt and map_reg[regnum] or match_reg(p, pat, regnum) | |
| 901 elseif p == "N" then | |
| 902 local regnum = band(rshift(op, 5), 31) | |
| 903 x = rt and map_reg[regnum] or match_reg(p, pat, regnum) | |
| 904 elseif p == "M" then | |
| 905 local regnum = band(rshift(op, 16), 31) | |
| 906 x = rt and map_reg[regnum] or match_reg(p, pat, regnum) | |
| 907 elseif p == "A" then | |
| 908 local regnum = band(rshift(op, 10), 31) | |
| 909 x = rt and map_reg[regnum] or match_reg(p, pat, regnum) | |
| 910 elseif p == "B" then | |
| 911 local addr = ctx.addr + pos + parse_immpc(op, name) | |
| 912 ctx.rel = addr | |
| 913 x = "0x"..tohex(addr) | |
| 914 elseif p == "T" then | |
| 915 x = bor(band(rshift(op, 26), 32), band(rshift(op, 19), 31)) | |
| 916 elseif p == "V" then | |
| 917 x = band(op, 15) | |
| 918 elseif p == "C" then | |
| 919 x = map_cond[band(rshift(op, 12), 15)] | |
| 920 elseif p == "c" then | |
| 921 local rn = band(rshift(op, 5), 31) | |
| 922 local rm = band(rshift(op, 16), 31) | |
| 923 local cond = band(rshift(op, 12), 15) | |
| 924 local invc = bxor(cond, 1) | |
| 925 x = map_cond[cond] | |
| 926 if altname and cond ~= 14 and cond ~= 15 then | |
| 927 local a1, a2 = match(altname, "([^|]*)|(.*)") | |
| 928 if rn == rm then | |
| 929 local n = #operands | |
| 930 operands[n] = nil | |
| 931 x = map_cond[invc] | |
| 932 if rn ~= 31 then | |
| 933 if a1 then name = a1 else name = altname end | |
| 934 else | |
| 935 operands[n-1] = nil | |
| 936 name = a2 | |
| 937 end | |
| 938 end | |
| 939 end | |
| 940 elseif p == "W" then | |
| 941 x = band(rshift(op, 5), 0xffff) | |
| 942 elseif p == "Y" then | |
| 943 x = band(rshift(op, 5), 0xffff) | |
| 944 local hw = band(rshift(op, 21), 3) | |
| 945 if altname and (hw == 0 or x ~= 0) then | |
| 946 name = altname | |
| 947 end | |
| 948 elseif p == "L" then | |
| 949 local rn = map_regs.x[band(rshift(op, 5), 31)] | |
| 950 local imm9 = arshift(lshift(op, 11), 23) | |
| 951 if band(op, 0x800) ~= 0 then | |
| 952 x = "["..rn..", #"..imm9.."]!" | |
| 953 else | |
| 954 x = "["..rn.."], #"..imm9 | |
| 955 end | |
| 956 elseif p == "U" then | |
| 957 local rn = map_regs.x[band(rshift(op, 5), 31)] | |
| 958 local sz = band(rshift(op, 30), 3) | |
| 959 local imm12 = lshift(arshift(lshift(op, 10), 20), sz) | |
| 960 if imm12 ~= 0 then | |
| 961 x = "["..rn..", #"..imm12.."]" | |
| 962 else | |
| 963 x = "["..rn.."]" | |
| 964 end | |
| 965 elseif p == "K" then | |
| 966 local rn = map_regs.x[band(rshift(op, 5), 31)] | |
| 967 local imm9 = arshift(lshift(op, 11), 23) | |
| 968 if imm9 ~= 0 then | |
| 969 x = "["..rn..", #"..imm9.."]" | |
| 970 else | |
| 971 x = "["..rn.."]" | |
| 972 end | |
| 973 elseif p == "O" then | |
| 974 local rn, rm = map_regs.x[band(rshift(op, 5), 31)] | |
| 975 local m = band(rshift(op, 13), 1) | |
| 976 if m == 0 then | |
| 977 rm = map_regs.w[band(rshift(op, 16), 31)] | |
| 978 else | |
| 979 rm = map_regs.x[band(rshift(op, 16), 31)] | |
| 980 end | |
| 981 x = "["..rn..", "..rm | |
| 982 local opt = band(rshift(op, 13), 7) | |
| 983 local s = band(rshift(op, 12), 1) | |
| 984 local sz = band(rshift(op, 30), 3) | |
| 985 -- extension to be applied | |
| 986 if opt == 3 then | |
| 987 if s == 0 then x = x.."]" | |
| 988 else x = x..", lsl #"..sz.."]" end | |
| 989 elseif opt == 2 or opt == 6 or opt == 7 then | |
| 990 if s == 0 then x = x..", "..map_extend[opt].."]" | |
| 991 else x = x..", "..map_extend[opt].." #"..sz.."]" end | |
| 992 else | |
| 993 x = x.."]" | |
| 994 end | |
| 995 elseif p == "P" then | |
| 996 local opcv, sh = rshift(op, 26), 2 | |
| 997 if opcv >= 0x2a then sh = 4 elseif opcv >= 0x1b then sh = 3 end | |
| 998 local imm7 = lshift(arshift(lshift(op, 10), 25), sh) | |
| 999 local rn = map_regs.x[band(rshift(op, 5), 31)] | |
| 1000 local ind = band(rshift(op, 23), 3) | |
| 1001 if ind == 1 then | |
| 1002 x = "["..rn.."], #"..imm7 | |
| 1003 elseif ind == 2 then | |
| 1004 if imm7 == 0 then | |
| 1005 x = "["..rn.."]" | |
| 1006 else | |
| 1007 x = "["..rn..", #"..imm7.."]" | |
| 1008 end | |
| 1009 elseif ind == 3 then | |
| 1010 x = "["..rn..", #"..imm7.."]!" | |
| 1011 end | |
| 1012 elseif p == "I" then | |
| 1013 local shf = band(rshift(op, 22), 3) | |
| 1014 local imm12 = band(rshift(op, 10), 0x0fff) | |
| 1015 local rn, rd = band(rshift(op, 5), 31), band(op, 31) | |
| 1016 if altname == "mov" and shf == 0 and imm12 == 0 and (rn == 31 or rd == 31) then | |
| 1017 name = altname | |
| 1018 x = nil | |
| 1019 elseif shf == 0 then | |
| 1020 x = imm12 | |
| 1021 elseif shf == 1 then | |
| 1022 x = imm12..", lsl #12" | |
| 1023 end | |
| 1024 elseif p == "i" then | |
| 1025 x = "#0x"..decode_imm13(op) | |
| 1026 elseif p == "1" then | |
| 1027 immr = band(rshift(op, 16), 63) | |
| 1028 x = immr | |
| 1029 elseif p == "2" then | |
| 1030 x = band(rshift(op, 10), 63) | |
| 1031 if altname then | |
| 1032 local a1, a2, a3, a4, a5, a6 = | |
| 1033 match(altname, "([^|]*)|([^|]*)|([^|]*)|([^|]*)|([^|]*)|(.*)") | |
| 1034 local sf = band(rshift(op, 26), 32) | |
| 1035 local uns = band(rshift(op, 30), 1) | |
| 1036 if prefer_bfx(sf, uns, x, immr) then | |
| 1037 name = a2 | |
| 1038 x = x - immr + 1 | |
| 1039 elseif immr == 0 and x == 7 then | |
| 1040 local n = #operands | |
| 1041 operands[n] = nil | |
| 1042 if sf ~= 0 then | |
| 1043 operands[n-1] = gsub(operands[n-1], "x", "w") | |
| 1044 end | |
| 1045 last = operands[n-1] | |
| 1046 name = a6 | |
| 1047 x = nil | |
| 1048 elseif immr == 0 and x == 15 then | |
| 1049 local n = #operands | |
| 1050 operands[n] = nil | |
| 1051 if sf ~= 0 then | |
| 1052 operands[n-1] = gsub(operands[n-1], "x", "w") | |
| 1053 end | |
| 1054 last = operands[n-1] | |
| 1055 name = a5 | |
| 1056 x = nil | |
| 1057 elseif x == 31 or x == 63 then | |
| 1058 if x == 31 and immr == 0 and name == "sbfm" then | |
| 1059 name = a4 | |
| 1060 local n = #operands | |
| 1061 operands[n] = nil | |
| 1062 if sf ~= 0 then | |
| 1063 operands[n-1] = gsub(operands[n-1], "x", "w") | |
| 1064 end | |
| 1065 last = operands[n-1] | |
| 1066 else | |
| 1067 name = a3 | |
| 1068 end | |
| 1069 x = nil | |
| 1070 elseif band(x, 31) ~= 31 and immr == x+1 and name == "ubfm" then | |
| 1071 name = a4 | |
| 1072 last = "#"..(sf+32 - immr) | |
| 1073 operands[#operands] = last | |
| 1074 x = nil | |
| 1075 elseif x < immr then | |
| 1076 name = a1 | |
| 1077 last = "#"..(sf+32 - immr) | |
| 1078 operands[#operands] = last | |
| 1079 x = x + 1 | |
| 1080 end | |
| 1081 end | |
| 1082 elseif p == "3" then | |
| 1083 x = band(rshift(op, 10), 63) | |
| 1084 if altname then | |
| 1085 local a1, a2 = match(altname, "([^|]*)|(.*)") | |
| 1086 if x < immr then | |
| 1087 name = a1 | |
| 1088 local sf = band(rshift(op, 26), 32) | |
| 1089 last = "#"..(sf+32 - immr) | |
| 1090 operands[#operands] = last | |
| 1091 x = x + 1 | |
| 1092 else | |
| 1093 name = a2 | |
| 1094 x = x - immr + 1 | |
| 1095 end | |
| 1096 end | |
| 1097 elseif p == "4" then | |
| 1098 x = band(rshift(op, 10), 63) | |
| 1099 local rn = band(rshift(op, 5), 31) | |
| 1100 local rm = band(rshift(op, 16), 31) | |
| 1101 if altname and rn == rm then | |
| 1102 local n = #operands | |
| 1103 operands[n] = nil | |
| 1104 last = operands[n-1] | |
| 1105 name = altname | |
| 1106 end | |
| 1107 elseif p == "5" then | |
| 1108 x = band(rshift(op, 16), 31) | |
| 1109 elseif p == "S" then | |
| 1110 x = band(rshift(op, 10), 63) | |
| 1111 if x == 0 then x = nil | |
| 1112 else x = map_shift[band(rshift(op, 22), 3)].." #"..x end | |
| 1113 elseif p == "X" then | |
| 1114 local opt = band(rshift(op, 13), 7) | |
| 1115 -- Width specifier <R>. | |
| 1116 if opt ~= 3 and opt ~= 7 then | |
| 1117 last = map_regs.w[band(rshift(op, 16), 31)] | |
| 1118 operands[#operands] = last | |
| 1119 end | |
| 1120 x = band(rshift(op, 10), 7) | |
| 1121 -- Extension. | |
| 1122 if opt == 2 + band(rshift(op, 31), 1) and | |
| 1123 band(rshift(op, second0 and 5 or 0), 31) == 31 then | |
| 1124 if x == 0 then x = nil | |
| 1125 else x = "lsl #"..x end | |
| 1126 else | |
| 1127 if x == 0 then x = map_extend[band(rshift(op, 13), 7)] | |
| 1128 else x = map_extend[band(rshift(op, 13), 7)].." #"..x end | |
| 1129 end | |
| 1130 elseif p == "R" then | |
| 1131 x = band(rshift(op,21), 3) | |
| 1132 if x == 0 then x = nil | |
| 1133 else x = "lsl #"..x*16 end | |
| 1134 elseif p == "z" then | |
| 1135 local n = #operands | |
| 1136 if operands[n] == "sp" then operands[n] = "xzr" | |
| 1137 elseif operands[n] == "wsp" then operands[n] = "wzr" | |
| 1138 end | |
| 1139 elseif p == "Z" then | |
| 1140 x = 0 | |
| 1141 elseif p == "F" then | |
| 1142 x = parse_fpimm8(op) | |
| 1143 elseif p == "g" or p == "f" or p == "x" or p == "w" or | |
| 1144 p == "d" or p == "s" then | |
| 1145 -- These are handled in D/N/M/A. | |
| 1146 elseif p == "0" then | |
| 1147 if last == "sp" or last == "wsp" then | |
| 1148 local n = #operands | |
| 1149 operands[n] = nil | |
| 1150 last = operands[n-1] | |
| 1151 if altname then | |
| 1152 local a1, a2 = match(altname, "([^|]*)|(.*)") | |
| 1153 if not a1 then | |
| 1154 name = altname | |
| 1155 elseif second0 then | |
| 1156 name, altname = a2, a1 | |
| 1157 else | |
| 1158 name, altname = a1, a2 | |
| 1159 end | |
| 1160 end | |
| 1161 end | |
| 1162 second0 = true | |
| 1163 else | |
| 1164 assert(false) | |
| 1165 end | |
| 1166 if x then | |
| 1167 last = x | |
| 1168 if type(x) == "number" then x = "#"..x end | |
| 1169 operands[#operands+1] = x | |
| 1170 end | |
| 1171 end | |
| 1172 | |
| 1173 return putop(ctx, name..suffix, operands) | |
| 1174 end | |
| 1175 | |
| 1176 ------------------------------------------------------------------------------ | |
| 1177 | |
| 1178 -- Disassemble a block of code. | |
| 1179 local function disass_block(ctx, ofs, len) | |
| 1180 if not ofs then ofs = 0 end | |
| 1181 local stop = len and ofs+len or #ctx.code | |
| 1182 ctx.pos = ofs | |
| 1183 ctx.rel = nil | |
| 1184 while ctx.pos < stop do disass_ins(ctx) end | |
| 1185 end | |
| 1186 | |
| 1187 -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). | |
| 1188 local function create(code, addr, out) | |
| 1189 local ctx = {} | |
| 1190 ctx.code = code | |
| 1191 ctx.addr = addr or 0 | |
| 1192 ctx.out = out or io.write | |
| 1193 ctx.symtab = {} | |
| 1194 ctx.disass = disass_block | |
| 1195 ctx.hexdump = 8 | |
| 1196 return ctx | |
| 1197 end | |
| 1198 | |
| 1199 -- Simple API: disassemble code (a string) at address and output via out. | |
| 1200 local function disass(code, addr, out) | |
| 1201 create(code, addr, out):disass() | |
| 1202 end | |
| 1203 | |
| 1204 -- Return register name for RID. | |
| 1205 local function regname(r) | |
| 1206 if r < 32 then return map_regs.x[r] end | |
| 1207 return map_regs.d[r-32] | |
| 1208 end | |
| 1209 | |
| 1210 -- Public module functions. | |
| 1211 return { | |
| 1212 create = create, | |
| 1213 disass = disass, | |
| 1214 regname = regname | |
| 1215 } | |
| 1216 |