/* this disassembler is courtesy of mednafen */ #include "psx.h" #include "types.h" #include #include //TODO - add break opcode to disassembly namespace MDFN_IEN_PSX { struct OpEntry { u32 mask; u32 value; const char *mnemonic; const char *format; }; #define MASK_OP (0x3F << 26) #define MASK_FUNC (0x3F) #define MASK_RS (0x1F << 21) #define MASK_RT (0x1F << 16) #define MASK_RD (0x1F << 11) #define MASK_SA (0x1F << 6) #define MK_OP(mnemonic, format, op, func, extra_mask) { MASK_OP | (op ? 0 : MASK_FUNC) | extra_mask, (op << 26) | func, mnemonic, format } #define MK_OP_REGIMM(mnemonic, regop) { MASK_OP | MASK_RT, (0x01 << 26) | (regop << 16), mnemonic, "s, p" } static OpEntry ops[] = { MK_OP("nop", "", 0, 0, MASK_RT | MASK_RD | MASK_SA), MK_OP("sll", "d, t, a", 0, 0, 0), MK_OP("srl", "d, t, a", 0, 2, 0), MK_OP("sra", "d, t, a", 0, 3, 0), MK_OP("sllv", "d, t, s", 0, 4, 0), MK_OP("srlv", "d, t, s", 0, 6, 0), MK_OP("srav", "d, t, s", 0, 7, 0), MK_OP("jr", "s", 0, 8, 0), MK_OP("jalr", "d, s", 0, 9, 0), MK_OP("syscall", "", 0, 12, 0), // TODO MK_OP("break", "", 0, 13, 0), // TODO MK_OP("mfhi", "d", 0, 16, 0), MK_OP("mthi", "s", 0, 17, 0), MK_OP("mflo", "d", 0, 18, 0), MK_OP("mtlo", "s", 0, 19, 0), MK_OP("mult", "s, t", 0, 24, 0), MK_OP("multu", "s, t", 0, 25, 0), MK_OP("div", "s, t", 0, 26, 0), MK_OP("divu", "s, t", 0, 27, 0), MK_OP("add", "d, s, t", 0, 32, 0), MK_OP("addu", "d, s, t", 0, 33, 0), MK_OP("sub", "d, s, t", 0, 34, 0), MK_OP("subu", "d, s, t", 0, 35, 0), MK_OP("and", "d, s, t", 0, 36, 0), MK_OP("or", "d, s, t", 0, 37, 0), MK_OP("xor", "d, s, t", 0, 38, 0), MK_OP("nor", "d, s, t", 0, 39, 0), MK_OP("slt", "d, s, t", 0, 42, 0), MK_OP("sltu", "d, s, t", 0, 43, 0), MK_OP_REGIMM("bgez", 0x01), MK_OP_REGIMM("bgezal", 0x11), MK_OP_REGIMM("bltz", 0x00), MK_OP_REGIMM("bltzal", 0x10), MK_OP("j", "P", 2, 0, 0), MK_OP("jal", "P", 3, 0, 0), MK_OP("beq", "s, t, p", 4, 0, 0), MK_OP("bne", "s, t, p", 5, 0, 0), MK_OP("blez", "s, p", 6, 0, 0), MK_OP("bgtz", "s, p", 7, 0, 0), MK_OP("addi", "t, s, i", 8, 0, 0), MK_OP("addiu", "t, s, i", 9, 0, 0), MK_OP("slti", "t, s, i", 10, 0, 0), MK_OP("sltiu", "t, s, i", 11, 0, 0), MK_OP("andi", "t, s, z", 12, 0, 0), MK_OP("ori", "t, s, z", 13, 0, 0), MK_OP("xori", "t, s, z", 14, 0, 0), MK_OP("lui", "t, z", 15, 0, 0), // COP0 stuff here //#define MK_OP(mnemonic, format, op, func, extra_mask) { MASK_OP | (op ? 0 : MASK_FUNC) | extra_mask, (op << 26) | func, mnemonic, format } #define COPMF(num) ((num)<<21) MK_OP("mfc0", "t, D", 16, 0, 0x03E00000), MK_OP("mfc1", "t, D", 17, 0, 0x03E00000), MK_OP("mfc2", "t, D", 18, 0, 0x03E00000), MK_OP("mfc3", "t, D", 19, 0, 0x03E00000), MK_OP("mtc0", "t, D", 16, COPMF(4), 0x03E00000), MK_OP("mtc1", "t, D", 17, COPMF(4), 0x03E00000), MK_OP("mtc2", "t, D", 18, COPMF(4), 0x03E00000), MK_OP("mtc3", "t, D", 19, COPMF(4), 0x03E00000), //MK_OP("rfe", "", 19, COPMF(4), 0x03E00000), //TODO MK_OP("lb", "t, i(s)", 32, 0, 0), MK_OP("lh", "t, i(s)", 33, 0, 0), MK_OP("lwl", "t, i(s)", 34, 0, 0), MK_OP("lw", "t, i(s)", 35, 0, 0), MK_OP("lbu", "t, i(s)", 36, 0, 0), MK_OP("lhu", "t, i(s)", 37, 0, 0), MK_OP("lwr", "t, i(s)", 38, 0, 0), MK_OP("sb", "t, i(s)", 40, 0, 0), MK_OP("sh", "t, i(s)", 41, 0, 0), MK_OP("swl", "t, i(s)", 42, 0, 0), MK_OP("sw", "t, i(s)", 43, 0, 0), MK_OP("swr", "t, i(s)", 46, 0, 0), { 0, 0, NULL, NULL } }; std::string DisassembleMIPS(u32 PC, u32 instr) { std::string ret = "UNKNOWN"; unsigned int rs = (instr >> 21) & 0x1F; unsigned int rt = (instr >> 16) & 0x1F; unsigned int rd = (instr >> 11) & 0x1F; unsigned int shamt = (instr >> 6) & 0x1F; unsigned int immediate = (s32)(s16)(instr & 0xFFFF); unsigned int immediate_ze = (instr & 0xFFFF); unsigned int jt = instr & ((1 << 26) - 1); static const char *gpr_names[32] = { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" }; OpEntry *op = ops; while(op->mnemonic) { if((instr & op->mask) == op->value) { // a = shift amount // s = rs // t = rt // d = rd // i = immediate // z = immediate, zero-extended // p = PC + 4 + immediate // P = ((PC + 4) & 0xF0000000) | (26bitval << 2) char s_a[16]; char s_i[16]; char s_z[16]; char s_p[16]; char s_P[16]; char s_D[16]; _snprintf(s_D, sizeof(s_D), "%d", rd); _snprintf(s_a, sizeof(s_a), "%d", shamt); if(immediate < 0) _snprintf(s_i, sizeof(s_i), "%d", immediate); else _snprintf(s_i, sizeof(s_i), "0x%04x", (u32)immediate); _snprintf(s_z, sizeof(s_z), "0x%04x", immediate_ze); _snprintf(s_p, sizeof(s_p), "0x%08x", PC + 4 + (immediate << 2)); _snprintf(s_P, sizeof(s_P), "0x%08x", ((PC + 4) & 0xF0000000) | (jt << 2)); ret = std::string(op->mnemonic); ret.append(10 - ret.size(), ' '); for(unsigned int i = 0; i < strlen(op->format); i++) { switch(op->format[i]) { case 'a': ret.append(s_a); break; case 'i': ret.append(s_i); break; case 'z': ret.append(s_z); break; case 'p': ret.append(s_p); break; case 'P': ret.append(s_P); break; case 's': ret.append(gpr_names[rs]); break; case 't': ret.append(gpr_names[rt]); break; case 'd': ret.append(gpr_names[rd]); break; case 'D': ret.append(s_D); break; default: ret.append(1, op->format[i]); break; } } break; } op++; } return(ret); } }