improve mips disassembler to handle most of N32 code
authorkub <derkub@gmail.com>
Mon, 14 Dec 2020 20:14:13 +0000 (21:14 +0100)
committerkub <derkub@gmail.com>
Mon, 14 Dec 2020 20:14:13 +0000 (21:14 +0100)
platform/common/dismips.c

index d855ad6..b3d9001 100644 (file)
@@ -6,8 +6,8 @@
  * See COPYING file in the top-level directory.
  */
 
-// unimplemented insns: MOV[FT], SYSCALL, BREAK, SYNC, SYNCI, T*, SDBBP, RDHWR,
-// CACHE, PREF, LWC*/LDC*, SWC*/SDC*, and all of COP* (fpu, mmu, irq, exc, ...)
+// unimplemented insns: SYNC, CACHE, PREF,
+// MOV[FT], LWC*/LDC*, SWC*/SDC*, and all of COP* (fpu, mmu, irq, exc, ...)
 // unimplemented variants of insns: EHB, SSNOP (both SLL zero), JALR.HB, JR.HB
 // however, it's certainly good enough for anything picodrive DRC throws at it.
 
@@ -56,15 +56,17 @@ static char *const register_names[32] = {
 
 
 enum insn_type {
-       REG_DTS, REG_TS,        // 3, 2, or 1 regs
+       REG_DST, REG_ST, REG_TD, // 3, 2, or 1 regs
        REG_DS, REG_DT, REG_D, REG_S,
        S_IMM_DT,               // 2 regs with shift amount
        F_IMM_TS,               // 2 regs with bitfield spec
        B_IMM_S, B_IMM_TS,      // pc-relative branches with 1 or 2 regs
+       T_IMM_S,                // trap insns with immediate
        J_IMM,                  // region-relative jump
        A_IMM_TS,               // arithmetic immediate with 2 regs
        L_IMM_T, L_IMM_TS,      // logical immediate with 1 or 2 regs
-       M_IMM_TS,               // memory indexed with 2 regs
+       M_IMM_TS, M_IMM_S,      // memory indexed with 2 regs
+       SB_CODE,                // code parameter (syscall, break, sdbbp)
        SR_BIT = 0x80           // shift right with R-bit
 };
 
@@ -83,51 +85,51 @@ static const struct insn special_insns[] = {
 //     {0x01,         , "movf\0movt"},
        {0x02, S_IMM_DT|SR_BIT, "srl\0rotr"},
        {0x03, S_IMM_DT, "sra"},
-       {0x04, REG_DTS, "sllv"},
-       {0x06, REG_DTS|SR_BIT, "srlv\0rotrv"},
-       {0x07, REG_DTS, "srav"},
+       {0x04, REG_DST, "sllv"},
+       {0x06, REG_DST|SR_BIT, "srlv\0rotrv"},
+       {0x07, REG_DST, "srav"},
        {0x08, REG_S,   "jr"},
        {0x09, REG_DS,  "jalr"},
-       {0x0a, REG_DTS, "movz"},
-       {0x0b, REG_DTS, "movn"},
-//     {0x0c, ,        "syscall"},
-//     {0x0d, ,        "break"},
+       {0x0a, REG_DST, "movz"},
+       {0x0b, REG_DST, "movn"},
+       {0x0c, SB_CODE, "syscall"},
+       {0x0d, SB_CODE, "break"},
 //     {0x0f, ,        "sync"},
        {0x10, REG_D,   "mfhi"},
        {0x11, REG_S,   "mthi"},
        {0x12, REG_D,   "mflo"},
        {0x13, REG_S,   "mtlo"},
-       {0x14, REG_DTS, "dsllv"},
-       {0x16, REG_DTS|SR_BIT, "dsrlv\0drotrv"},
-       {0x17, REG_DTS, "dsrav"},
-       {0x18, REG_TS,  "mult"},
-       {0x19, REG_TS,  "multu"},
-       {0x1A, REG_TS,  "div"},
-       {0x1B, REG_TS,  "divu"},
-       {0x1C, REG_TS,  "dmult"},
-       {0x1D, REG_TS,  "dmultu"},
-       {0x1E, REG_TS,  "ddiv"},
-       {0x1F, REG_TS,  "ddivu"},
-       {0x20, REG_DTS, "add"},
-       {0x21, REG_DTS, "addu"},
-       {0x22, REG_DTS, "sub"},
-       {0x23, REG_DTS, "subu"},
-       {0x24, REG_DTS, "and"},
-       {0x25, REG_DTS, "or"},
-       {0x26, REG_DTS, "xor"},
-       {0x27, REG_DTS, "nor"},
-       {0x2A, REG_DTS, "slt"},
-       {0x2B, REG_DTS, "sltu"},
-       {0x2C, REG_DTS, "dadd"},
-       {0x2D, REG_DTS, "daddu"},
-       {0x2E, REG_DTS, "dsub"},
-       {0x2F, REG_DTS, "dsubu"},
-//     {0x30, REG_TS,  "tge" },
-//     {0x31, REG_TS,  "tgeu" },
-//     {0x32, REG_TS,  "tlt" },
-//     {0x33, REG_TS,  "tltu" },
-//     {0x34, REG_TS,  "teq" },
-//     {0x36, REG_TS,  "tne" },
+       {0x14, REG_DST, "dsllv"},
+       {0x16, REG_DST|SR_BIT, "dsrlv\0drotrv"},
+       {0x17, REG_DST, "dsrav"},
+       {0x18, REG_ST,  "mult"},
+       {0x19, REG_ST,  "multu"},
+       {0x1A, REG_ST,  "div"},
+       {0x1B, REG_ST,  "divu"},
+       {0x1C, REG_ST,  "dmult"},
+       {0x1D, REG_ST,  "dmultu"},
+       {0x1E, REG_ST,  "ddiv"},
+       {0x1F, REG_ST,  "ddivu"},
+       {0x20, REG_DST, "add"},
+       {0x21, REG_DST, "addu"},
+       {0x22, REG_DST, "sub"},
+       {0x23, REG_DST, "subu"},
+       {0x24, REG_DST, "and"},
+       {0x25, REG_DST, "or"},
+       {0x26, REG_DST, "xor"},
+       {0x27, REG_DST, "nor"},
+       {0x2A, REG_DST, "slt"},
+       {0x2B, REG_DST, "sltu"},
+       {0x2C, REG_DST, "dadd"},
+       {0x2D, REG_DST, "daddu"},
+       {0x2E, REG_DST, "dsub"},
+       {0x2F, REG_DST, "dsubu"},
+       {0x30, REG_ST,  "tge" },
+       {0x31, REG_ST,  "tgeu" },
+       {0x32, REG_ST,  "tlt" },
+       {0x33, REG_ST,  "tltu" },
+       {0x34, REG_ST,  "teq" },
+       {0x36, REG_ST,  "tne" },
        {0x38, S_IMM_DT, "dsll"},
        {0x3A, S_IMM_DT|SR_BIT, "dsrl\0drotrv"},
        {0x3B, S_IMM_DT, "dsra"},
@@ -139,16 +141,16 @@ static const struct insn special_insns[] = {
 // instructions with opcode SPECIAL2 (R-type)
 #define OP_SPECIAL2    0x1C
 static const struct insn special2_insns[] = {
-       {0x00, REG_TS,  "madd" },
-       {0x01, REG_TS,  "maddu" },
-       {0x02, REG_TS,  "mul" },
-       {0x04, REG_TS,  "msub" },
-       {0x05, REG_TS,  "msubu" },
+       {0x00, REG_ST,  "madd" },
+       {0x01, REG_ST,  "maddu" },
+       {0x02, REG_ST,  "mul" },
+       {0x04, REG_ST,  "msub" },
+       {0x05, REG_ST,  "msubu" },
        {0x20, REG_DS,  "clz" },
        {0x21, REG_DS,  "clo" },
        {0x24, REG_DS,  "dclz" },
        {0x25, REG_DS,  "dclo" },
-//     {0x37,       ,  "sdbbp" },
+       {0x37, SB_CODE, "sdbbp" },
 };
 
 // instructions with opcode SPECIAL3 (R-type)
@@ -162,7 +164,7 @@ static const struct insn special3_insns[] = {
        {0x05, F_IMM_TS, "dinsm" },
        {0x06, F_IMM_TS, "dinsu" },
        {0x07, F_IMM_TS, "dins" },
-//     {0x3b,         , "rdhwr" },
+       {0x3b, REG_TD,   "rdhwr" },
 };
 
 // instruction with opcode SPECIAL3 and function *BSHFL
@@ -185,18 +187,17 @@ static const struct insn regimm_insns[] = {
        {0x01, B_IMM_S, "bgez"},
        {0x02, B_IMM_S, "bltzl"},
        {0x03, B_IMM_S, "bgezl"},
-//     {0x08, ,        "tgei"},
-//     {0x09, ,        "tgeiu"},
-//     {0x0a, ,        "tlti"},
-//     {0x0b, ,        "tltiu"},
-//     {0x0c, ,        "teqi"},
-//     {0x0e, ,        "tnei"},
+       {0x08, T_IMM_S, "tgei"},
+       {0x09, T_IMM_S, "tgeiu"},
+       {0x0a, T_IMM_S, "tlti"},
+       {0x0b, T_IMM_S, "tltiu"},
+       {0x0c, T_IMM_S, "teqi"},
+       {0x0e, T_IMM_S, "tnei"},
        {0x10, B_IMM_S, "bltzal"},
        {0x11, B_IMM_S, "bgezal"},
        {0x12, B_IMM_S, "bltzall"},
        {0x13, B_IMM_S, "bgezall"},
-       {0x13, B_IMM_S, "bgezall"},
-//     {0x1f,        , "synci" },
+       {0x1f, M_IMM_S, "synci" },
 };
 
 // instructions with other opcodes (I-type)
@@ -337,7 +338,7 @@ int dismips(uintptr_t pc, uint32_t insn, char *buf, size_t buflen, unsigned long
        }
 
        switch (pi->type & ~SR_BIT) {
-       case REG_DTS:
+       case REG_DST:
                if ((insn & 0x3f) == 0x25 /*OR*/ && (insn & 0x1f0000) == 0 /*zero*/)
                        snprintf(buf, buflen, "move %s, %s", rd, rs);
                else if ((pi->type & SR_BIT) && (insn & (1<<6)))
@@ -345,8 +346,14 @@ int dismips(uintptr_t pc, uint32_t insn, char *buf, size_t buflen, unsigned long
                else
                        snprintf(buf, buflen, "%s %s, %s, %s", pi->name, rd, rs, rt);
                break;
-       case REG_TS:
-               snprintf(buf, buflen, "%s %s, %s", pi->name, rs, rt);
+       case REG_ST:
+               if ((insn & 0x38) == 0x30 /*T..*/)
+                       snprintf(buf, buflen, "%s %s, %s (code %d)", pi->name, rs, rt, (insn>>6) & 0x3ff);
+               else
+                       snprintf(buf, buflen, "%s %s, %s", pi->name, rs, rt);
+               break;
+       case REG_TD:
+               snprintf(buf, buflen, "%s %s, %s", pi->name, rt, rd);
                break;
        case REG_DS:
                snprintf(buf, buflen, "%s %s, %s", pi->name, rd, rs);
@@ -406,6 +413,15 @@ int dismips(uintptr_t pc, uint32_t insn, char *buf, size_t buflen, unsigned long
        case M_IMM_TS:
                snprintf(buf, buflen, "%s %s, %d(%s)", pi->name, rt, imm, rs);
                break;
+       case M_IMM_S:
+               snprintf(buf, buflen, "%s %d(%s)", pi->name, imm, rs);
+               break;
+       case T_IMM_S:
+               snprintf(buf, buflen, "%s %s, %d", pi->name, rs, imm);
+               break;
+       case SB_CODE:
+               snprintf(buf, buflen, "%s %d", pi->name, (insn>>6) & 0xfffff);
+               break;
        }
        return 1;
 }