diff options
author | Mike Pall <mike> | 2011-08-18 19:41:27 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2011-08-18 19:41:27 +0200 |
commit | ec1b70ae35996f825506bacb0b10bccaf66eb6b5 (patch) | |
tree | 247e6b8d1a2d95a6069379cf3d0990a65b700639 /lib | |
parent | 607bd88f57f427a03bedf0ed6dd8f44c90b1e1a1 (diff) | |
download | luajit-ec1b70ae35996f825506bacb0b10bccaf66eb6b5.tar.gz luajit-ec1b70ae35996f825506bacb0b10bccaf66eb6b5.tar.bz2 luajit-ec1b70ae35996f825506bacb0b10bccaf66eb6b5.zip |
PPC: Add PPC disassembler.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/dis_ppc.lua | 578 |
1 files changed, 578 insertions, 0 deletions
diff --git a/lib/dis_ppc.lua b/lib/dis_ppc.lua new file mode 100644 index 00000000..13d87c70 --- /dev/null +++ b/lib/dis_ppc.lua | |||
@@ -0,0 +1,578 @@ | |||
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. | ||
11 | -- | ||
12 | -- NYI: VMX, VMX128 | ||
13 | ------------------------------------------------------------------------------ | ||
14 | |||
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 | ||
22 | |||
23 | ------------------------------------------------------------------------------ | ||
24 | -- Primary and extended opcode maps | ||
25 | ------------------------------------------------------------------------------ | ||
26 | |||
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", | ||
36 | } | ||
37 | |||
38 | local map_rld = { | ||
39 | shift = 2, mask = 7, | ||
40 | [0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.", | ||
41 | { | ||
42 | shift = 1, mask = 1, | ||
43 | [0] = "rldclRR~HM.", "rldcrRR~HM.", | ||
44 | }, | ||
45 | } | ||
46 | |||
47 | local map_ext = setmetatable({ | ||
48 | shift = 1, mask = 1023, | ||
49 | |||
50 | [0] = "cmp_YLRR", [32] = "cmpl_YLRR", | ||
51 | [4] = "twARR", [68] = "tdARR", | ||
52 | |||
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.", | ||
59 | |||
60 | [9] = "mulhduRRR.", [73] = "mulhdRRR.", [233] = "mulldRRR.", | ||
61 | [457] = "divduRRR.", [489] = "divdRRR.", | ||
62 | [745] = "mulldoRRR.", | ||
63 | [969] = "divduoRRR.", [1001] = "divdoRRR.", | ||
64 | |||
65 | [10] = "addcRRR.", [138] = "addeRRR.", | ||
66 | [202] = "addzeRR.", [234] = "addmeRR.", [266] = "addRRR.", | ||
67 | [522] = "addcoRRR.", [650] = "addeoRRR.", | ||
68 | [714] = "addzeoRR.", [746] = "addmeoRR.", [778] = "addoRRR.", | ||
69 | |||
70 | [11] = "mulhwuRRR.", [75] = "mulhwRRR.", [235] = "mullwRRR.", | ||
71 | [459] = "divwuRRR.", [491] = "divwRRR.", | ||
72 | [747] = "mullwoRRR.", | ||
73 | [971] = "divwouRRR.", [1003] = "divwoRRR.", | ||
74 | |||
75 | [15] = "iselltRRR", [47] = "iselgtRRR", [79] = "iseleqRRR", | ||
76 | |||
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", | ||
83 | }, | ||
84 | [467] = { | ||
85 | shift = 11, mask = 1023, | ||
86 | [32] = "mtxerR", [256] = "mtlrR", [288] = "mtctrR", [16] = "mtspefscrR", | ||
87 | }, | ||
88 | |||
89 | [20] = "lwarxRR0R", [84] = "ldarxRR0R", | ||
90 | |||
91 | [21] = "ldxRR0R", [53] = "lduxRRR", | ||
92 | [149] = "stdxRR0R", [181] = "stduxRRR", | ||
93 | [341] = "lwaxRR0R", [373] = "lwauxRRR", | ||
94 | |||
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", | ||
102 | |||
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", | ||
108 | |||
109 | [598] = { | ||
110 | shift = 21, mask = 3, | ||
111 | [0] = "sync", "lwsync", "ptesync", | ||
112 | }, | ||
113 | [758] = "dcba-RR", | ||
114 | [854] = "eieio", [982] = "icbi-R0R", [1014] = "dcbz-R0R", | ||
115 | |||
116 | [26] = "cntlzwRR~", [58] = "cntlzdRR~", | ||
117 | [122] = "popcntbRR~", | ||
118 | [154] = "prtywRR~", [186] = "prtydRR~", | ||
119 | |||
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", | ||
124 | |||
125 | [512] = "mcrxrX", | ||
126 | |||
127 | [532] = "ldbrxRR0R", [660] = "stdbrxRR0R", | ||
128 | |||
129 | [533] = "lswxRR0R", [597] = "lswiRR0A", | ||
130 | [661] = "stswxRR0R", [725] = "stswiRR0A", | ||
131 | |||
132 | [534] = "lwbrxRR0R", [662] = "stwbrxRR0R", | ||
133 | [790] = "lhbrxRR0R", [918] = "sthbrxRR0R", | ||
134 | |||
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", | ||
141 | |||
142 | [24] = "slwRR~R.", | ||
143 | |||
144 | [27] = "sldRR~R.", [536] = "srwRR~R.", | ||
145 | [792] = "srawRR~R.", [824] = "srawiRR~A.", | ||
146 | |||
147 | [794] = "sradRR~R.", [826] = "sradiRR~H.", [827] = "sradiRR~H.", | ||
148 | [922] = "extshRR~.", [954] = "extsbRR~.", [986] = "extswRR~.", | ||
149 | |||
150 | [539] = "srdRR~R.", | ||
151 | }, | ||
152 | { __index = function(t, x) | ||
153 | if band(x, 31) == 15 then return "iselRRRC" end | ||
154 | end | ||
155 | }) | ||
156 | |||
157 | local map_ld = { | ||
158 | shift = 0, mask = 3, | ||
159 | [0] = "ldRRE", "lduRRE", "lwaRRE", | ||
160 | } | ||
161 | |||
162 | local map_std = { | ||
163 | shift = 0, mask = 3, | ||
164 | [0] = "stdRRE", "stduRRE", | ||
165 | } | ||
166 | |||
167 | local map_fps = { | ||
168 | shift = 5, mask = 1, | ||
169 | { | ||
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~.", | ||
175 | } | ||
176 | } | ||
177 | |||
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.", | ||
192 | }, | ||
193 | { | ||
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~.", | ||
199 | } | ||
200 | } | ||
201 | |||
202 | local map_spe = { | ||
203 | shift = 0, mask = 2047, | ||
204 | |||
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", | ||
210 | |||
211 | [527] = "brincRRR", | ||
212 | |||
213 | [529] = "evandRRR", [530] = "evandcRRR", [534] = "evxorRRR", | ||
214 | [535] = "evor|evmrRRR=", [536] = "evnor|evnotRRR=", | ||
215 | [537] = "eveqvRRR", [539] = "evorcRRR", [542] = "evnandRRR", | ||
216 | |||
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", | ||
224 | |||
225 | [560] = "evcmpgtuYRR", [561] = "evcmpgtsYRR", | ||
226 | [562] = "evcmpltuYRR", [563] = "evcmpltsYRR", | ||
227 | [564] = "evcmpeqYRR", | ||
228 | |||
229 | [632] = "evselRRR", [633] = "evselRRRW", | ||
230 | [634] = "evselRRRW", [635] = "evselRRRW", | ||
231 | [636] = "evselRRRW", [637] = "evselRRRW", | ||
232 | [638] = "evselRRRW", [639] = "evselRRRW", | ||
233 | |||
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", | ||
244 | |||
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", | ||
256 | |||
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", | ||
270 | |||
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", | ||
282 | |||
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", | ||
290 | |||
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", | ||
303 | |||
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", | ||
310 | |||
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", | ||
337 | } | ||
338 | |||
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, | ||
356 | } | ||
357 | |||
358 | ------------------------------------------------------------------------------ | ||
359 | |||
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", | ||
365 | } | ||
366 | |||
367 | local map_cond = { [0] = "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", } | ||
368 | |||
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)]) | ||
375 | end | ||
376 | end | ||
377 | |||
378 | ------------------------------------------------------------------------------ | ||
379 | |||
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 | ||
387 | 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)) | ||
394 | end | ||
395 | ctx.pos = pos + 4 | ||
396 | end | ||
397 | |||
398 | -- Fallback for unknown opcodes. | ||
399 | local function unknown(ctx) | ||
400 | return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) | ||
401 | end | ||
402 | |||
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 | ||
413 | |||
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)] | ||
418 | end | ||
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 | ||
422 | |||
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 "+") | ||
469 | end | ||
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 "+") | ||
474 | end | ||
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 "+") | ||
482 | end | ||
483 | if cond > 3 then x = "cr"..rshift(cond, 2) end | ||
484 | 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 | ||
509 | 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 | ||
524 | end | ||
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 | ||
531 | end | ||
532 | elseif p == "-" then | ||
533 | rs = rs - 5 | ||
534 | else | ||
535 | assert(false) | ||
536 | end | ||
537 | if x then operands[#operands+1] = x; last = x end | ||
538 | end | ||
539 | |||
540 | return putop(ctx, name, operands) | ||
541 | end | ||
542 | |||
543 | ------------------------------------------------------------------------------ | ||
544 | |||
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 | ||
553 | end | ||
554 | |||
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 | ||
565 | end | ||
566 | |||
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() | ||
570 | end | ||
571 | |||
572 | |||
573 | -- Public module functions. | ||
574 | module(...) | ||
575 | |||
576 | create = create_ | ||
577 | disass = disass_ | ||
578 | |||