Mercurial
comparison third_party/luajit/src/jit/dis_mips.lua @ 178:94705b5986b3
[ThirdParty] Added WRK and luajit for load testing.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Thu, 22 Jan 2026 20:10:30 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 177:24fe8ff94056 | 178:94705b5986b3 |
|---|---|
| 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 ------------------------------------------------------------------------------ | |
| 12 | |
| 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 | |
| 20 | |
| 21 ------------------------------------------------------------------------------ | |
| 22 -- Extended opcode maps common to all MIPS releases | |
| 23 ------------------------------------------------------------------------------ | |
| 24 | |
| 25 local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", } | |
| 26 local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", } | |
| 27 | |
| 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", | |
| 41 }, | |
| 42 } | |
| 43 | |
| 44 ------------------------------------------------------------------------------ | |
| 45 -- Primary and extended opcode maps for MIPS R1-R5 | |
| 46 ------------------------------------------------------------------------------ | |
| 47 | |
| 48 local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", } | |
| 49 | |
| 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", | |
| 69 } | |
| 70 | |
| 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", | |
| 77 } | |
| 78 | |
| 79 local map_bshfl = { | |
| 80 shift = 6, mask = 31, | |
| 81 [2] = "wsbhDT", | |
| 82 [16] = "sebDT", | |
| 83 [24] = "sehDT", | |
| 84 } | |
| 85 | |
| 86 local map_dbshfl = { | |
| 87 shift = 6, mask = 31, | |
| 88 [2] = "dsbhDT", | |
| 89 [5] = "dshdDT", | |
| 90 } | |
| 91 | |
| 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", | |
| 97 } | |
| 98 | |
| 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", | |
| 109 } | |
| 110 | |
| 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", | |
| 131 } | |
| 132 | |
| 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", | |
| 153 } | |
| 154 | |
| 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", | |
| 175 } | |
| 176 | |
| 177 local map_cop1w = { | |
| 178 shift = 0, mask = 63, | |
| 179 [32] = "cvt.s.wFG", [33] = "cvt.d.wFG", | |
| 180 } | |
| 181 | |
| 182 local map_cop1l = { | |
| 183 shift = 0, mask = 63, | |
| 184 [32] = "cvt.s.lFG", [33] = "cvt.d.lFG", | |
| 185 } | |
| 186 | |
| 187 local map_cop1bc = { | |
| 188 shift = 16, mask = 3, | |
| 189 [0] = "bc1fCB", "bc1tCB", "bc1flCB", "bc1tlCB", | |
| 190 } | |
| 191 | |
| 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, | |
| 200 } | |
| 201 | |
| 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, | |
| 220 } | |
| 221 | |
| 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", | |
| 239 } | |
| 240 | |
| 241 ------------------------------------------------------------------------------ | |
| 242 -- Primary and extended opcode maps for MIPS R6 | |
| 243 ------------------------------------------------------------------------------ | |
| 244 | |
| 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" } | |
| 253 | |
| 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", | |
| 273 } | |
| 274 | |
| 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", | |
| 284 } | |
| 285 } | |
| 286 | |
| 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", | |
| 295 } | |
| 296 } | |
| 297 | |
| 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", | |
| 303 } | |
| 304 | |
| 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", | |
| 310 } | |
| 311 | |
| 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" } | |
| 317 } | |
| 318 } | |
| 319 | |
| 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", | |
| 332 } | |
| 333 | |
| 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", | |
| 346 } | |
| 347 | |
| 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", | |
| 359 } | |
| 360 | |
| 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", | |
| 372 } | |
| 373 | |
| 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, | |
| 382 } | |
| 383 | |
| 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 | |
| 387 end | |
| 388 | |
| 389 local map_pop06_r6 = { | |
| 390 maprs = maprs_popTS, [0] = "blezSB", "blezalcTB", "bgezalcTB", "bgeucSTB" | |
| 391 } | |
| 392 local map_pop07_r6 = { | |
| 393 maprs = maprs_popTS, [0] = "bgtzSB", "bgtzalcTB", "bltzalcTB", "bltucSTB" | |
| 394 } | |
| 395 local map_pop26_r6 = { | |
| 396 maprs = maprs_popTS, "blezcTB", "bgezcTB", "bgecSTB" | |
| 397 } | |
| 398 local map_pop27_r6 = { | |
| 399 maprs = maprs_popTS, "bgtzcTB", "bltzcTB", "bltcSTB" | |
| 400 } | |
| 401 | |
| 402 local function maprs_popS(rs, rt) | |
| 403 if rs == 0 then return 0 else return 1 end | |
| 404 end | |
| 405 | |
| 406 local map_pop66_r6 = { | |
| 407 maprs = maprs_popS, [0] = "jicTI", "beqzcSb" | |
| 408 } | |
| 409 local map_pop76_r6 = { | |
| 410 maprs = maprs_popS, [0] = "jialcTI", "bnezcSb" | |
| 411 } | |
| 412 | |
| 413 local function maprs_popST(rs, rt) | |
| 414 if rs >= rt then return 0 elseif rs == 0 then return 1 else return 2 end | |
| 415 end | |
| 416 | |
| 417 local map_pop10_r6 = { | |
| 418 maprs = maprs_popST, [0] = "bovcSTB", "beqzalcTB", "beqcSTB" | |
| 419 } | |
| 420 local map_pop30_r6 = { | |
| 421 maprs = maprs_popST, [0] = "bnvcSTB", "bnezalcTB", "bnecSTB" | |
| 422 } | |
| 423 | |
| 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", | |
| 441 } | |
| 442 | |
| 443 ------------------------------------------------------------------------------ | |
| 444 | |
| 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", | |
| 450 } | |
| 451 | |
| 452 ------------------------------------------------------------------------------ | |
| 453 | |
| 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 | |
| 461 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)) | |
| 468 end | |
| 469 ctx.pos = pos + 4 | |
| 470 end | |
| 471 | |
| 472 -- Fallback for unknown opcodes. | |
| 473 local function unknown(ctx) | |
| 474 return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) | |
| 475 end | |
| 476 | |
| 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) | |
| 481 end | |
| 482 | |
| 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) | |
| 487 end | |
| 488 | |
| 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 | |
| 496 | |
| 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._ | |
| 504 end | |
| 505 end | |
| 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 | |
| 509 | |
| 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 | |
| 599 end | |
| 600 end | |
| 601 elseif p == "1" then | |
| 602 if last == "ra" then | |
| 603 operands[#operands] = nil | |
| 604 end | |
| 605 else | |
| 606 assert(false) | |
| 607 end | |
| 608 if x then operands[#operands+1] = x; last = x end | |
| 609 end | |
| 610 | |
| 611 return putop(ctx, name, operands) | |
| 612 end | |
| 613 | |
| 614 ------------------------------------------------------------------------------ | |
| 615 | |
| 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 | |
| 624 end | |
| 625 | |
| 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 | |
| 638 end | |
| 639 | |
| 640 local function create_el(code, addr, out) | |
| 641 local ctx = create(code, addr, out) | |
| 642 ctx.get = get_le | |
| 643 return ctx | |
| 644 end | |
| 645 | |
| 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 | |
| 650 end | |
| 651 | |
| 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 | |
| 657 end | |
| 658 | |
| 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() | |
| 662 end | |
| 663 | |
| 664 local function disass_el(code, addr, out) | |
| 665 create_el(code, addr, out):disass() | |
| 666 end | |
| 667 | |
| 668 local function disass_r6(code, addr, out) | |
| 669 create_r6(code, addr, out):disass() | |
| 670 end | |
| 671 | |
| 672 local function disass_r6_el(code, addr, out) | |
| 673 create_r6_el(code, addr, out):disass() | |
| 674 end | |
| 675 | |
| 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) | |
| 680 end | |
| 681 | |
| 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 | |
| 693 } | |
| 694 |