Merge branch 'master' into v2.1
[luajit-2.0.git] / src / jit / dis_ppc.lua
blob178df1cecd150515e943d2da664395573eb74d4c
1 ----------------------------------------------------------------------------
2 -- LuaJIT PPC disassembler module.
3 --
4 -- Copyright (C) 2005-2014 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_rlwinm = setmetatable({
39 shift = 0, mask = -1,
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
55 local map_rld = {
56 shift = 2, mask = 7,
57 [0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.",
59 shift = 1, mask = 1,
60 [0] = "rldclRR~RM.", "rldcrRR~RM.",
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.",
79 [745] = "mulldoRRR.",
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.",
89 [747] = "mullwoRRR.",
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", },
97 [339] = {
98 shift = 11, mask = 1023,
99 [32] = "mferR", [256] = "mflrR", [288] = "mfctrR", [16] = "mfspefscrR",
101 [467] = {
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",
124 [470] = "dcbi-RR",
126 [598] = {
127 shift = 21, mask = 3,
128 [0] = "sync", "lwsync", "ptesync",
130 [758] = "dcba-RR",
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.",
140 [508] = "cmpbRR~R",
142 [512] = "mcrxrX",
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",
159 [24] = "slwRR~R.",
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~.",
167 [539] = "srdRR~R.",
169 { __index = function(t, x)
170 if band(x, 31) == 15 then return "iselRRRC" end
174 local map_ld = {
175 shift = 0, mask = 3,
176 [0] = "ldRRE", "lduRRE", "lwaRRE",
179 local map_std = {
180 shift = 0, mask = 3,
181 [0] = "stdRRE", "stduRRE",
184 local map_fps = {
185 shift = 5, mask = 1,
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~.",
195 local 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.",
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~.",
219 local map_spe = {
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",
228 [527] = "brincRRR",
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",
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",
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",
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",
323 [1220] = "evmraRR",
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",
356 local 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,
375 ------------------------------------------------------------------------------
377 local 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",
384 local map_cond = { [0] = "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", }
386 -- Format a condition bit.
387 local 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)])
395 ------------------------------------------------------------------------------
397 -- Output a nicely formatted line with an opcode and operands.
398 local 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
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))
412 ctx.pos = pos + 4
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)
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
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
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")
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)
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
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
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
539 elseif p == "-" then
540 rs = rs - 5
541 else
542 assert(false)
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
558 ctx.rel = nil
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)
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
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
582 return "f"..(r-32)
585 -- Public module functions.
586 return {
587 create = create,
588 disass = disass,
589 regname = regname