diff --git a/cpu/ppc/ppcdisasm.cpp b/cpu/ppc/ppcdisasm.cpp index 288929c..e16fa99 100644 --- a/cpu/ppc/ppcdisasm.cpp +++ b/cpu/ppc/ppcdisasm.cpp @@ -1,5 +1,6 @@ #include #include +#include //Mandated by Visual Studio #include "ppcdisasm.h" using namespace std; @@ -19,10 +20,6 @@ std::string my_sprintf(const char* format, Args... args) return str; } -const char* arith_im_mnem[9] = { - "mulli", "subfic", "", "", "", "addic", "addic.", "addi", "addis" -}; - const char* bx_mnem[4] = { "b", "bl", "ba", "bla" }; @@ -56,21 +53,31 @@ const char* opc_muldivs[16] = { /* multiply and division instructions */ "", "", "divwu", "divw" }; -const char* opc_int_ldst[16] = { /* integer load and store instructions */ - "lwz", "lwzu", "lbz", "lbzu", "stw", "stwu", "stb", "stbu", "lhz", "lhzu", - "lha", "lhau", "sth", "sthu", "lmw", "stmw" -}; - /** various formatting helpers. */ +void fmt_oneop(string& buf, const char* opc, int src) +{ + buf = my_sprintf("%-8sr%d", opc, src); +} + void fmt_twoop(string& buf, const char* opc, int dst, int src) { buf = my_sprintf("%-8sr%d, r%d", opc, dst, src); } -void fmt_twoop_simm(string& buf, const char* opc, int dst, int imm) +void fmt_twoop_imm(string& buf, const char* opc, int dst, int imm) { - buf = my_sprintf("%-8sr%d, %s0x%X", opc, dst, (imm < 0) ? "-" : "", abs(imm)); + buf = my_sprintf("%-8sr%d, 0x%04X", opc, dst, imm); +} + +void fmt_twoop_fromspr(string& buf, const char* opc, int dst, int src) +{ + buf = my_sprintf("%-8sspr%d, r%d", opc, dst, src); +} + +void fmt_twoop_tospr(string& buf, const char* opc, int dst, int src) +{ + buf = my_sprintf("%-8sr%d, spr%d", opc, dst, src); } void fmt_threeop(string& buf, const char* opc, int dst, int src1, int src2) @@ -78,15 +85,22 @@ void fmt_threeop(string& buf, const char* opc, int dst, int src1, int src2) buf = my_sprintf("%-8sr%d, r%d, r%d", opc, dst, src1, src2); } -void fmt_threeop_uimm(string& buf, const char* opc, int dst, int src1, int imm) +void fmt_threeop_imm(string& buf, const char* opc, int dst, int src1, int imm) { buf = my_sprintf("%-8sr%d, r%d, 0x%04X", opc, dst, src1, imm); } -void fmt_threeop_simm(string& buf, const char* opc, int dst, int src1, int imm) +void fmt_fourop(string& buf, const char* opc, int dst, int src1, int src2, int src3) { - buf = my_sprintf("%-8sr%d, r%d, %s0x%X", opc, dst, src1, - (imm < 0) ? "-" : "", abs(imm)); + buf = my_sprintf("%-8sr%d, r%d, r%d, r%d", opc, dst, src1, src2, src3); +} + +void fmt_rotateop(string& buf, const char* opc, int dst, int src1, int sh, int mb, int me, bool imm) +{ + if (imm) + buf = my_sprintf("%-8sr%d, r%d, sh%d, mb%d, me%d", opc, dst, src1, sh, mb, me); + else + buf = my_sprintf("%-8sr%d, r%d, r%d, mb%d, me%d", opc, dst, src1, sh, mb, me); } void opc_illegal(PPCDisasmContext* ctx) @@ -104,34 +118,163 @@ void opc_group4(PPCDisasmContext* ctx) printf("Altivec group 4 not supported yet\n"); } -void opc_ar_im(PPCDisasmContext* ctx) +void opc_rlwimi(PPCDisasmContext* ctx) +{ + auto rs = (ctx->instr_code >> 21) & 0x1F; + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto sh = (ctx->instr_code >> 11) & 0x1F; + auto mb = (ctx->instr_code >> 6) & 0x1F; + auto me = (ctx->instr_code >> 1) & 0x1F; + + if (ctx->instr_code & 1) + fmt_rotateop(ctx->instr_str, "rlwimi.", rs, ra, sh, mb, me, true); + else + fmt_rotateop(ctx->instr_str, "rlwimi", rs, ra, sh, mb, me, true); +} + +void opc_rlwinm(PPCDisasmContext* ctx) +{ + auto rs = (ctx->instr_code >> 21) & 0x1F; + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto sh = (ctx->instr_code >> 11) & 0x1F; + auto mb = (ctx->instr_code >> 6) & 0x1F; + auto me = (ctx->instr_code >> 1) & 0x1F; + + if (ctx->instr_code & 1) + fmt_rotateop(ctx->instr_str, "rlwinm.", rs, ra, sh, mb, me, true); + else + fmt_rotateop(ctx->instr_str, "rlwinm", rs, ra, sh, mb, me, true); +} + +void opc_rlwnm(PPCDisasmContext* ctx) +{ + auto rs = (ctx->instr_code >> 21) & 0x1F; + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto rb = (ctx->instr_code >> 11) & 0x1F; + auto mb = (ctx->instr_code >> 6) & 0x1F; + auto me = (ctx->instr_code >> 1) & 0x1F; + + if (ctx->instr_code & 1) + fmt_rotateop(ctx->instr_str, "rlwnm.", rs, ra, rb, mb, me, false); + else + fmt_rotateop(ctx->instr_str, "rlwnm", rs, ra, rb, mb, me, false); +} + +void opc_mulli(PPCDisasmContext* ctx) { auto ra = (ctx->instr_code >> 16) & 0x1F; auto rd = (ctx->instr_code >> 21) & 0x1F; - int32_t imm = SIGNEXT(ctx->instr_code & 0xFFFF, 15); + auto imm = ctx->instr_code & 0xFFFF; - if ((ctx->instr_code >> 26) == 0xE && !ra && ctx->simplified) { - fmt_twoop_simm(ctx->instr_str, "li", rd, imm); - } - else { - fmt_threeop_simm(ctx->instr_str, arith_im_mnem[(ctx->instr_code >> 26) - 7], - rd, ra, imm); - } + fmt_threeop_imm(ctx->instr_str, "mulli", rd, ra, imm); +} + +void opc_subfic(PPCDisasmContext* ctx) +{ + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto rd = (ctx->instr_code >> 21) & 0x1F; + auto imm = ctx->instr_code & 0xFFFF; + + fmt_threeop_imm(ctx->instr_str, "subfic", rd, ra, imm); } void power_dozi(PPCDisasmContext* ctx) { - //return "DEADBEEF"; + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto rd = (ctx->instr_code >> 21) & 0x1F; + auto imm = ctx->instr_code & 0xFFFF; + + fmt_threeop_imm(ctx->instr_str, "dozi", rd, ra, imm); } void opc_cmpli(PPCDisasmContext* ctx) { - //return "DEADBEEF"; + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto crfd = (ctx->instr_code >> 23) & 0x07; + auto imm = ctx->instr_code & 0xFFFF; + + if (ctx->instr_code & 0x200000) + opc_illegal(ctx); + else + fmt_threeop_imm(ctx->instr_str, "cmpli", crfd, ra, imm); } void opc_cmpi(PPCDisasmContext* ctx) { - //return "DEADBEEF"; + auto crfd = (ctx->instr_code >> 23) & 0x07; + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto imm = ctx->instr_code & 0xFFFF; + + if (ctx->instr_code & 0x200000) + opc_illegal(ctx); + else + fmt_threeop_imm(ctx->instr_str, "cmpi", crfd, ra, imm); +} + +void opc_addic(PPCDisasmContext* ctx) +{ + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto rd = (ctx->instr_code >> 21) & 0x1F; + auto imm = ctx->instr_code & 0xFFFF; + + fmt_threeop_imm(ctx->instr_str, "addic", rd, ra, imm); +} + +void opc_addicdot(PPCDisasmContext* ctx) +{ + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto rd = (ctx->instr_code >> 21) & 0x1F; + auto imm = ctx->instr_code & 0xFFFF; + + fmt_threeop_imm(ctx->instr_str, "addic.", rd, ra, imm); +} + +void opc_addi(PPCDisasmContext* ctx) +{ + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto rd = (ctx->instr_code >> 21) & 0x1F; + auto imm = ctx->instr_code & 0xFFFF; + + if (ra == 0 && ctx->simplified) + fmt_twoop_imm(ctx->instr_str, "li", rd, imm); + else + fmt_threeop_imm(ctx->instr_str, "addi", rd, ra, imm); +} + +void opc_addis(PPCDisasmContext* ctx) +{ + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto rd = (ctx->instr_code >> 21) & 0x1F; + auto imm = ctx->instr_code & 0xFFFF; + + if (ra == 0 && ctx->simplified) + fmt_twoop_imm(ctx->instr_str, "lis", rd, imm); + else + fmt_threeop_imm(ctx->instr_str, "addis", rd, ra, imm); +} + +void opc_lwz(PPCDisasmContext* ctx) +{ + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto rd = (ctx->instr_code >> 21) & 0x1F; + auto offset = ctx->instr_code & 0xFFFF; + + if (ra == 0) + fmt_twoop_imm(ctx->instr_str, "lzw", rd, offset); + else + fmt_threeop_imm(ctx->instr_str, "lzw", rd, ra, offset); +} + +void opc_lwzu(PPCDisasmContext* ctx) +{ + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto rd = (ctx->instr_code >> 21) & 0x1F; + auto offset = ctx->instr_code & 0xFFFF; + + if ((ra == 0) || (ra == rd)) + opc_illegal(ctx); + else + fmt_threeop_imm(ctx->instr_str, "lzwu", rd, ra, offset); } void generic_bcx(PPCDisasmContext* ctx, uint32_t bo, uint32_t bi, uint32_t dst) @@ -139,10 +282,10 @@ void generic_bcx(PPCDisasmContext* ctx, uint32_t bo, uint32_t bi, uint32_t dst) char opcode[10] = "bc"; if (ctx->instr_code & 1) { - strcat(opcode, "l"); /* add suffix "l" if the LK bit is set */ + strcat_s(opcode, "l"); /* add suffix "l" if the LK bit is set */ } if (ctx->instr_code & 2) { - strcat(opcode, "a"); /* add suffix "a" if the AA bit is set */ + strcat_s(opcode, "a"); /* add suffix "a" if the AA bit is set */ } ctx->instr_str = my_sprintf("%-8s%d, %d, 0x%08X", opcode, bo, bi, dst); } @@ -171,37 +314,36 @@ void opc_bcx(PPCDisasmContext* ctx) } if (!(bo & 4)) { - strcat(opcode, "d"); - strcat(opcode, (bo & 2) ? "z" : "nz"); + strcat_s(opcode, "d"); + strcat_s(opcode, (bo & 2) ? "z" : "nz"); if (!(bo & 0x10)) { - strcat(opcode, (bo & 8) ? "t" : "f"); + strcat_s(opcode, (bo & 8) ? "t" : "f"); if (cr) { - strcat(operands, "4*cr0+"); + strcat_s(operands, "4*cr0+"); operands[4] = cr + '0'; } - strcat(operands, br_cond[4 + (bi & 3)]); - strcat(operands, ", "); + strcat_s(operands, br_cond[4 + (bi & 3)]); } } else { /* CTR ignored */ - strcat(opcode, br_cond[((bo >> 1) & 4) | (bi & 3)]); + strcat_s(opcode, br_cond[((bo >> 1) & 4) | (bi & 3)]); if (cr) { - strcat(operands, "cr0, "); + strcat_s(operands, "cr0"); operands[2] = cr + '0'; } } if (ctx->instr_code & 1) { - strcat(opcode, "l"); /* add suffix "l" if the LK bit is set */ + strcat_s(opcode, "l"); /* add suffix "l" if the LK bit is set */ } if (ctx->instr_code & 2) { - strcat(opcode, "a"); /* add suffix "a" if the AA bit is set */ + strcat_s(opcode, "a"); /* add suffix "a" if the AA bit is set */ } if (bo & 1) { /* incorporate prediction bit if set */ - strcat(opcode, (ctx->instr_code & 0x8000) ? "-" : "+"); + strcat_s(opcode, (ctx->instr_code & 0x8000) ? "-" : "+"); } - ctx->instr_str = my_sprintf("%-8s%s0x%08X", opcode, operands, dst); + ctx->instr_str = my_sprintf("%-8s%s, 0x%08X", opcode, operands, dst); } void opc_bx(PPCDisasmContext* ctx) @@ -212,6 +354,24 @@ void opc_bx(PPCDisasmContext* ctx) ctx->instr_str = my_sprintf("%-8s0x%08X", bx_mnem[ctx->instr_code & 3], dst); } +void opc_andidot(PPCDisasmContext* ctx) +{ + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto rs = (ctx->instr_code >> 21) & 0x1F; + auto imm = ctx->instr_code & 0xFFFF; + + fmt_threeop_imm(ctx->instr_str, "andi.", ra, rs, imm); +} + +void opc_andisdot(PPCDisasmContext* ctx) +{ + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto rs = (ctx->instr_code >> 21) & 0x1F; + auto imm = ctx->instr_code & 0xFFFF; + + fmt_threeop_imm(ctx->instr_str, "andi.", ra, rs, imm); +} + void opc_ori(PPCDisasmContext* ctx) { auto ra = (ctx->instr_code >> 16) & 0x1F; @@ -226,7 +386,42 @@ void opc_ori(PPCDisasmContext* ctx) fmt_twoop(ctx->instr_str, "mr", ra, rs); return; } - fmt_threeop_uimm(ctx->instr_str, "ori", ra, rs, imm); + fmt_threeop_imm(ctx->instr_str, "ori", ra, rs, imm); +} + +void opc_oris(PPCDisasmContext* ctx) +{ + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto rs = (ctx->instr_code >> 21) & 0x1F; + auto imm = ctx->instr_code & 0xFFFF; + + fmt_threeop_imm(ctx->instr_str, "oris", ra, rs, imm); +} + +void opc_xori(PPCDisasmContext* ctx) +{ + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto rs = (ctx->instr_code >> 21) & 0x1F; + auto imm = ctx->instr_code & 0xFFFF; + + fmt_threeop_imm(ctx->instr_str, "xori", ra, rs, imm); +} + +void opc_xoris(PPCDisasmContext* ctx) +{ + auto ra = (ctx->instr_code >> 16) & 0x1F; + auto rs = (ctx->instr_code >> 21) & 0x1F; + auto imm = ctx->instr_code & 0xFFFF; + + fmt_threeop_imm(ctx->instr_str, "xoris", ra, rs, imm); +} + +void opc_group19(PPCDisasmContext* ctx) +{ + int ext_opc = (ctx->instr_code >> 1) & 0x3FF; /* extract extended opcode */ + + if (ext_opc == 50) + ctx->instr_str = my_sprintf("%-8s, "rfi"); } void opc_group31(PPCDisasmContext* ctx) @@ -248,11 +443,11 @@ void opc_group31(PPCDisasmContext* ctx) opc_illegal(ctx); } else { - strcpy(opcode, opc_subs[index]); + strcpy_s(opcode, opc_subs[index]); if (ext_opc & 0x200) /* check OE bit */ - strcat(opcode, "o"); + strcat_s(opcode, "o"); if (rc_set) - strcat(opcode, "."); + strcat_s(opcode, "."); if (index == 3 || index == 6 || index == 7 || index == 11 || index == 15) { /* ugly check for two-operands instructions */ if (rb != 0) @@ -271,11 +466,11 @@ void opc_group31(PPCDisasmContext* ctx) opc_illegal(ctx); } else { - strcpy(opcode, opc_adds[index]); + strcpy_s(opcode, opc_adds[index]); if (ext_opc & 0x200) /* check OE bit */ - strcat(opcode, "o"); + strcat_s(opcode, "o"); if (rc_set) - strcat(opcode, "."); + strcat_s(opcode, "."); if (index == 6 || index == 7) { if (rb != 0) opc_illegal(ctx); @@ -293,11 +488,11 @@ void opc_group31(PPCDisasmContext* ctx) opc_illegal(ctx); } else { - strcpy(opcode, opc_muldivs[index]); + strcpy_s(opcode, opc_muldivs[index]); if (ext_opc & 0x200) /* check OE bit */ - strcat(opcode, "o"); + strcat_s(opcode, "o"); if (rc_set) - strcat(opcode, "."); + strcat_s(opcode, "."); if ((!index || index == 2) && (ext_opc & 0x200)) opc_illegal(ctx); else @@ -310,13 +505,13 @@ void opc_group31(PPCDisasmContext* ctx) fmt_twoop(ctx->instr_str, rc_set ? "mr." : "mr", ra, rs); } else { - strcpy(opcode, opc_logic[index]); + strcpy_s(opcode, opc_logic[index]); if (!strlen(opcode)) { opc_illegal(ctx); } else { if (rc_set) - strcat(opcode, "."); + strcat_s(opcode, "."); fmt_threeop(ctx->instr_str, opcode, ra, rs, rb); } } @@ -336,6 +531,8 @@ void opc_group31(PPCDisasmContext* ctx) break; } + auto ref_spr = (((ctx->instr_code >> 11) & 31) << 5) | ((ctx->instr_code >> 16) & 31); + switch (ext_opc) { case 4: if (rc_set) @@ -343,6 +540,9 @@ void opc_group31(PPCDisasmContext* ctx) else ctx->instr_str = my_sprintf("%-8s%d, r%d, r%d", "tw", rs, ra, rb); break; + case 19: /* mfcr */ + fmt_oneop(ctx->instr_str, "mfcr", rs); + break; case 144: /* mtcrf */ if (ctx->instr_code & 0x100801) opc_illegal(ctx); @@ -351,50 +551,34 @@ void opc_group31(PPCDisasmContext* ctx) (ctx->instr_code >> 12) & 0xFF, rs); } break; + case 146: /* mtmsr */ + fmt_oneop(ctx->instr_str, "mtmsr", rs); + break; + case 339: /* mfspr */ + fmt_twoop_fromspr(ctx->instr_str, "mfspr", rs, ref_spr); + break; + case 467: /* mtspr */ + fmt_twoop_tospr(ctx->instr_str, "mtspr", ref_spr, rs); + break; default: opc_illegal(ctx); } } -void opc_intldst(PPCDisasmContext* ctx) -{ - int32_t opcode = (ctx->instr_code >> 26) - 32; - int32_t ra = (ctx->instr_code >> 16) & 0x1F; - int32_t rd = (ctx->instr_code >> 21) & 0x1F; - int32_t imm = SIGNEXT(ctx->instr_code & 0xFFFF, 15); - - /* ra = 0 is forbidden for loads and stores with update */ - /* ra = rd is forbidden for loads with update */ - if (((opcode < 14) && (opcode & 5) == 1 && ra == rd) || ((opcode & 1) && !ra)) - { - opc_illegal(ctx); - return; - } - - if (ra) { - ctx->instr_str = my_sprintf("%-8sr%d, %s0x%X(r%d)", opc_int_ldst[opcode], - rd, ((imm < 0) ? "-" : ""), abs(imm), ra); - } - else { - ctx->instr_str = my_sprintf("%-8sr%d, %s0x%X", opc_int_ldst[opcode], - rd, ((imm < 0) ? "-" : ""), abs(imm)); - } -} - /** main dispatch table. */ static std::function OpcodeDispatchTable[64] = { opc_illegal, opc_illegal, opc_illegal, opc_twi, - opc_group4, opc_illegal, opc_illegal, opc_ar_im, - opc_ar_im, power_dozi, opc_cmpli, opc_cmpi, - opc_ar_im, opc_ar_im, opc_ar_im, opc_ar_im, - opc_bcx, opc_illegal, opc_bx, opc_illegal, + opc_group4, opc_illegal, opc_illegal, opc_mulli, + opc_subfic, power_dozi, opc_cmpli, opc_cmpi, + opc_addic, opc_addicdot, opc_addi, opc_addis, + opc_bcx, opc_illegal, opc_bx, opc_group19, + opc_rlwimi, opc_rlwinm, opc_illegal, opc_rlwnm, + opc_ori, opc_oris, opc_xori, opc_xoris, + opc_andidot, opc_andisdot, opc_illegal, opc_group31, + opc_lwz, opc_lwzu, opc_illegal, opc_illegal, + opc_illegal, opc_illegal, opc_illegal, opc_illegal, + opc_illegal, opc_illegal, opc_illegal, opc_illegal, opc_illegal, opc_illegal, opc_illegal, opc_illegal, - opc_ori, opc_illegal, opc_illegal, opc_illegal, - opc_illegal, opc_illegal, opc_illegal, opc_group31, - opc_intldst, opc_intldst, opc_intldst, opc_intldst, - opc_intldst, opc_intldst, opc_intldst, opc_intldst, - opc_intldst, opc_intldst, opc_intldst, opc_intldst, - opc_intldst, opc_intldst, opc_intldst, opc_intldst, opc_illegal, opc_illegal, opc_illegal, opc_illegal, opc_illegal, opc_illegal, opc_illegal, opc_illegal, opc_illegal, opc_illegal, opc_illegal, opc_illegal,