dis_mips.lua 21 KB

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