PPC: Add y-bit variants of conditional branches to DynASM.
[luajit-2.0.git] / lib / dis_ppc.lua
blob13d87c70bb7fb23b28dd33639a68001b4760b3de
1 ----------------------------------------------------------------------------
2 -- LuaJIT PPC disassembler module.
3 --
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.
8 --
9 -- It disassembles all common, non-privileged 32/64 bit PowerPC instructions
10 -- plus the e500 SPE instructions and some Cell/Xenon extensions.
12 -- NYI: VMX, VMX128
13 ------------------------------------------------------------------------------
15 local type = type
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 ------------------------------------------------------------------------------
27 local 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",
38 local map_rld = {
39 shift = 2, mask = 7,
40 [0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.",
42 shift = 1, mask = 1,
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.",
62 [745] = "mulldoRRR.",
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.",
72 [747] = "mullwoRRR.",
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", },
80 [339] = {
81 shift = 11, mask = 1023,
82 [32] = "mferR", [256] = "mflrR", [288] = "mfctrR", [16] = "mfspefscrR",
84 [467] = {
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",
107 [470] = "dcbi-RR",
109 [598] = {
110 shift = 21, mask = 3,
111 [0] = "sync", "lwsync", "ptesync",
113 [758] = "dcba-RR",
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.",
123 [508] = "cmpbRR~R",
125 [512] = "mcrxrX",
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",
142 [24] = "slwRR~R.",
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~.",
150 [539] = "srdRR~R.",
152 { __index = function(t, x)
153 if band(x, 31) == 15 then return "iselRRRC" end
157 local map_ld = {
158 shift = 0, mask = 3,
159 [0] = "ldRRE", "lduRRE", "lwaRRE",
162 local map_std = {
163 shift = 0, mask = 3,
164 [0] = "stdRRE", "stduRRE",
167 local map_fps = {
168 shift = 5, mask = 1,
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~.",
178 local map_fpd = {
179 shift = 5, mask = 1,
180 [0] = {
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.",
186 [12] = "frspF-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~.",
202 local map_spe = {
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",
211 [527] = "brincRRR",
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",
249 [719] = "efscfdR-R",
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",
263 [751] = "efdcfsR-R",
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",
306 [1220] = "evmraRR",
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",
339 local map_pri = {
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 ------------------------------------------------------------------------------
360 local map_gpr = {
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)
371 if cond <= 3 then
372 return map_cond[band(cond, 3)]
373 else
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)
382 local pos = ctx.pos
383 local extra = ""
384 if ctx.rel then
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))
391 else
392 ctx.out(format("%08x %-7s %s%s\n",
393 ctx.addr+pos, text, concat(operands, ", "), extra))
395 ctx.pos = pos + 4
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)
405 local pos = ctx.pos
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)
408 local operands = {}
409 local last = nil
410 local rs = 21
411 ctx.op = op
412 ctx.rel = nil
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
424 local x = nil
425 if p == "R" then
426 x = map_gpr[band(rshift(op, rs), 31)]
427 rs = rs - 5
428 elseif p == "F" then
429 x = "f"..band(rshift(op, rs), 31)
430 rs = rs - 5
431 elseif p == "A" then
432 x = band(rshift(op, rs), 31)
433 rs = rs - 5
434 elseif p == "S" then
435 x = arshift(lshift(op, 27-rs), 27)
436 rs = rs - 5
437 elseif p == "I" then
438 x = arshift(lshift(op, 16), 16)
439 elseif p == "U" then
440 x = band(op, 0xffff)
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)
450 elseif p == "H" then
451 x = band(rshift(op, rs), 31) + lshift(band(op, 2), 4)
452 rs = rs - 5
453 elseif p == "M" then
454 x = band(rshift(op, rs), 31) + band(op, 0x20)
455 elseif p == "C" then
456 x = condfmt(band(rshift(op, rs), 31))
457 rs = rs - 5
458 elseif p == "B" then
459 local bo = rshift(op, 21)
460 local cond = band(rshift(op, 16), 31)
461 local cn = ""
462 rs = rs - 10
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)
486 elseif p == "J" then
487 x = arshift(lshift(op, 27-rs), 29-rs)*4
488 if band(op, 2) == 0 then x = ctx.addr + pos + x end
489 ctx.rel = x
490 x = "0x"..tohex(x)
491 elseif p == "K" then
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
497 rs = rs - 5
498 elseif p == "W" then
499 x = "cr"..band(op, 7)
500 elseif p == "Z" then
501 x = band(rshift(op, rs-4), 255)
502 rs = rs - 10
503 elseif p == ">" then
504 operands[#operands] = rshift(operands[#operands], 1)
505 elseif p == "0" then
506 if last == "r0" then
507 operands[#operands] = nil
508 if altname then name = altname end
510 elseif p == "L" then
511 name = gsub(name, "_", band(op, 0x00200000) ~= 0 and "d" or "w")
512 elseif p == "." then
513 if band(op, 1) == 1 then name = name.."." end
514 elseif p == "N" then
515 if op == 0x60000000 then name = "nop"; break end
516 elseif p == "~" then
517 local n = #operands
518 operands[n-1], operands[n] = operands[n], operands[n-1]
519 elseif p == "=" then
520 local n = #operands
521 if last == operands[n-1] then
522 operands[n] = nil
523 name = altname
525 elseif p == "%" then
526 local n = #operands
527 if last == operands[n-1] and last == operands[n-2] then
528 operands[n] = nil
529 operands[n-1] = nil
530 name = altname
532 elseif p == "-" then
533 rs = rs - 5
534 else
535 assert(false)
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
551 ctx.rel = nil
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)
557 local ctx = {}
558 ctx.code = code
559 ctx.addr = addr or 0
560 ctx.out = out or io.write
561 ctx.symtab = {}
562 ctx.disass = disass_block
563 ctx.hexdump = 8
564 return ctx
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.
574 module(...)
576 create = create_
577 disass = disass_