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