1 ----------------------------------------------------------------------------
2 -- LuaJIT MIPS disassembler module.
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.
9 -- It disassembles all standard MIPS32R1/R2 instructions.
10 -- Default mode is big-endian, but see: dis_mipsel.lua
11 ------------------------------------------------------------------------------
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", }
31 shift
= 21, mask
= 15,
32 [0] = "mfc0TDW", [4] = "mtc0TDW",
34 [11] = { shift
= 5, mask
= 1, [0] = "diT0", "eiT0", },
38 [1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp",
39 [24] = "eret", [31] = "deret",
44 ------------------------------------------------------------------------------
45 -- Primary and extended opcode maps for MIPS R1-R5
46 ------------------------------------------------------------------------------
48 local map_movci
= { shift
= 16, mask
= 1, [0] = "movfDSC", "movtDSC", }
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
= {
73 [0] = "maddST", "madduST", "mulDST", false,
75 [32] = "clzDS", [33] = "cloDS",
92 local map_special3
= {
94 [0] = "extTSAK", [1] = "dextmTSAP", [3] = "dextTSAK",
95 [4] = "insTSAL", [6] = "dinsuTSEQ", [7] = "dinsTSAL",
96 [32] = map_bshfl
, [36] = map_dbshfl
, [59] = "rdhwrTD",
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",
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",
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",
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",
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",
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,
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",
178 shift
= 0, mask
= 63,
179 [32] = "cvt.s.wFG", [33] = "cvt.d.wFG",
183 shift
= 0, mask
= 63,
184 [32] = "cvt.s.lFG", [33] = "cvt.d.lFG",
188 shift
= 16, mask
= 3,
189 [0] = "bc1fCB", "bc1tCB", "bc1flCB", "bc1tlCB",
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
,
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,
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
= {
279 shift
= 6, mask
= 31,
287 local map_dbshfl_r6
= {
291 shift
= 6, mask
= 31,
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"
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 ------------------------------------------------------------------------------
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
)
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
))
466 ctx
.out(format("%08x %-7s %s%s\n",
467 ctx
.addr
+pos
, text
, concat(operands
, ", "), extra
))
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
)
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
)
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
)
497 local opat
= ctx
.map_pri
[rshift(op
, 26)]
498 while type(opat
) ~= "string" do
499 if not opat
then return unknown(ctx
) end
501 opat
= opat
[opat
.maprs(band(rshift(op
,21),31), band(rshift(op
,16),31))]
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
513 x
= map_gpr
[band(rshift(op
, 21), 31)]
515 x
= map_gpr
[band(rshift(op
, 16), 31)]
517 x
= map_gpr
[band(rshift(op
, 11), 31)]
519 x
= "f"..band(rshift(op
, 6), 31)
521 x
= "f"..band(rshift(op
, 11), 31)
523 x
= "f"..band(rshift(op
, 16), 31)
525 x
= "f"..band(rshift(op
, 21), 31)
527 x
= band(rshift(op
, 6), 31)
529 x
= band(rshift(op
, 6), 7)
531 x
= band(rshift(op
, 6), 31) + 32
533 x
= band(rshift(op
, 11), 31)
535 x
= band(rshift(op
, 16), 31)
537 x
= band(rshift(op
, 18), 7)
538 if x
== 0 then x
= nil end
540 x
= band(rshift(op
, 11), 31) + 1
542 x
= band(rshift(op
, 11), 31) + 33
544 x
= band(rshift(op
, 11), 31) - last
+ 1
546 x
= band(rshift(op
, 11), 31) - last
+ 33
548 x
= arshift(lshift(op
, 16), 16)
550 x
= arshift(lshift(op
, 13), 11)
552 x
= arshift(lshift(op
, 14), 11)
556 local disp
= arshift(lshift(op
, 16), 16)
557 operands
[#operands
] = format("%d(%s)", disp
, last
)
559 local index
= map_gpr
[band(rshift(op
, 16), 31)]
560 operands
[#operands
] = format("%s(%s)", index
, last
)
562 x
= ctx
.addr
+ ctx
.pos
+ arshift(lshift(op
, 16), 14) + 4
564 x
= format("0x%08x", x
)
566 x
= ctx
.addr
+ ctx
.pos
+ arshift(lshift(op
, 11), 9) + 4
568 x
= format("0x%08x", x
)
570 x
= ctx
.addr
+ ctx
.pos
+ arshift(lshift(op
, 6), 4) + 4
572 x
= format("0x%08x", x
)
574 local a
= ctx
.addr
+ ctx
.pos
575 x
= a
- band(a
, 0x0fffffff) + band(op
, 0x03ffffff)*4
577 x
= format("0x%08x", x
)
579 x
= band(rshift(op
, 8), 7)
580 if x
== 0 then x
= nil end
583 if x
== 0 then x
= nil end
585 x
= band(rshift(op
, 6), 0x000fffff)
586 if x
== 0 then x
= nil end
588 x
= band(rshift(op
, 6), 1023)
589 if x
== 0 then x
= nil end
591 if last
== "r0" or last
== 0 then
596 local a1
, a2
= match(altname
, "([^|]*)|(.*)")
597 if a1
then name
, altname
= a1
, a2
598 else name
= altname
end
603 operands
[#operands
] = nil
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
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
)
631 ctx
.out
= out
or io
.write
633 ctx
.disass
= disass_block
636 ctx
.map_pri
= map_pri
640 local function create_el(code
, addr
, out
)
641 local ctx
= create(code
, addr
, out
)
646 local function create_r6(code
, addr
, out
)
647 local ctx
= create(code
, addr
, out
)
648 ctx
.map_pri
= map_pri_r6
652 local function create_r6_el(code
, addr
, out
)
653 local ctx
= create(code
, addr
, out
)
655 ctx
.map_pri
= map_pri_r6
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
682 -- Public module functions.
685 create_el
= create_el
,
686 create_r6
= create_r6
,
687 create_r6_el
= create_r6_el
,
689 disass_el
= disass_el
,
690 disass_r6
= disass_r6
,
691 disass_r6_el
= disass_r6_el
,