1---------------------------------------------------------------------------- 2-- LuaJIT PPC disassembler module. 3-- 4-- Copyright (C) 2005-2017 Mike Pall. All rights reserved. 5-- Released under the MIT/X license. See Copyright Notice in luajit.h 6---------------------------------------------------------------------------- 7-- This is a helper module used by the LuaJIT machine code dumper module. 8-- 9-- It disassembles all common, non-privileged 32/64 bit PowerPC instructions 10-- plus the e500 SPE instructions and some Cell/Xenon extensions. 11-- 12-- NYI: VMX, VMX128 13------------------------------------------------------------------------------ 14 15local type = type 16local byte, format = string.byte, string.format 17local match, gmatch, gsub = string.match, string.gmatch, string.gsub 18local concat = table.concat 19local bit = require("bit") 20local band, bor, tohex = bit.band, bit.bor, bit.tohex 21local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift 22 23------------------------------------------------------------------------------ 24-- Primary and extended opcode maps 25------------------------------------------------------------------------------ 26 27local map_crops = { 28 shift = 1, mask = 1023, 29 [0] = "mcrfXX", 30 [33] = "crnor|crnotCCC=", [129] = "crandcCCC", 31 [193] = "crxor|crclrCCC%", [225] = "crnandCCC", 32 [257] = "crandCCC", [289] = "creqv|crsetCCC%", 33 [417] = "crorcCCC", [449] = "cror|crmoveCCC=", 34 [16] = "b_lrKB", [528] = "b_ctrKB", 35 [150] = "isync", 36} 37 38local map_rlwinm = setmetatable({ 39 shift = 0, mask = -1, 40}, 41{ __index = function(t, x) 42 local rot = band(rshift(x, 11), 31) 43 local mb = band(rshift(x, 6), 31) 44 local me = band(rshift(x, 1), 31) 45 if mb == 0 and me == 31-rot then 46 return "slwiRR~A." 47 elseif me == 31 and mb == 32-rot then 48 return "srwiRR~-A." 49 else 50 return "rlwinmRR~AAA." 51 end 52 end 53}) 54 55local map_rld = { 56 shift = 2, mask = 7, 57 [0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.", 58 { 59 shift = 1, mask = 1, 60 [0] = "rldclRR~RM.", "rldcrRR~RM.", 61 }, 62} 63 64local map_ext = setmetatable({ 65 shift = 1, mask = 1023, 66 67 [0] = "cmp_YLRR", [32] = "cmpl_YLRR", 68 [4] = "twARR", [68] = "tdARR", 69 70 [8] = "subfcRRR.", [40] = "subfRRR.", 71 [104] = "negRR.", [136] = "subfeRRR.", 72 [200] = "subfzeRR.", [232] = "subfmeRR.", 73 [520] = "subfcoRRR.", [552] = "subfoRRR.", 74 [616] = "negoRR.", [648] = "subfeoRRR.", 75 [712] = "subfzeoRR.", [744] = "subfmeoRR.", 76 77 [9] = "mulhduRRR.", [73] = "mulhdRRR.", [233] = "mulldRRR.", 78 [457] = "divduRRR.", [489] = "divdRRR.", 79 [745] = "mulldoRRR.", 80 [969] = "divduoRRR.", [1001] = "divdoRRR.", 81 82 [10] = "addcRRR.", [138] = "addeRRR.", 83 [202] = "addzeRR.", [234] = "addmeRR.", [266] = "addRRR.", 84 [522] = "addcoRRR.", [650] = "addeoRRR.", 85 [714] = "addzeoRR.", [746] = "addmeoRR.", [778] = "addoRRR.", 86 87 [11] = "mulhwuRRR.", [75] = "mulhwRRR.", [235] = "mullwRRR.", 88 [459] = "divwuRRR.", [491] = "divwRRR.", 89 [747] = "mullwoRRR.", 90 [971] = "divwouRRR.", [1003] = "divwoRRR.", 91 92 [15] = "iselltRRR", [47] = "iselgtRRR", [79] = "iseleqRRR", 93 94 [144] = { shift = 20, mask = 1, [0] = "mtcrfRZ~", "mtocrfRZ~", }, 95 [19] = { shift = 20, mask = 1, [0] = "mfcrR", "mfocrfRZ", }, 96 [371] = { shift = 11, mask = 1023, [392] = "mftbR", [424] = "mftbuR", }, 97 [339] = { 98 shift = 11, mask = 1023, 99 [32] = "mferR", [256] = "mflrR", [288] = "mfctrR", [16] = "mfspefscrR", 100 }, 101 [467] = { 102 shift = 11, mask = 1023, 103 [32] = "mtxerR", [256] = "mtlrR", [288] = "mtctrR", [16] = "mtspefscrR", 104 }, 105 106 [20] = "lwarxRR0R", [84] = "ldarxRR0R", 107 108 [21] = "ldxRR0R", [53] = "lduxRRR", 109 [149] = "stdxRR0R", [181] = "stduxRRR", 110 [341] = "lwaxRR0R", [373] = "lwauxRRR", 111 112 [23] = "lwzxRR0R", [55] = "lwzuxRRR", 113 [87] = "lbzxRR0R", [119] = "lbzuxRRR", 114 [151] = "stwxRR0R", [183] = "stwuxRRR", 115 [215] = "stbxRR0R", [247] = "stbuxRRR", 116 [279] = "lhzxRR0R", [311] = "lhzuxRRR", 117 [343] = "lhaxRR0R", [375] = "lhauxRRR", 118 [407] = "sthxRR0R", [439] = "sthuxRRR", 119 120 [54] = "dcbst-R0R", [86] = "dcbf-R0R", 121 [150] = "stwcxRR0R.", [214] = "stdcxRR0R.", 122 [246] = "dcbtst-R0R", [278] = "dcbt-R0R", 123 [310] = "eciwxRR0R", [438] = "ecowxRR0R", 124 [470] = "dcbi-RR", 125 126 [598] = { 127 shift = 21, mask = 3, 128 [0] = "sync", "lwsync", "ptesync", 129 }, 130 [758] = "dcba-RR", 131 [854] = "eieio", [982] = "icbi-R0R", [1014] = "dcbz-R0R", 132 133 [26] = "cntlzwRR~", [58] = "cntlzdRR~", 134 [122] = "popcntbRR~", 135 [154] = "prtywRR~", [186] = "prtydRR~", 136 137 [28] = "andRR~R.", [60] = "andcRR~R.", [124] = "nor|notRR~R=.", 138 [284] = "eqvRR~R.", [316] = "xorRR~R.", 139 [412] = "orcRR~R.", [444] = "or|mrRR~R=.", [476] = "nandRR~R.", 140 [508] = "cmpbRR~R", 141 142 [512] = "mcrxrX", 143 144 [532] = "ldbrxRR0R", [660] = "stdbrxRR0R", 145 146 [533] = "lswxRR0R", [597] = "lswiRR0A", 147 [661] = "stswxRR0R", [725] = "stswiRR0A", 148 149 [534] = "lwbrxRR0R", [662] = "stwbrxRR0R", 150 [790] = "lhbrxRR0R", [918] = "sthbrxRR0R", 151 152 [535] = "lfsxFR0R", [567] = "lfsuxFRR", 153 [599] = "lfdxFR0R", [631] = "lfduxFRR", 154 [663] = "stfsxFR0R", [695] = "stfsuxFRR", 155 [727] = "stfdxFR0R", [759] = "stfduxFR0R", 156 [855] = "lfiwaxFR0R", 157 [983] = "stfiwxFR0R", 158 159 [24] = "slwRR~R.", 160 161 [27] = "sldRR~R.", [536] = "srwRR~R.", 162 [792] = "srawRR~R.", [824] = "srawiRR~A.", 163 164 [794] = "sradRR~R.", [826] = "sradiRR~H.", [827] = "sradiRR~H.", 165 [922] = "extshRR~.", [954] = "extsbRR~.", [986] = "extswRR~.", 166 167 [539] = "srdRR~R.", 168}, 169{ __index = function(t, x) 170 if band(x, 31) == 15 then return "iselRRRC" end 171 end 172}) 173 174local map_ld = { 175 shift = 0, mask = 3, 176 [0] = "ldRRE", "lduRRE", "lwaRRE", 177} 178 179local map_std = { 180 shift = 0, mask = 3, 181 [0] = "stdRRE", "stduRRE", 182} 183 184local map_fps = { 185 shift = 5, mask = 1, 186 { 187 shift = 1, mask = 15, 188 [0] = false, false, "fdivsFFF.", false, 189 "fsubsFFF.", "faddsFFF.", "fsqrtsF-F.", false, 190 "fresF-F.", "fmulsFF-F.", "frsqrtesF-F.", false, 191 "fmsubsFFFF~.", "fmaddsFFFF~.", "fnmsubsFFFF~.", "fnmaddsFFFF~.", 192 } 193} 194 195local map_fpd = { 196 shift = 5, mask = 1, 197 [0] = { 198 shift = 1, mask = 1023, 199 [0] = "fcmpuXFF", [32] = "fcmpoXFF", [64] = "mcrfsXX", 200 [38] = "mtfsb1A.", [70] = "mtfsb0A.", [134] = "mtfsfiA>>-A>", 201 [8] = "fcpsgnFFF.", [40] = "fnegF-F.", [72] = "fmrF-F.", 202 [136] = "fnabsF-F.", [264] = "fabsF-F.", 203 [12] = "frspF-F.", 204 [14] = "fctiwF-F.", [15] = "fctiwzF-F.", 205 [583] = "mffsF.", [711] = "mtfsfZF.", 206 [392] = "frinF-F.", [424] = "frizF-F.", 207 [456] = "fripF-F.", [488] = "frimF-F.", 208 [814] = "fctidF-F.", [815] = "fctidzF-F.", [846] = "fcfidF-F.", 209 }, 210 { 211 shift = 1, mask = 15, 212 [0] = false, false, "fdivFFF.", false, 213 "fsubFFF.", "faddFFF.", "fsqrtF-F.", "fselFFFF~.", 214 "freF-F.", "fmulFF-F.", "frsqrteF-F.", false, 215 "fmsubFFFF~.", "fmaddFFFF~.", "fnmsubFFFF~.", "fnmaddFFFF~.", 216 } 217} 218 219local map_spe = { 220 shift = 0, mask = 2047, 221 222 [512] = "evaddwRRR", [514] = "evaddiwRAR~", 223 [516] = "evsubwRRR~", [518] = "evsubiwRAR~", 224 [520] = "evabsRR", [521] = "evnegRR", 225 [522] = "evextsbRR", [523] = "evextshRR", [524] = "evrndwRR", 226 [525] = "evcntlzwRR", [526] = "evcntlswRR", 227 228 [527] = "brincRRR", 229 230 [529] = "evandRRR", [530] = "evandcRRR", [534] = "evxorRRR", 231 [535] = "evor|evmrRRR=", [536] = "evnor|evnotRRR=", 232 [537] = "eveqvRRR", [539] = "evorcRRR", [542] = "evnandRRR", 233 234 [544] = "evsrwuRRR", [545] = "evsrwsRRR", 235 [546] = "evsrwiuRRA", [547] = "evsrwisRRA", 236 [548] = "evslwRRR", [550] = "evslwiRRA", 237 [552] = "evrlwRRR", [553] = "evsplatiRS", 238 [554] = "evrlwiRRA", [555] = "evsplatfiRS", 239 [556] = "evmergehiRRR", [557] = "evmergeloRRR", 240 [558] = "evmergehiloRRR", [559] = "evmergelohiRRR", 241 242 [560] = "evcmpgtuYRR", [561] = "evcmpgtsYRR", 243 [562] = "evcmpltuYRR", [563] = "evcmpltsYRR", 244 [564] = "evcmpeqYRR", 245 246 [632] = "evselRRR", [633] = "evselRRRW", 247 [634] = "evselRRRW", [635] = "evselRRRW", 248 [636] = "evselRRRW", [637] = "evselRRRW", 249 [638] = "evselRRRW", [639] = "evselRRRW", 250 251 [640] = "evfsaddRRR", [641] = "evfssubRRR", 252 [644] = "evfsabsRR", [645] = "evfsnabsRR", [646] = "evfsnegRR", 253 [648] = "evfsmulRRR", [649] = "evfsdivRRR", 254 [652] = "evfscmpgtYRR", [653] = "evfscmpltYRR", [654] = "evfscmpeqYRR", 255 [656] = "evfscfuiR-R", [657] = "evfscfsiR-R", 256 [658] = "evfscfufR-R", [659] = "evfscfsfR-R", 257 [660] = "evfsctuiR-R", [661] = "evfsctsiR-R", 258 [662] = "evfsctufR-R", [663] = "evfsctsfR-R", 259 [664] = "evfsctuizR-R", [666] = "evfsctsizR-R", 260 [668] = "evfststgtYRR", [669] = "evfststltYRR", [670] = "evfststeqYRR", 261 262 [704] = "efsaddRRR", [705] = "efssubRRR", 263 [708] = "efsabsRR", [709] = "efsnabsRR", [710] = "efsnegRR", 264 [712] = "efsmulRRR", [713] = "efsdivRRR", 265 [716] = "efscmpgtYRR", [717] = "efscmpltYRR", [718] = "efscmpeqYRR", 266 [719] = "efscfdR-R", 267 [720] = "efscfuiR-R", [721] = "efscfsiR-R", 268 [722] = "efscfufR-R", [723] = "efscfsfR-R", 269 [724] = "efsctuiR-R", [725] = "efsctsiR-R", 270 [726] = "efsctufR-R", [727] = "efsctsfR-R", 271 [728] = "efsctuizR-R", [730] = "efsctsizR-R", 272 [732] = "efststgtYRR", [733] = "efststltYRR", [734] = "efststeqYRR", 273 274 [736] = "efdaddRRR", [737] = "efdsubRRR", 275 [738] = "efdcfuidR-R", [739] = "efdcfsidR-R", 276 [740] = "efdabsRR", [741] = "efdnabsRR", [742] = "efdnegRR", 277 [744] = "efdmulRRR", [745] = "efddivRRR", 278 [746] = "efdctuidzR-R", [747] = "efdctsidzR-R", 279 [748] = "efdcmpgtYRR", [749] = "efdcmpltYRR", [750] = "efdcmpeqYRR", 280 [751] = "efdcfsR-R", 281 [752] = "efdcfuiR-R", [753] = "efdcfsiR-R", 282 [754] = "efdcfufR-R", [755] = "efdcfsfR-R", 283 [756] = "efdctuiR-R", [757] = "efdctsiR-R", 284 [758] = "efdctufR-R", [759] = "efdctsfR-R", 285 [760] = "efdctuizR-R", [762] = "efdctsizR-R", 286 [764] = "efdtstgtYRR", [765] = "efdtstltYRR", [766] = "efdtsteqYRR", 287 288 [768] = "evlddxRR0R", [769] = "evlddRR8", 289 [770] = "evldwxRR0R", [771] = "evldwRR8", 290 [772] = "evldhxRR0R", [773] = "evldhRR8", 291 [776] = "evlhhesplatxRR0R", [777] = "evlhhesplatRR2", 292 [780] = "evlhhousplatxRR0R", [781] = "evlhhousplatRR2", 293 [782] = "evlhhossplatxRR0R", [783] = "evlhhossplatRR2", 294 [784] = "evlwhexRR0R", [785] = "evlwheRR4", 295 [788] = "evlwhouxRR0R", [789] = "evlwhouRR4", 296 [790] = "evlwhosxRR0R", [791] = "evlwhosRR4", 297 [792] = "evlwwsplatxRR0R", [793] = "evlwwsplatRR4", 298 [796] = "evlwhsplatxRR0R", [797] = "evlwhsplatRR4", 299 300 [800] = "evstddxRR0R", [801] = "evstddRR8", 301 [802] = "evstdwxRR0R", [803] = "evstdwRR8", 302 [804] = "evstdhxRR0R", [805] = "evstdhRR8", 303 [816] = "evstwhexRR0R", [817] = "evstwheRR4", 304 [820] = "evstwhoxRR0R", [821] = "evstwhoRR4", 305 [824] = "evstwwexRR0R", [825] = "evstwweRR4", 306 [828] = "evstwwoxRR0R", [829] = "evstwwoRR4", 307 308 [1027] = "evmhessfRRR", [1031] = "evmhossfRRR", [1032] = "evmheumiRRR", 309 [1033] = "evmhesmiRRR", [1035] = "evmhesmfRRR", [1036] = "evmhoumiRRR", 310 [1037] = "evmhosmiRRR", [1039] = "evmhosmfRRR", [1059] = "evmhessfaRRR", 311 [1063] = "evmhossfaRRR", [1064] = "evmheumiaRRR", [1065] = "evmhesmiaRRR", 312 [1067] = "evmhesmfaRRR", [1068] = "evmhoumiaRRR", [1069] = "evmhosmiaRRR", 313 [1071] = "evmhosmfaRRR", [1095] = "evmwhssfRRR", [1096] = "evmwlumiRRR", 314 [1100] = "evmwhumiRRR", [1101] = "evmwhsmiRRR", [1103] = "evmwhsmfRRR", 315 [1107] = "evmwssfRRR", [1112] = "evmwumiRRR", [1113] = "evmwsmiRRR", 316 [1115] = "evmwsmfRRR", [1127] = "evmwhssfaRRR", [1128] = "evmwlumiaRRR", 317 [1132] = "evmwhumiaRRR", [1133] = "evmwhsmiaRRR", [1135] = "evmwhsmfaRRR", 318 [1139] = "evmwssfaRRR", [1144] = "evmwumiaRRR", [1145] = "evmwsmiaRRR", 319 [1147] = "evmwsmfaRRR", 320 321 [1216] = "evaddusiaawRR", [1217] = "evaddssiaawRR", 322 [1218] = "evsubfusiaawRR", [1219] = "evsubfssiaawRR", 323 [1220] = "evmraRR", 324 [1222] = "evdivwsRRR", [1223] = "evdivwuRRR", 325 [1224] = "evaddumiaawRR", [1225] = "evaddsmiaawRR", 326 [1226] = "evsubfumiaawRR", [1227] = "evsubfsmiaawRR", 327 328 [1280] = "evmheusiaawRRR", [1281] = "evmhessiaawRRR", 329 [1283] = "evmhessfaawRRR", [1284] = "evmhousiaawRRR", 330 [1285] = "evmhossiaawRRR", [1287] = "evmhossfaawRRR", 331 [1288] = "evmheumiaawRRR", [1289] = "evmhesmiaawRRR", 332 [1291] = "evmhesmfaawRRR", [1292] = "evmhoumiaawRRR", 333 [1293] = "evmhosmiaawRRR", [1295] = "evmhosmfaawRRR", 334 [1320] = "evmhegumiaaRRR", [1321] = "evmhegsmiaaRRR", 335 [1323] = "evmhegsmfaaRRR", [1324] = "evmhogumiaaRRR", 336 [1325] = "evmhogsmiaaRRR", [1327] = "evmhogsmfaaRRR", 337 [1344] = "evmwlusiaawRRR", [1345] = "evmwlssiaawRRR", 338 [1352] = "evmwlumiaawRRR", [1353] = "evmwlsmiaawRRR", 339 [1363] = "evmwssfaaRRR", [1368] = "evmwumiaaRRR", 340 [1369] = "evmwsmiaaRRR", [1371] = "evmwsmfaaRRR", 341 [1408] = "evmheusianwRRR", [1409] = "evmhessianwRRR", 342 [1411] = "evmhessfanwRRR", [1412] = "evmhousianwRRR", 343 [1413] = "evmhossianwRRR", [1415] = "evmhossfanwRRR", 344 [1416] = "evmheumianwRRR", [1417] = "evmhesmianwRRR", 345 [1419] = "evmhesmfanwRRR", [1420] = "evmhoumianwRRR", 346 [1421] = "evmhosmianwRRR", [1423] = "evmhosmfanwRRR", 347 [1448] = "evmhegumianRRR", [1449] = "evmhegsmianRRR", 348 [1451] = "evmhegsmfanRRR", [1452] = "evmhogumianRRR", 349 [1453] = "evmhogsmianRRR", [1455] = "evmhogsmfanRRR", 350 [1472] = "evmwlusianwRRR", [1473] = "evmwlssianwRRR", 351 [1480] = "evmwlumianwRRR", [1481] = "evmwlsmianwRRR", 352 [1491] = "evmwssfanRRR", [1496] = "evmwumianRRR", 353 [1497] = "evmwsmianRRR", [1499] = "evmwsmfanRRR", 354} 355 356local map_pri = { 357 [0] = false, false, "tdiARI", "twiARI", 358 map_spe, false, false, "mulliRRI", 359 "subficRRI", false, "cmpl_iYLRU", "cmp_iYLRI", 360 "addicRRI", "addic.RRI", "addi|liRR0I", "addis|lisRR0I", 361 "b_KBJ", "sc", "bKJ", map_crops, 362 "rlwimiRR~AAA.", map_rlwinm, false, "rlwnmRR~RAA.", 363 "oriNRR~U", "orisRR~U", "xoriRR~U", "xorisRR~U", 364 "andi.RR~U", "andis.RR~U", map_rld, map_ext, 365 "lwzRRD", "lwzuRRD", "lbzRRD", "lbzuRRD", 366 "stwRRD", "stwuRRD", "stbRRD", "stbuRRD", 367 "lhzRRD", "lhzuRRD", "lhaRRD", "lhauRRD", 368 "sthRRD", "sthuRRD", "lmwRRD", "stmwRRD", 369 "lfsFRD", "lfsuFRD", "lfdFRD", "lfduFRD", 370 "stfsFRD", "stfsuFRD", "stfdFRD", "stfduFRD", 371 false, false, map_ld, map_fps, 372 false, false, map_std, map_fpd, 373} 374 375------------------------------------------------------------------------------ 376 377local map_gpr = { 378 [0] = "r0", "sp", "r2", "r3", "r4", "r5", "r6", "r7", 379 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 380 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 381 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", 382} 383 384local map_cond = { [0] = "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", } 385 386-- Format a condition bit. 387local function condfmt(cond) 388 if cond <= 3 then 389 return map_cond[band(cond, 3)] 390 else 391 return format("4*cr%d+%s", rshift(cond, 2), map_cond[band(cond, 3)]) 392 end 393end 394 395------------------------------------------------------------------------------ 396 397-- Output a nicely formatted line with an opcode and operands. 398local function putop(ctx, text, operands) 399 local pos = ctx.pos 400 local extra = "" 401 if ctx.rel then 402 local sym = ctx.symtab[ctx.rel] 403 if sym then extra = "\t->"..sym end 404 end 405 if ctx.hexdump > 0 then 406 ctx.out(format("%08x %s %-7s %s%s\n", 407 ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) 408 else 409 ctx.out(format("%08x %-7s %s%s\n", 410 ctx.addr+pos, text, concat(operands, ", "), extra)) 411 end 412 ctx.pos = pos + 4 413end 414 415-- Fallback for unknown opcodes. 416local function unknown(ctx) 417 return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) 418end 419 420-- Disassemble a single instruction. 421local function disass_ins(ctx) 422 local pos = ctx.pos 423 local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) 424 local op = bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3) 425 local operands = {} 426 local last = nil 427 local rs = 21 428 ctx.op = op 429 ctx.rel = nil 430 431 local opat = map_pri[rshift(b0, 2)] 432 while type(opat) ~= "string" do 433 if not opat then return unknown(ctx) end 434 opat = opat[band(rshift(op, opat.shift), opat.mask)] 435 end 436 local name, pat = match(opat, "^([a-z0-9_.]*)(.*)") 437 local altname, pat2 = match(pat, "|([a-z0-9_.]*)(.*)") 438 if altname then pat = pat2 end 439 440 for p in gmatch(pat, ".") do 441 local x = nil 442 if p == "R" then 443 x = map_gpr[band(rshift(op, rs), 31)] 444 rs = rs - 5 445 elseif p == "F" then 446 x = "f"..band(rshift(op, rs), 31) 447 rs = rs - 5 448 elseif p == "A" then 449 x = band(rshift(op, rs), 31) 450 rs = rs - 5 451 elseif p == "S" then 452 x = arshift(lshift(op, 27-rs), 27) 453 rs = rs - 5 454 elseif p == "I" then 455 x = arshift(lshift(op, 16), 16) 456 elseif p == "U" then 457 x = band(op, 0xffff) 458 elseif p == "D" or p == "E" then 459 local disp = arshift(lshift(op, 16), 16) 460 if p == "E" then disp = band(disp, -4) end 461 if last == "r0" then last = "0" end 462 operands[#operands] = format("%d(%s)", disp, last) 463 elseif p >= "2" and p <= "8" then 464 local disp = band(rshift(op, rs), 31) * p 465 if last == "r0" then last = "0" end 466 operands[#operands] = format("%d(%s)", disp, last) 467 elseif p == "H" then 468 x = band(rshift(op, rs), 31) + lshift(band(op, 2), 4) 469 rs = rs - 5 470 elseif p == "M" then 471 x = band(rshift(op, rs), 31) + band(op, 0x20) 472 elseif p == "C" then 473 x = condfmt(band(rshift(op, rs), 31)) 474 rs = rs - 5 475 elseif p == "B" then 476 local bo = rshift(op, 21) 477 local cond = band(rshift(op, 16), 31) 478 local cn = "" 479 rs = rs - 10 480 if band(bo, 4) == 0 then 481 cn = band(bo, 2) == 0 and "dnz" or "dz" 482 if band(bo, 0x10) == 0 then 483 cn = cn..(band(bo, 8) == 0 and "f" or "t") 484 end 485 if band(bo, 0x10) == 0 then x = condfmt(cond) end 486 name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+") 487 elseif band(bo, 0x10) == 0 then 488 cn = map_cond[band(cond, 3) + (band(bo, 8) == 0 and 4 or 0)] 489 if cond > 3 then x = "cr"..rshift(cond, 2) end 490 name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+") 491 end 492 name = gsub(name, "_", cn) 493 elseif p == "J" then 494 x = arshift(lshift(op, 27-rs), 29-rs)*4 495 if band(op, 2) == 0 then x = ctx.addr + pos + x end 496 ctx.rel = x 497 x = "0x"..tohex(x) 498 elseif p == "K" then 499 if band(op, 1) ~= 0 then name = name.."l" end 500 if band(op, 2) ~= 0 then name = name.."a" end 501 elseif p == "X" or p == "Y" then 502 x = band(rshift(op, rs+2), 7) 503 if x == 0 and p == "Y" then x = nil else x = "cr"..x end 504 rs = rs - 5 505 elseif p == "W" then 506 x = "cr"..band(op, 7) 507 elseif p == "Z" then 508 x = band(rshift(op, rs-4), 255) 509 rs = rs - 10 510 elseif p == ">" then 511 operands[#operands] = rshift(operands[#operands], 1) 512 elseif p == "0" then 513 if last == "r0" then 514 operands[#operands] = nil 515 if altname then name = altname end 516 end 517 elseif p == "L" then 518 name = gsub(name, "_", band(op, 0x00200000) ~= 0 and "d" or "w") 519 elseif p == "." then 520 if band(op, 1) == 1 then name = name.."." end 521 elseif p == "N" then 522 if op == 0x60000000 then name = "nop"; break end 523 elseif p == "~" then 524 local n = #operands 525 operands[n-1], operands[n] = operands[n], operands[n-1] 526 elseif p == "=" then 527 local n = #operands 528 if last == operands[n-1] then 529 operands[n] = nil 530 name = altname 531 end 532 elseif p == "%" then 533 local n = #operands 534 if last == operands[n-1] and last == operands[n-2] then 535 operands[n] = nil 536 operands[n-1] = nil 537 name = altname 538 end 539 elseif p == "-" then 540 rs = rs - 5 541 else 542 assert(false) 543 end 544 if x then operands[#operands+1] = x; last = x end 545 end 546 547 return putop(ctx, name, operands) 548end 549 550------------------------------------------------------------------------------ 551 552-- Disassemble a block of code. 553local function disass_block(ctx, ofs, len) 554 if not ofs then ofs = 0 end 555 local stop = len and ofs+len or #ctx.code 556 stop = stop - stop % 4 557 ctx.pos = ofs - ofs % 4 558 ctx.rel = nil 559 while ctx.pos < stop do disass_ins(ctx) end 560end 561 562-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). 563local function create(code, addr, out) 564 local ctx = {} 565 ctx.code = code 566 ctx.addr = addr or 0 567 ctx.out = out or io.write 568 ctx.symtab = {} 569 ctx.disass = disass_block 570 ctx.hexdump = 8 571 return ctx 572end 573 574-- Simple API: disassemble code (a string) at address and output via out. 575local function disass(code, addr, out) 576 create(code, addr, out):disass() 577end 578 579-- Return register name for RID. 580local function regname(r) 581 if r < 32 then return map_gpr[r] end 582 return "f"..(r-32) 583end 584 585-- Public module functions. 586return { 587 create = create, 588 disass = disass, 589 regname = regname 590} 591 592