1 ----------------------------------------------------------------------------
2 -- LuaJIT PPC disassembler module.
4 -- Copyright (C) 2005-2010 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.
9 -- It disassembles all common, non-privileged 32/64 bit PowerPC instructions
10 -- plus the e500 SPE instructions and some Cell/Xenon extensions.
13 ------------------------------------------------------------------------------
16 local sub
, byte
, format = string.sub
, string.byte
, string.format
17 local match
, gmatch
, gsub = string.match
, string.gmatch
, string.gsub
18 local concat
= table.concat
19 local bit
= require("bit")
20 local band
, bor
, tohex
= bit
.band
, bit
.bor
, bit
.tohex
21 local lshift
, rshift
, arshift
= bit
.lshift
, bit
.rshift
, bit
.arshift
23 ------------------------------------------------------------------------------
24 -- Primary and extended opcode maps
25 ------------------------------------------------------------------------------
28 shift
= 1, mask
= 1023,
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",
38 local map_rlwinm
= setmetatable({
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
47 elseif me
== 31 and mb
== 32-rot
then
50 return "rlwinmRR~AAA."
57 [0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.",
60 [0] = "rldclRR~HM.", "rldcrRR~HM.",
64 local map_ext
= setmetatable({
65 shift
= 1, mask
= 1023,
67 [0] = "cmp_YLRR", [32] = "cmpl_YLRR",
68 [4] = "twARR", [68] = "tdARR",
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.",
77 [9] = "mulhduRRR.", [73] = "mulhdRRR.", [233] = "mulldRRR.",
78 [457] = "divduRRR.", [489] = "divdRRR.",
80 [969] = "divduoRRR.", [1001] = "divdoRRR.",
82 [10] = "addcRRR.", [138] = "addeRRR.",
83 [202] = "addzeRR.", [234] = "addmeRR.", [266] = "addRRR.",
84 [522] = "addcoRRR.", [650] = "addeoRRR.",
85 [714] = "addzeoRR.", [746] = "addmeoRR.", [778] = "addoRRR.",
87 [11] = "mulhwuRRR.", [75] = "mulhwRRR.", [235] = "mullwRRR.",
88 [459] = "divwuRRR.", [491] = "divwRRR.",
90 [971] = "divwouRRR.", [1003] = "divwoRRR.",
92 [15] = "iselltRRR", [47] = "iselgtRRR", [79] = "iseleqRRR",
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", },
98 shift
= 11, mask
= 1023,
99 [32] = "mferR", [256] = "mflrR", [288] = "mfctrR", [16] = "mfspefscrR",
102 shift
= 11, mask
= 1023,
103 [32] = "mtxerR", [256] = "mtlrR", [288] = "mtctrR", [16] = "mtspefscrR",
106 [20] = "lwarxRR0R", [84] = "ldarxRR0R",
108 [21] = "ldxRR0R", [53] = "lduxRRR",
109 [149] = "stdxRR0R", [181] = "stduxRRR",
110 [341] = "lwaxRR0R", [373] = "lwauxRRR",
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",
120 [54] = "dcbst-R0R", [86] = "dcbf-R0R",
121 [150] = "stwcxRR0R.", [214] = "stdcxRR0R.",
122 [246] = "dcbtst-R0R", [278] = "dcbt-R0R",
123 [310] = "eciwxRR0R", [438] = "ecowxRR0R",
127 shift
= 21, mask
= 3,
128 [0] = "sync", "lwsync", "ptesync",
131 [854] = "eieio", [982] = "icbi-R0R", [1014] = "dcbz-R0R",
133 [26] = "cntlzwRR~", [58] = "cntlzdRR~",
134 [122] = "popcntbRR~",
135 [154] = "prtywRR~", [186] = "prtydRR~",
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.",
144 [532] = "ldbrxRR0R", [660] = "stdbrxRR0R",
146 [533] = "lswxRR0R", [597] = "lswiRR0A",
147 [661] = "stswxRR0R", [725] = "stswiRR0A",
149 [534] = "lwbrxRR0R", [662] = "stwbrxRR0R",
150 [790] = "lhbrxRR0R", [918] = "sthbrxRR0R",
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",
161 [27] = "sldRR~R.", [536] = "srwRR~R.",
162 [792] = "srawRR~R.", [824] = "srawiRR~A.",
164 [794] = "sradRR~R.", [826] = "sradiRR~H.", [827] = "sradiRR~H.",
165 [922] = "extshRR~.", [954] = "extsbRR~.", [986] = "extswRR~.",
169 { __index
= function(t
, x
)
170 if band(x
, 31) == 15 then return "iselRRRC" end
176 [0] = "ldRRE", "lduRRE", "lwaRRE",
181 [0] = "stdRRE", "stduRRE",
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~.",
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.",
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.",
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~.",
220 shift
= 0, mask
= 2047,
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",
230 [529] = "evandRRR", [530] = "evandcRRR", [534] = "evxorRRR",
231 [535] = "evor|evmrRRR=", [536] = "evnor|evnotRRR=",
232 [537] = "eveqvRRR", [539] = "evorcRRR", [542] = "evnandRRR",
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",
242 [560] = "evcmpgtuYRR", [561] = "evcmpgtsYRR",
243 [562] = "evcmpltuYRR", [563] = "evcmpltsYRR",
244 [564] = "evcmpeqYRR",
246 [632] = "evselRRR", [633] = "evselRRRW",
247 [634] = "evselRRRW", [635] = "evselRRRW",
248 [636] = "evselRRRW", [637] = "evselRRRW",
249 [638] = "evselRRRW", [639] = "evselRRRW",
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",
262 [704] = "efsaddRRR", [705] = "efssubRRR",
263 [708] = "efsabsRR", [709] = "efsnabsRR", [710] = "efsnegRR",
264 [712] = "efsmulRRR", [713] = "efsdivRRR",
265 [716] = "efscmpgtYRR", [717] = "efscmpltYRR", [718] = "efscmpeqYRR",
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",
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",
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",
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",
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",
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",
321 [1216] = "evaddusiaawRR", [1217] = "evaddssiaawRR",
322 [1218] = "evsubfusiaawRR", [1219] = "evsubfssiaawRR",
324 [1222] = "evdivwsRRR", [1223] = "evdivwuRRR",
325 [1224] = "evaddumiaawRR", [1225] = "evaddsmiaawRR",
326 [1226] = "evsubfumiaawRR", [1227] = "evsubfsmiaawRR",
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",
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
,
375 ------------------------------------------------------------------------------
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",
384 local map_cond
= { [0] = "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", }
386 -- Format a condition bit.
387 local function condfmt(cond
)
389 return map_cond
[band(cond
, 3)]
391 return format("4*cr%d+%s", rshift(cond
, 2), map_cond
[band(cond
, 3)])
395 ------------------------------------------------------------------------------
397 -- Output a nicely formatted line with an opcode and operands.
398 local function putop(ctx
, text
, operands
)
402 local sym
= ctx
.symtab
[ctx
.rel
]
403 if sym
then extra
= "\t->"..sym
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
))
409 ctx
.out(format("%08x %-7s %s%s\n",
410 ctx
.addr
+pos
, text
, concat(operands
, ", "), extra
))
415 -- Fallback for unknown opcodes.
416 local function unknown(ctx
)
417 return putop(ctx
, ".long", { "0x"..tohex(ctx
.op
) })
420 -- Disassemble a single instruction.
421 local function disass_ins(ctx
)
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
)
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
)]
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
440 for p
in gmatch(pat
, ".") do
443 x
= map_gpr
[band(rshift(op
, rs
), 31)]
446 x
= "f"..band(rshift(op
, rs
), 31)
449 x
= band(rshift(op
, rs
), 31)
452 x
= arshift(lshift(op
, 27-rs
), 27)
455 x
= arshift(lshift(op
, 16), 16)
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
)
468 x
= band(rshift(op
, rs
), 31) + lshift(band(op
, 2), 4)
471 x
= band(rshift(op
, rs
), 31) + band(op
, 0x20)
473 x
= condfmt(band(rshift(op
, rs
), 31))
476 local bo
= rshift(op
, 21)
477 local cond
= band(rshift(op
, 16), 31)
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")
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 "+")
492 name
= gsub(name
, "_", cn
)
494 x
= arshift(lshift(op
, 27-rs
), 29-rs
)*4
495 if band(op
, 2) == 0 then x
= ctx
.addr
+ pos
+ x
end
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
506 x
= "cr"..band(op
, 7)
508 x
= band(rshift(op
, rs
-4), 255)
511 operands
[#operands
] = rshift(operands
[#operands
], 1)
514 operands
[#operands
] = nil
515 if altname
then name
= altname
end
518 name
= gsub(name
, "_", band(op
, 0x00200000) ~= 0 and "d" or "w")
520 if band(op
, 1) == 1 then name
= name
.."." end
522 if op
== 0x60000000 then name
= "nop"; break end
525 operands
[n
-1], operands
[n
] = operands
[n
], operands
[n
-1]
528 if last
== operands
[n
-1] then
534 if last
== operands
[n
-1] and last
== operands
[n
-2] then
544 if x
then operands
[#operands
+1] = x
; last
= x
end
547 return putop(ctx
, name
, operands
)
550 ------------------------------------------------------------------------------
552 -- Disassemble a block of code.
553 local 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
559 while ctx
.pos
< stop
do disass_ins(ctx
) end
562 -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
563 local function create_(code
, addr
, out
)
567 ctx
.out
= out
or io
.write
569 ctx
.disass
= disass_block
574 -- Simple API: disassemble code (a string) at address and output via out.
575 local function disass_(code
, addr
, out
)
576 create_(code
, addr
, out
):disass()
579 -- Return register name for RID.
580 local function regname_(r
)
581 if r
< 32 then return map_gpr
[r
] end
585 -- Public module functions.