OSX/iOS: Fix SDK incompatibility.
[luajit-2.0.git] / src / jit / dis_mips.lua
blobb0e99df4225e7bc104fbc0be9e9e163337303204
1 ----------------------------------------------------------------------------
2 -- LuaJIT MIPS disassembler module.
3 --
4 -- Copyright (C) 2005-2023 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 standard MIPS32R1/R2 instructions.
10 -- Default mode is big-endian, but see: dis_mipsel.lua
11 ------------------------------------------------------------------------------
13 local type = type
14 local byte, format = string.byte, string.format
15 local match, gmatch = string.match, string.gmatch
16 local concat = table.concat
17 local bit = require("bit")
18 local band, bor, tohex = bit.band, bit.bor, bit.tohex
19 local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
21 ------------------------------------------------------------------------------
22 -- Extended opcode maps common to all MIPS releases
23 ------------------------------------------------------------------------------
25 local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", }
26 local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", }
28 local map_cop0 = {
29 shift = 25, mask = 1,
30 [0] = {
31 shift = 21, mask = 15,
32 [0] = "mfc0TDW", [4] = "mtc0TDW",
33 [10] = "rdpgprDT",
34 [11] = { shift = 5, mask = 1, [0] = "diT0", "eiT0", },
35 [14] = "wrpgprDT",
36 }, {
37 shift = 0, mask = 63,
38 [1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp",
39 [24] = "eret", [31] = "deret",
40 [32] = "wait",
44 ------------------------------------------------------------------------------
45 -- Primary and extended opcode maps for MIPS R1-R5
46 ------------------------------------------------------------------------------
48 local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", }
50 local map_special = {
51 shift = 0, mask = 63,
52 [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
53 map_movci, map_srl, "sraDTA",
54 "sllvDTS", false, map_srlv, "sravDTS",
55 "jrS", "jalrD1S", "movzDST", "movnDST",
56 "syscallY", "breakY", false, "sync",
57 "mfhiD", "mthiS", "mfloD", "mtloS",
58 "dsllvDST", false, "dsrlvDST", "dsravDST",
59 "multST", "multuST", "divST", "divuST",
60 "dmultST", "dmultuST", "ddivST", "ddivuST",
61 "addDST", "addu|moveDST0", "subDST", "subu|neguDS0T",
62 "andDST", "or|moveDST0", "xorDST", "nor|notDST0",
63 false, false, "sltDST", "sltuDST",
64 "daddDST", "dadduDST", "dsubDST", "dsubuDST",
65 "tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ",
66 "teqSTZ", false, "tneSTZ", false,
67 "dsllDTA", false, "dsrlDTA", "dsraDTA",
68 "dsll32DTA", false, "dsrl32DTA", "dsra32DTA",
71 local map_special2 = {
72 shift = 0, mask = 63,
73 [0] = "maddST", "madduST", "mulDST", false,
74 "msubST", "msubuST",
75 [32] = "clzDS", [33] = "cloDS",
76 [63] = "sdbbpY",
79 local map_bshfl = {
80 shift = 6, mask = 31,
81 [2] = "wsbhDT",
82 [16] = "sebDT",
83 [24] = "sehDT",
86 local map_dbshfl = {
87 shift = 6, mask = 31,
88 [2] = "dsbhDT",
89 [5] = "dshdDT",
92 local map_special3 = {
93 shift = 0, mask = 63,
94 [0] = "extTSAK", [1] = "dextmTSAP", [3] = "dextTSAK",
95 [4] = "insTSAL", [6] = "dinsuTSEQ", [7] = "dinsTSAL",
96 [32] = map_bshfl, [36] = map_dbshfl, [59] = "rdhwrTD",
99 local map_regimm = {
100 shift = 16, mask = 31,
101 [0] = "bltzSB", "bgezSB", "bltzlSB", "bgezlSB",
102 false, false, false, false,
103 "tgeiSI", "tgeiuSI", "tltiSI", "tltiuSI",
104 "teqiSI", false, "tneiSI", false,
105 "bltzalSB", "bgezalSB", "bltzallSB", "bgezallSB",
106 false, false, false, false,
107 false, false, false, false,
108 false, false, false, "synciSO",
111 local map_cop1s = {
112 shift = 0, mask = 63,
113 [0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH",
114 "sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG",
115 "round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG",
116 "round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG",
117 false,
118 { shift = 16, mask = 1, [0] = "movf.sFGC", "movt.sFGC" },
119 "movz.sFGT", "movn.sFGT",
120 false, "recip.sFG", "rsqrt.sFG", false,
121 false, false, false, false,
122 false, false, false, false,
123 false, "cvt.d.sFG", false, false,
124 "cvt.w.sFG", "cvt.l.sFG", "cvt.ps.sFGH", false,
125 false, false, false, false,
126 false, false, false, false,
127 "c.f.sVGH", "c.un.sVGH", "c.eq.sVGH", "c.ueq.sVGH",
128 "c.olt.sVGH", "c.ult.sVGH", "c.ole.sVGH", "c.ule.sVGH",
129 "c.sf.sVGH", "c.ngle.sVGH", "c.seq.sVGH", "c.ngl.sVGH",
130 "c.lt.sVGH", "c.nge.sVGH", "c.le.sVGH", "c.ngt.sVGH",
133 local map_cop1d = {
134 shift = 0, mask = 63,
135 [0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH",
136 "sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG",
137 "round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG",
138 "round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG",
139 false,
140 { shift = 16, mask = 1, [0] = "movf.dFGC", "movt.dFGC" },
141 "movz.dFGT", "movn.dFGT",
142 false, "recip.dFG", "rsqrt.dFG", false,
143 false, false, false, false,
144 false, false, false, false,
145 "cvt.s.dFG", false, false, false,
146 "cvt.w.dFG", "cvt.l.dFG", false, false,
147 false, false, false, false,
148 false, false, false, false,
149 "c.f.dVGH", "c.un.dVGH", "c.eq.dVGH", "c.ueq.dVGH",
150 "c.olt.dVGH", "c.ult.dVGH", "c.ole.dVGH", "c.ule.dVGH",
151 "c.df.dVGH", "c.ngle.dVGH", "c.deq.dVGH", "c.ngl.dVGH",
152 "c.lt.dVGH", "c.nge.dVGH", "c.le.dVGH", "c.ngt.dVGH",
155 local map_cop1ps = {
156 shift = 0, mask = 63,
157 [0] = "add.psFGH", "sub.psFGH", "mul.psFGH", false,
158 false, "abs.psFG", "mov.psFG", "neg.psFG",
159 false, false, false, false,
160 false, false, false, false,
161 false,
162 { shift = 16, mask = 1, [0] = "movf.psFGC", "movt.psFGC" },
163 "movz.psFGT", "movn.psFGT",
164 false, false, false, false,
165 false, false, false, false,
166 false, false, false, false,
167 "cvt.s.puFG", false, false, false,
168 false, false, false, false,
169 "cvt.s.plFG", false, false, false,
170 "pll.psFGH", "plu.psFGH", "pul.psFGH", "puu.psFGH",
171 "c.f.psVGH", "c.un.psVGH", "c.eq.psVGH", "c.ueq.psVGH",
172 "c.olt.psVGH", "c.ult.psVGH", "c.ole.psVGH", "c.ule.psVGH",
173 "c.psf.psVGH", "c.ngle.psVGH", "c.pseq.psVGH", "c.ngl.psVGH",
174 "c.lt.psVGH", "c.nge.psVGH", "c.le.psVGH", "c.ngt.psVGH",
177 local map_cop1w = {
178 shift = 0, mask = 63,
179 [32] = "cvt.s.wFG", [33] = "cvt.d.wFG",
182 local map_cop1l = {
183 shift = 0, mask = 63,
184 [32] = "cvt.s.lFG", [33] = "cvt.d.lFG",
187 local map_cop1bc = {
188 shift = 16, mask = 3,
189 [0] = "bc1fCB", "bc1tCB", "bc1flCB", "bc1tlCB",
192 local map_cop1 = {
193 shift = 21, mask = 31,
194 [0] = "mfc1TG", "dmfc1TG", "cfc1TG", "mfhc1TG",
195 "mtc1TG", "dmtc1TG", "ctc1TG", "mthc1TG",
196 map_cop1bc, false, false, false,
197 false, false, false, false,
198 map_cop1s, map_cop1d, false, false,
199 map_cop1w, map_cop1l, map_cop1ps,
202 local map_cop1x = {
203 shift = 0, mask = 63,
204 [0] = "lwxc1FSX", "ldxc1FSX", false, false,
205 false, "luxc1FSX", false, false,
206 "swxc1FSX", "sdxc1FSX", false, false,
207 false, "suxc1FSX", false, "prefxMSX",
208 false, false, false, false,
209 false, false, false, false,
210 false, false, false, false,
211 false, false, "alnv.psFGHS", false,
212 "madd.sFRGH", "madd.dFRGH", false, false,
213 false, false, "madd.psFRGH", false,
214 "msub.sFRGH", "msub.dFRGH", false, false,
215 false, false, "msub.psFRGH", false,
216 "nmadd.sFRGH", "nmadd.dFRGH", false, false,
217 false, false, "nmadd.psFRGH", false,
218 "nmsub.sFRGH", "nmsub.dFRGH", false, false,
219 false, false, "nmsub.psFRGH", false,
222 local map_pri = {
223 [0] = map_special, map_regimm, "jJ", "jalJ",
224 "beq|beqz|bST00B", "bne|bnezST0B", "blezSB", "bgtzSB",
225 "addiTSI", "addiu|liTS0I", "sltiTSI", "sltiuTSI",
226 "andiTSU", "ori|liTS0U", "xoriTSU", "luiTU",
227 map_cop0, map_cop1, false, map_cop1x,
228 "beql|beqzlST0B", "bnel|bnezlST0B", "blezlSB", "bgtzlSB",
229 "daddiTSI", "daddiuTSI", false, false,
230 map_special2, "jalxJ", false, map_special3,
231 "lbTSO", "lhTSO", "lwlTSO", "lwTSO",
232 "lbuTSO", "lhuTSO", "lwrTSO", false,
233 "sbTSO", "shTSO", "swlTSO", "swTSO",
234 false, false, "swrTSO", "cacheNSO",
235 "llTSO", "lwc1HSO", "lwc2TSO", "prefNSO",
236 false, "ldc1HSO", "ldc2TSO", "ldTSO",
237 "scTSO", "swc1HSO", "swc2TSO", false,
238 false, "sdc1HSO", "sdc2TSO", "sdTSO",
241 ------------------------------------------------------------------------------
242 -- Primary and extended opcode maps for MIPS R6
243 ------------------------------------------------------------------------------
245 local map_mul_r6 = { shift = 6, mask = 3, [2] = "mulDST", [3] = "muhDST" }
246 local map_mulu_r6 = { shift = 6, mask = 3, [2] = "muluDST", [3] = "muhuDST" }
247 local map_div_r6 = { shift = 6, mask = 3, [2] = "divDST", [3] = "modDST" }
248 local map_divu_r6 = { shift = 6, mask = 3, [2] = "divuDST", [3] = "moduDST" }
249 local map_dmul_r6 = { shift = 6, mask = 3, [2] = "dmulDST", [3] = "dmuhDST" }
250 local map_dmulu_r6 = { shift = 6, mask = 3, [2] = "dmuluDST", [3] = "dmuhuDST" }
251 local map_ddiv_r6 = { shift = 6, mask = 3, [2] = "ddivDST", [3] = "dmodDST" }
252 local map_ddivu_r6 = { shift = 6, mask = 3, [2] = "ddivuDST", [3] = "dmoduDST" }
254 local map_special_r6 = {
255 shift = 0, mask = 63,
256 [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
257 false, map_srl, "sraDTA",
258 "sllvDTS", false, map_srlv, "sravDTS",
259 "jrS", "jalrD1S", false, false,
260 "syscallY", "breakY", false, "sync",
261 "clzDS", "cloDS", "dclzDS", "dcloDS",
262 "dsllvDST", "dlsaDSTA", "dsrlvDST", "dsravDST",
263 map_mul_r6, map_mulu_r6, map_div_r6, map_divu_r6,
264 map_dmul_r6, map_dmulu_r6, map_ddiv_r6, map_ddivu_r6,
265 "addDST", "addu|moveDST0", "subDST", "subu|neguDS0T",
266 "andDST", "or|moveDST0", "xorDST", "nor|notDST0",
267 false, false, "sltDST", "sltuDST",
268 "daddDST", "dadduDST", "dsubDST", "dsubuDST",
269 "tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ",
270 "teqSTZ", "seleqzDST", "tneSTZ", "selnezDST",
271 "dsllDTA", false, "dsrlDTA", "dsraDTA",
272 "dsll32DTA", false, "dsrl32DTA", "dsra32DTA",
275 local map_bshfl_r6 = {
276 shift = 9, mask = 3,
277 [1] = "alignDSTa",
278 _ = {
279 shift = 6, mask = 31,
280 [0] = "bitswapDT",
281 [2] = "wsbhDT",
282 [16] = "sebDT",
283 [24] = "sehDT",
287 local map_dbshfl_r6 = {
288 shift = 9, mask = 3,
289 [1] = "dalignDSTa",
290 _ = {
291 shift = 6, mask = 31,
292 [0] = "dbitswapDT",
293 [2] = "dsbhDT",
294 [5] = "dshdDT",
298 local map_special3_r6 = {
299 shift = 0, mask = 63,
300 [0] = "extTSAK", [1] = "dextmTSAP", [3] = "dextTSAK",
301 [4] = "insTSAL", [6] = "dinsuTSEQ", [7] = "dinsTSAL",
302 [32] = map_bshfl_r6, [36] = map_dbshfl_r6, [59] = "rdhwrTD",
305 local map_regimm_r6 = {
306 shift = 16, mask = 31,
307 [0] = "bltzSB", [1] = "bgezSB",
308 [6] = "dahiSI", [30] = "datiSI",
309 [23] = "sigrieI", [31] = "synciSO",
312 local map_pcrel_r6 = {
313 shift = 19, mask = 3,
314 [0] = "addiupcS2", "lwpcS2", "lwupcS2", {
315 shift = 18, mask = 1,
316 [0] = "ldpcS3", { shift = 16, mask = 3, [2] = "auipcSI", [3] = "aluipcSI" }
320 local map_cop1s_r6 = {
321 shift = 0, mask = 63,
322 [0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH",
323 "sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG",
324 "round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG",
325 "round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG",
326 "sel.sFGH", false, false, false,
327 "seleqz.sFGH", "recip.sFG", "rsqrt.sFG", "selnez.sFGH",
328 "maddf.sFGH", "msubf.sFGH", "rint.sFG", "class.sFG",
329 "min.sFGH", "mina.sFGH", "max.sFGH", "maxa.sFGH",
330 false, "cvt.d.sFG", false, false,
331 "cvt.w.sFG", "cvt.l.sFG",
334 local map_cop1d_r6 = {
335 shift = 0, mask = 63,
336 [0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH",
337 "sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG",
338 "round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG",
339 "round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG",
340 "sel.dFGH", false, false, false,
341 "seleqz.dFGH", "recip.dFG", "rsqrt.dFG", "selnez.dFGH",
342 "maddf.dFGH", "msubf.dFGH", "rint.dFG", "class.dFG",
343 "min.dFGH", "mina.dFGH", "max.dFGH", "maxa.dFGH",
344 "cvt.s.dFG", false, false, false,
345 "cvt.w.dFG", "cvt.l.dFG",
348 local map_cop1w_r6 = {
349 shift = 0, mask = 63,
350 [0] = "cmp.af.sFGH", "cmp.un.sFGH", "cmp.eq.sFGH", "cmp.ueq.sFGH",
351 "cmp.lt.sFGH", "cmp.ult.sFGH", "cmp.le.sFGH", "cmp.ule.sFGH",
352 "cmp.saf.sFGH", "cmp.sun.sFGH", "cmp.seq.sFGH", "cmp.sueq.sFGH",
353 "cmp.slt.sFGH", "cmp.sult.sFGH", "cmp.sle.sFGH", "cmp.sule.sFGH",
354 false, "cmp.or.sFGH", "cmp.une.sFGH", "cmp.ne.sFGH",
355 false, false, false, false,
356 false, "cmp.sor.sFGH", "cmp.sune.sFGH", "cmp.sne.sFGH",
357 false, false, false, false,
358 "cvt.s.wFG", "cvt.d.wFG",
361 local map_cop1l_r6 = {
362 shift = 0, mask = 63,
363 [0] = "cmp.af.dFGH", "cmp.un.dFGH", "cmp.eq.dFGH", "cmp.ueq.dFGH",
364 "cmp.lt.dFGH", "cmp.ult.dFGH", "cmp.le.dFGH", "cmp.ule.dFGH",
365 "cmp.saf.dFGH", "cmp.sun.dFGH", "cmp.seq.dFGH", "cmp.sueq.dFGH",
366 "cmp.slt.dFGH", "cmp.sult.dFGH", "cmp.sle.dFGH", "cmp.sule.dFGH",
367 false, "cmp.or.dFGH", "cmp.une.dFGH", "cmp.ne.dFGH",
368 false, false, false, false,
369 false, "cmp.sor.dFGH", "cmp.sune.dFGH", "cmp.sne.dFGH",
370 false, false, false, false,
371 "cvt.s.lFG", "cvt.d.lFG",
374 local map_cop1_r6 = {
375 shift = 21, mask = 31,
376 [0] = "mfc1TG", "dmfc1TG", "cfc1TG", "mfhc1TG",
377 "mtc1TG", "dmtc1TG", "ctc1TG", "mthc1TG",
378 false, "bc1eqzHB", false, false,
379 false, "bc1nezHB", false, false,
380 map_cop1s_r6, map_cop1d_r6, false, false,
381 map_cop1w_r6, map_cop1l_r6,
384 local function maprs_popTS(rs, rt)
385 if rt == 0 then return 0 elseif rs == 0 then return 1
386 elseif rs == rt then return 2 else return 3 end
389 local map_pop06_r6 = {
390 maprs = maprs_popTS, [0] = "blezSB", "blezalcTB", "bgezalcTB", "bgeucSTB"
392 local map_pop07_r6 = {
393 maprs = maprs_popTS, [0] = "bgtzSB", "bgtzalcTB", "bltzalcTB", "bltucSTB"
395 local map_pop26_r6 = {
396 maprs = maprs_popTS, "blezcTB", "bgezcTB", "bgecSTB"
398 local map_pop27_r6 = {
399 maprs = maprs_popTS, "bgtzcTB", "bltzcTB", "bltcSTB"
402 local function maprs_popS(rs, rt)
403 if rs == 0 then return 0 else return 1 end
406 local map_pop66_r6 = {
407 maprs = maprs_popS, [0] = "jicTI", "beqzcSb"
409 local map_pop76_r6 = {
410 maprs = maprs_popS, [0] = "jialcTI", "bnezcSb"
413 local function maprs_popST(rs, rt)
414 if rs >= rt then return 0 elseif rs == 0 then return 1 else return 2 end
417 local map_pop10_r6 = {
418 maprs = maprs_popST, [0] = "bovcSTB", "beqzalcTB", "beqcSTB"
420 local map_pop30_r6 = {
421 maprs = maprs_popST, [0] = "bnvcSTB", "bnezalcTB", "bnecSTB"
424 local map_pri_r6 = {
425 [0] = map_special_r6, map_regimm_r6, "jJ", "jalJ",
426 "beq|beqz|bST00B", "bne|bnezST0B", map_pop06_r6, map_pop07_r6,
427 map_pop10_r6, "addiu|liTS0I", "sltiTSI", "sltiuTSI",
428 "andiTSU", "ori|liTS0U", "xoriTSU", "aui|luiTS0U",
429 map_cop0, map_cop1_r6, false, false,
430 false, false, map_pop26_r6, map_pop27_r6,
431 map_pop30_r6, "daddiuTSI", false, false,
432 false, "dauiTSI", false, map_special3_r6,
433 "lbTSO", "lhTSO", false, "lwTSO",
434 "lbuTSO", "lhuTSO", false, false,
435 "sbTSO", "shTSO", false, "swTSO",
436 false, false, false, false,
437 false, "lwc1HSO", "bc#", false,
438 false, "ldc1HSO", map_pop66_r6, "ldTSO",
439 false, "swc1HSO", "balc#", map_pcrel_r6,
440 false, "sdc1HSO", map_pop76_r6, "sdTSO",
443 ------------------------------------------------------------------------------
445 local map_gpr = {
446 [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
447 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
448 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
449 "r24", "r25", "r26", "r27", "r28", "sp", "r30", "ra",
452 ------------------------------------------------------------------------------
454 -- Output a nicely formatted line with an opcode and operands.
455 local function putop(ctx, text, operands)
456 local pos = ctx.pos
457 local extra = ""
458 if ctx.rel then
459 local sym = ctx.symtab[ctx.rel]
460 if sym then extra = "\t->"..sym end
462 if ctx.hexdump > 0 then
463 ctx.out(format("%08x %s %-7s %s%s\n",
464 ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
465 else
466 ctx.out(format("%08x %-7s %s%s\n",
467 ctx.addr+pos, text, concat(operands, ", "), extra))
469 ctx.pos = pos + 4
472 -- Fallback for unknown opcodes.
473 local function unknown(ctx)
474 return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
477 local function get_be(ctx)
478 local pos = ctx.pos
479 local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
480 return bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3)
483 local function get_le(ctx)
484 local pos = ctx.pos
485 local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
486 return bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
489 -- Disassemble a single instruction.
490 local function disass_ins(ctx)
491 local op = ctx:get()
492 local operands = {}
493 local last = nil
494 ctx.op = op
495 ctx.rel = nil
497 local opat = ctx.map_pri[rshift(op, 26)]
498 while type(opat) ~= "string" do
499 if not opat then return unknown(ctx) end
500 if opat.maprs then
501 opat = opat[opat.maprs(band(rshift(op,21),31), band(rshift(op,16),31))]
502 else
503 opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
506 local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
507 local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)")
508 if altname then pat = pat2 end
510 for p in gmatch(pat, ".") do
511 local x = nil
512 if p == "S" then
513 x = map_gpr[band(rshift(op, 21), 31)]
514 elseif p == "T" then
515 x = map_gpr[band(rshift(op, 16), 31)]
516 elseif p == "D" then
517 x = map_gpr[band(rshift(op, 11), 31)]
518 elseif p == "F" then
519 x = "f"..band(rshift(op, 6), 31)
520 elseif p == "G" then
521 x = "f"..band(rshift(op, 11), 31)
522 elseif p == "H" then
523 x = "f"..band(rshift(op, 16), 31)
524 elseif p == "R" then
525 x = "f"..band(rshift(op, 21), 31)
526 elseif p == "A" then
527 x = band(rshift(op, 6), 31)
528 elseif p == "a" then
529 x = band(rshift(op, 6), 7)
530 elseif p == "E" then
531 x = band(rshift(op, 6), 31) + 32
532 elseif p == "M" then
533 x = band(rshift(op, 11), 31)
534 elseif p == "N" then
535 x = band(rshift(op, 16), 31)
536 elseif p == "C" then
537 x = band(rshift(op, 18), 7)
538 if x == 0 then x = nil end
539 elseif p == "K" then
540 x = band(rshift(op, 11), 31) + 1
541 elseif p == "P" then
542 x = band(rshift(op, 11), 31) + 33
543 elseif p == "L" then
544 x = band(rshift(op, 11), 31) - last + 1
545 elseif p == "Q" then
546 x = band(rshift(op, 11), 31) - last + 33
547 elseif p == "I" then
548 x = arshift(lshift(op, 16), 16)
549 elseif p == "2" then
550 x = arshift(lshift(op, 13), 11)
551 elseif p == "3" then
552 x = arshift(lshift(op, 14), 11)
553 elseif p == "U" then
554 x = band(op, 0xffff)
555 elseif p == "O" then
556 local disp = arshift(lshift(op, 16), 16)
557 operands[#operands] = format("%d(%s)", disp, last)
558 elseif p == "X" then
559 local index = map_gpr[band(rshift(op, 16), 31)]
560 operands[#operands] = format("%s(%s)", index, last)
561 elseif p == "B" then
562 x = ctx.addr + ctx.pos + arshift(lshift(op, 16), 14) + 4
563 ctx.rel = x
564 x = format("0x%08x", x)
565 elseif p == "b" then
566 x = ctx.addr + ctx.pos + arshift(lshift(op, 11), 9) + 4
567 ctx.rel = x
568 x = format("0x%08x", x)
569 elseif p == "#" then
570 x = ctx.addr + ctx.pos + arshift(lshift(op, 6), 4) + 4
571 ctx.rel = x
572 x = format("0x%08x", x)
573 elseif p == "J" then
574 local a = ctx.addr + ctx.pos
575 x = a - band(a, 0x0fffffff) + band(op, 0x03ffffff)*4
576 ctx.rel = x
577 x = format("0x%08x", x)
578 elseif p == "V" then
579 x = band(rshift(op, 8), 7)
580 if x == 0 then x = nil end
581 elseif p == "W" then
582 x = band(op, 7)
583 if x == 0 then x = nil end
584 elseif p == "Y" then
585 x = band(rshift(op, 6), 0x000fffff)
586 if x == 0 then x = nil end
587 elseif p == "Z" then
588 x = band(rshift(op, 6), 1023)
589 if x == 0 then x = nil end
590 elseif p == "0" then
591 if last == "r0" or last == 0 then
592 local n = #operands
593 operands[n] = nil
594 last = operands[n-1]
595 if altname then
596 local a1, a2 = match(altname, "([^|]*)|(.*)")
597 if a1 then name, altname = a1, a2
598 else name = altname end
601 elseif p == "1" then
602 if last == "ra" then
603 operands[#operands] = nil
605 else
606 assert(false)
608 if x then operands[#operands+1] = x; last = x end
611 return putop(ctx, name, operands)
614 ------------------------------------------------------------------------------
616 -- Disassemble a block of code.
617 local function disass_block(ctx, ofs, len)
618 if not ofs then ofs = 0 end
619 local stop = len and ofs+len or #ctx.code
620 stop = stop - stop % 4
621 ctx.pos = ofs - ofs % 4
622 ctx.rel = nil
623 while ctx.pos < stop do disass_ins(ctx) end
626 -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
627 local function create(code, addr, out)
628 local ctx = {}
629 ctx.code = code
630 ctx.addr = addr or 0
631 ctx.out = out or io.write
632 ctx.symtab = {}
633 ctx.disass = disass_block
634 ctx.hexdump = 8
635 ctx.get = get_be
636 ctx.map_pri = map_pri
637 return ctx
640 local function create_el(code, addr, out)
641 local ctx = create(code, addr, out)
642 ctx.get = get_le
643 return ctx
646 local function create_r6(code, addr, out)
647 local ctx = create(code, addr, out)
648 ctx.map_pri = map_pri_r6
649 return ctx
652 local function create_r6_el(code, addr, out)
653 local ctx = create(code, addr, out)
654 ctx.get = get_le
655 ctx.map_pri = map_pri_r6
656 return ctx
659 -- Simple API: disassemble code (a string) at address and output via out.
660 local function disass(code, addr, out)
661 create(code, addr, out):disass()
664 local function disass_el(code, addr, out)
665 create_el(code, addr, out):disass()
668 local function disass_r6(code, addr, out)
669 create_r6(code, addr, out):disass()
672 local function disass_r6_el(code, addr, out)
673 create_r6_el(code, addr, out):disass()
676 -- Return register name for RID.
677 local function regname(r)
678 if r < 32 then return map_gpr[r] end
679 return "f"..(r-32)
682 -- Public module functions.
683 return {
684 create = create,
685 create_el = create_el,
686 create_r6 = create_r6,
687 create_r6_el = create_r6_el,
688 disass = disass,
689 disass_el = disass_el,
690 disass_r6 = disass_r6,
691 disass_r6_el = disass_r6_el,
692 regname = regname