dingusppc/cpu/ppc/ppcdisasm.cpp

1726 lines
48 KiB
C++
Raw Normal View History

/** @file Logic for the disassembler.
@author maximumspatium
*/
#define _CRT_SECURE_NO_WARNINGS /* shut up MSVC regarding the unsafe strcpy/strcat */
2020-01-22 11:28:42 +00:00
#include <iostream>
#include <string>
2020-02-07 01:02:50 +00:00
#include <cstring>
#include <functional> /* without this, MSVC doesn't understand std::function */
2020-01-22 11:28:42 +00:00
#include "ppcdisasm.h"
using namespace std;
template< typename... Args >
std::string my_sprintf(const char* format, Args... args)
{
2020-01-22 11:28:42 +00:00
int length = std::snprintf(nullptr, 0, format, args...);
2020-01-22 11:28:42 +00:00
if (length <= 0)
return {}; /* empty string in C++11 */
char* buf = new char[length + 1];
std::snprintf(buf, length + 1, format, args...);
std::string str(buf);
delete[] buf;
return str;
}
2020-01-29 02:29:10 +00:00
const char* arith_im_mnem[9] = {
"mulli", "subfic", "", "", "", "addic", "addic.", "addi", "addis"
};
2020-01-22 11:28:42 +00:00
const char* bx_mnem[4] = {
2020-01-22 11:28:42 +00:00
"b", "bl", "ba", "bla"
};
2020-01-29 02:29:10 +00:00
const char* bclrx_mnem[2] = {
"blr", "blrl"
2020-01-29 02:29:10 +00:00
};
const char* bcctrx_mnem[2] = {
"bctr", "bctrl"
2020-01-29 02:29:10 +00:00
};
2020-01-22 11:28:42 +00:00
const char* br_cond[8] = { /* simplified branch conditions */
2020-01-22 11:28:42 +00:00
"ge", "le", "ne", "ns", "lt", "gt", "eq", "so"
};
2020-01-29 02:29:10 +00:00
const char* bclrx_cond[8] = { /* simplified branch conditions */
"gelr", "lelr", "nelr", "nslr", "ltlr", "gtlr", "eqlr", "solr"
};
const char* bcctrx_cond[8] = { /* simplified branch conditions */
"gectr", "lectr", "nectr", "nsctr", "ltctr", "gtctr", "eqctr", "soctr"
};
const char* opc_idx_ldst[32] = { /* indexed load/store opcodes */
"lwzx", "lwzux", "lbzx", "lbzux", "stwx", "stwux", "stbx", "stbux",
"lhzx", "lhzux", "lhax", "lhaux", "sthx", "sthux", "", "",
"lfsx", "lfsux", "lfdx", "lfdux", "stfsx", "stfsux", "stfdx", "stfdux",
"", "", "", "", "", "", "stfiwx", ""
2020-01-22 11:28:42 +00:00
};
2020-02-08 03:54:10 +00:00
const char* opc_bim_str[6] = { /* boolean immediate instructions */
"ori", "oris", "xori", "xoris", "andi.", "andis."
};
2020-01-22 11:28:42 +00:00
const char* opc_logic[16] = { /* indexed load/store opcodes */
2020-01-22 11:28:42 +00:00
"and", "andc", "", "nor", "", "", "", "", "eqv", "xor", "", "", "orc", "or",
"nand", ""
};
2020-01-22 11:28:42 +00:00
const char* opc_subs[16] = { /* subtracts & friends */
2020-01-22 11:28:42 +00:00
"subfc", "subf", "", "neg", "subfe", "", "subfze", "subfme", "doz", "", "",
"abs", "", "", "", "nabs"
};
2020-01-22 11:28:42 +00:00
const char* opc_adds[9] = { /* additions */
2020-01-22 11:28:42 +00:00
"addc", "", "", "", "adde", "", "addze", "addme", "add"
};
2020-01-22 11:28:42 +00:00
const char* opc_muldivs[16] = { /* multiply and division instructions */
2020-01-22 11:28:42 +00:00
"mulhwu", "", "mulhw", "mul", "", "", "", "mullw", "", "", "div", "divs",
"", "", "divwu", "divw"
};
const char* opc_shft_reg[32]{ /* Regular shift instructions */
"slw", "", "", "", "slq", "sliq", "sllq", "slliq",
"", "", "", "", "", "", "", "",
"srw", "", "", "", "srq", "sriq", "srlq", "srliq",
"sraw", "srawi", "", "", "sraq", "sraiq", "", ""
};
const char* opc_shft_ext[32]{ /* Extended shift instructions (601 only) */
"", "", "", "", "sle", "", "sleq", "",
"", "", "", "", "", "", "", "",
"rrib", "", "", "", "sre", "", "sreq", "",
"", "", "", "", "srea", "", "", ""
2020-02-13 03:06:26 +00:00
};
2020-01-29 02:29:10 +00:00
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"
};
2020-02-13 03:06:26 +00:00
/* processor management + byte reversed load and store */
const char* proc_mgmt_str[32] = {
2020-02-07 03:26:45 +00:00
"", "dcbst", "dcbf", "", "stwcx.", "", "", "dcbtst",
"dcbt", "eciwx", "", "", "", "ecowx", "dcbi", "",
"lwbrx", "tlbsync", "sync", "", "stwbrx", "", "", "dcba",
"lhbrx", "", "eieio", "", "sthbrx", "", "icbi", "dcbz"
};
const char* opc_flt_ldst[8] = { /* integer load and store instructions */
"lfs", "lfsu", "lfd", "lfdu", "stfs", "stfsu", "sftd", "sftdu"
};
2020-01-25 04:40:00 +00:00
const char* opc_flt_ext_arith[32] = { /* integer load and store instructions */
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "fsel",
"", "fmul", "", "", "fmsub", "fmadd", "fnmsub", "fnmadd",
};
const char* trap_cond[32] = { /*Trap conditions*/
"", "twlgt", "twllt", "", "tweq", "twlge", "twlle", "",
"twgt", "", "", "", "twge", "", "", "",
"twlt", "", "", "", "twle", "", "", "",
"twne", "", "", "", "", "", "", ""
};
2020-01-22 11:28:42 +00:00
/** various formatting helpers. */
2020-01-25 22:24:08 +00:00
void fmt_oneop(string& buf, const char* opc, int src)
{
buf = my_sprintf("%-8sr%d", opc, src);
}
2020-01-22 11:28:42 +00:00
void fmt_twoop(string& buf, const char* opc, int dst, int src)
2020-01-22 11:28:42 +00:00
{
buf = my_sprintf("%-8sr%d, r%d", opc, dst, src);
}
2020-01-29 02:29:10 +00:00
void fmt_twoop_simm(string& buf, const char* opc, int dst, int imm)
2020-01-25 22:24:08 +00:00
{
2020-01-29 02:29:10 +00:00
buf = my_sprintf("%-8sr%d, %s0x%X", opc, dst, (imm < 0) ? "-" : "", abs(imm));
2020-01-25 22:24:08 +00:00
}
void fmt_twoop_fromspr(string& buf, const char* opc, int dst, int src)
2020-01-25 04:40:00 +00:00
{
2020-02-06 05:33:49 +00:00
buf = my_sprintf("%-8sr%d, spr%d", opc, dst, src);
2020-01-25 22:24:08 +00:00
}
void fmt_twoop_tospr(string& buf, const char* opc, int dst, int src)
{
2020-02-06 05:33:49 +00:00
buf = my_sprintf("%-8sspr%d, r%d", opc, dst, src);
2020-01-25 04:40:00 +00:00
}
void fmt_twoop_flt(string& buf, const char* opc, int dst, int src1)
{
2020-02-14 04:04:14 +00:00
buf = my_sprintf("%-8sf%d, f%d", opc, dst, src1);
}
2020-01-22 11:28:42 +00:00
void fmt_threeop(string& buf, const char* opc, int dst, int src1, int src2)
2020-01-22 11:28:42 +00:00
{
buf = my_sprintf("%-8sr%d, r%d, r%d", opc, dst, src1, src2);
}
2020-01-29 02:29:10 +00:00
void fmt_threeop_crb(string& buf, const char* opc, int dst, int src1, int src2)
{
buf = my_sprintf("%-8scrb%d, crb%d, crb%d", opc, dst, src1, src2);
}
void fmt_threeop_uimm(string& buf, const char* opc, int dst, int src1, int imm)
2020-01-22 11:28:42 +00:00
{
buf = my_sprintf("%-8sr%d, r%d, 0x%04X", opc, dst, src1, imm);
}
2020-01-29 02:29:10 +00:00
void fmt_threeop_simm(string& buf, const char* opc, int dst, int src1, int imm)
2020-01-25 22:24:08 +00:00
{
2020-01-29 02:29:10 +00:00
buf = my_sprintf("%-8sr%d, r%d, %s0x%X", opc, dst, src1,
(imm < 0) ? "-" : "", abs(imm));
2020-01-25 22:24:08 +00:00
}
void fmt_threeop_flt(string& buf, const char* opc, int dst, int src1, int src2)
{
2020-02-14 04:04:14 +00:00
buf = my_sprintf("%-8sf%d, f%d, f%d", opc, dst, src1, src2);
}
void fmt_fourop_flt(string& buf, const char* opc, int dst, int src1, int src2, int src3)
{
2020-02-14 04:04:14 +00:00
buf = my_sprintf("%-8sf%d, f%d, f%d, f%d", opc, dst, src1, src2, src3);
}
2020-02-13 03:06:26 +00:00
void fmt_rotateop(string& buf, const char* opc, int dst, int src, int sh, int mb, int me, bool imm)
2020-01-25 04:40:00 +00:00
{
2020-01-25 22:24:08 +00:00
if (imm)
2020-02-13 03:06:26 +00:00
buf = my_sprintf("%-8sr%d, r%d, %d, %d, %d", opc, dst, src, sh, mb, me);
2020-01-25 22:24:08 +00:00
else
2020-02-13 03:06:26 +00:00
buf = my_sprintf("%-8sr%d, r%d, r%d, %d, %d", opc, dst, src, sh, mb, me);
2020-01-25 04:40:00 +00:00
}
2020-01-29 02:29:10 +00:00
2020-01-22 11:28:42 +00:00
void opc_illegal(PPCDisasmContext* ctx)
2020-01-22 11:28:42 +00:00
{
ctx->instr_str = my_sprintf("%-8s0x%08X", "dc.l", ctx->instr_code);
}
2020-01-22 11:28:42 +00:00
void opc_twi(PPCDisasmContext* ctx)
2020-01-22 11:28:42 +00:00
{
char opcode[10] = "";
auto to = (ctx->instr_code >> 21) & 0x1F;
auto ra = (ctx->instr_code >> 16) & 0x1F;
int32_t imm = SIGNEXT(ctx->instr_code & 0xFFFF, 15);
if (ctx->simplified) {
strcpy(opcode, trap_cond[to]);
2020-02-13 05:21:16 +00:00
if (strlen(opcode) > 0) {
strcat(opcode, "i");
ctx->instr_str = my_sprintf("%-8sr%d, 0x%08X", opcode, ra, imm);
2020-02-13 05:21:16 +00:00
return;
}
}
2020-02-13 05:21:16 +00:00
ctx->instr_str = my_sprintf("%-8s%d, r%d, 0x%08X", "twi", to, ra, imm);
2020-01-22 11:28:42 +00:00
}
2020-01-22 11:28:42 +00:00
void opc_group4(PPCDisasmContext* ctx)
2020-01-22 11:28:42 +00:00
{
printf("Altivec group 4 not supported yet\n");
}
2020-01-29 02:29:10 +00:00
void opc_ar_im(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);
2020-02-07 03:26:45 +00:00
if (ctx->simplified) {
if (((ctx->instr_code >> 26) == 0xE) & !ra) {
fmt_twoop_simm(ctx->instr_str, "li", rd, imm);
return;
}
else if (((ctx->instr_code >> 26) == 0xF) & !ra) {
fmt_twoop_simm(ctx->instr_str, "lis", rd, imm);
return;
}
if (imm > 0x7FFF) {
switch ((ctx->instr_code >> 26)) {
case 0xC:
fmt_threeop_simm(ctx->instr_str, "subic", rd, ra, imm);
return;
case 0xD:
fmt_threeop_simm(ctx->instr_str, "subic.", rd, ra, imm);
return;
case 0xE:
fmt_threeop_simm(ctx->instr_str, "subi", rd, ra, imm);
return;
case 0xF:
fmt_threeop_simm(ctx->instr_str, "subis", rd, ra, imm);
return;
}
}
2020-01-29 02:29:10 +00:00
}
2020-02-07 03:26:45 +00:00
fmt_threeop_simm(ctx->instr_str, arith_im_mnem[(ctx->instr_code >> 26) - 7],
rd, ra, imm);
2020-01-29 02:29:10 +00:00
}
void power_dozi(PPCDisasmContext* ctx)
{
auto ra = (ctx->instr_code >> 16) & 0x1F;
auto rd = (ctx->instr_code >> 21) & 0x1F;
auto imm = ctx->instr_code & 0xFFFF;
fmt_threeop_simm(ctx->instr_str, "dozi", rd, ra, imm);
}
2020-01-25 22:24:08 +00:00
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)
2020-02-13 03:06:26 +00:00
fmt_rotateop(ctx->instr_str, "rlwimi.", ra, rs, sh, mb, me, true);
2020-01-25 22:24:08 +00:00
else
2020-02-13 03:06:26 +00:00
fmt_rotateop(ctx->instr_str, "rlwimi", ra, rs, sh, mb, me, true);
2020-01-25 22:24:08 +00:00
}
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->simplified) {
if (mb == 0) {
if (me < 32) {
if (sh == (31 - me)) {
2020-02-13 03:58:51 +00:00
if (ctx->instr_code & 1)
fmt_threeop_simm(ctx->instr_str, "slwi.", rs, ra, sh);
else
fmt_threeop_simm(ctx->instr_str, "slwi", rs, ra, sh);
return;
}
if (sh == 0) {
fmt_threeop(ctx->instr_str, "clrrwi", rs, ra, mb);
return;
}
}
if (me == 31) {
fmt_threeop(ctx->instr_str, "rotlwi", rs, ra, sh);
return;
}
if (me > 0){
ctx->instr_str = my_sprintf("%-8sr%d, r%d, %d, %d", "extlwi", rs, ra, sh, me);
return;
}
}
}
2020-02-13 03:06:26 +00:00
2020-01-25 22:24:08 +00:00
if (ctx->instr_code & 1)
2020-02-13 03:06:26 +00:00
fmt_rotateop(ctx->instr_str, "rlwinm.", ra, rs, sh, mb, me, true);
2020-01-25 22:24:08 +00:00
else
2020-02-13 03:06:26 +00:00
fmt_rotateop(ctx->instr_str, "rlwinm", ra, rs, sh, mb, me, true);
2020-01-25 22:24:08 +00:00
}
void opc_rlmi(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)
2020-02-13 03:06:26 +00:00
fmt_rotateop(ctx->instr_str, "rlmi.", ra, rs, sh, mb, me, true);
else
2020-02-13 03:06:26 +00:00
fmt_rotateop(ctx->instr_str, "rlmi", ra, rs, sh, mb, me, true);
}
2020-01-25 22:24:08 +00:00
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;
2020-02-07 03:26:45 +00:00
if (ctx->simplified) {
if ((me == 31) & (mb == 0)) {
if (ctx->instr_code & 1) {
2020-02-13 03:06:26 +00:00
fmt_rotateop(ctx->instr_str, "rotlw.", ra, rs, rb, mb, me, false);
2020-02-07 03:26:45 +00:00
return;
}
else {
2020-02-13 03:06:26 +00:00
fmt_rotateop(ctx->instr_str, "rotlw", ra, rs, rb, mb, me, false);
2020-02-07 03:26:45 +00:00
return;
}
}
}
2020-01-25 22:24:08 +00:00
if (ctx->instr_code & 1)
2020-02-13 03:06:26 +00:00
fmt_rotateop(ctx->instr_str, "rlwnm.", ra, rs, rb, mb, me, false);
2020-01-25 22:24:08 +00:00
else
2020-02-13 03:06:26 +00:00
fmt_rotateop(ctx->instr_str, "rlwnm", ra, rs, rb, mb, me, false);
2020-01-25 22:24:08 +00:00
}
2020-01-29 02:29:10 +00:00
void opc_cmp_i_li(PPCDisasmContext* ctx)
2020-01-22 11:28:42 +00:00
{
auto ls = (ctx->instr_code >> 21) & 0x1;
2020-01-25 04:40:00 +00:00
auto ra = (ctx->instr_code >> 16) & 0x1F;
2020-01-29 02:29:10 +00:00
auto crfd = (ctx->instr_code >> 23) & 0x07;
2020-01-25 22:24:08 +00:00
auto imm = ctx->instr_code & 0xFFFF;
2020-01-25 04:40:00 +00:00
if ((ctx->instr_code >> 26) & 0x1)
ctx->instr_str = my_sprintf("%-8scr%d, %d, r%d, 0x%04X", "cmpi", crfd, ls, ra, imm);
else
ctx->instr_str = my_sprintf("%-8scr%d, %d, r%d, 0x%04X", "cmpli", crfd, ls, ra, imm);
2020-01-25 22:24:08 +00:00
}
2020-02-08 03:54:10 +00:00
void opc_bool_im(PPCDisasmContext* ctx)
{
char opcode[10];
auto ra = (ctx->instr_code >> 16) & 0x1F;
auto rs = (ctx->instr_code >> 21) & 0x1F;
auto index = ((ctx->instr_code >> 26) & 0x1F) - 24;
auto imm = ctx->instr_code & 0xFFFF;
if (ctx->simplified) {
if (index == 0) {
2020-02-10 04:55:24 +00:00
if (imm == 0 && !ra && !rs && !imm) { /* unofficial, produced by IDA */
ctx->instr_str = my_sprintf("%-8s", "nop");
2020-02-08 03:54:10 +00:00
return;
}
}
}
strcpy(opcode, opc_bim_str[index]);
fmt_threeop_uimm(ctx->instr_str, opcode, ra, rs, imm);
}
2020-01-29 02:29:10 +00:00
void generic_bcx(PPCDisasmContext* ctx, uint32_t bo, uint32_t bi, uint32_t dst)
2020-01-25 22:24:08 +00:00
{
2020-01-29 02:29:10 +00:00
char opcode[10] = "bc";
2020-01-25 22:24:08 +00:00
2020-01-29 02:29:10 +00:00
if (ctx->instr_code & 1) {
2020-02-06 14:01:27 +00:00
strcat(opcode, "l"); /* add suffix "l" if the LK bit is set */
2020-01-29 02:29:10 +00:00
}
if (ctx->instr_code & 2) {
2020-02-06 14:01:27 +00:00
strcat(opcode, "a"); /* add suffix "a" if the AA bit is set */
2020-01-29 02:29:10 +00:00
}
ctx->instr_str = my_sprintf("%-8s%d, %d, 0x%08X", opcode, bo, bi, dst);
2020-01-22 11:28:42 +00:00
}
2020-01-29 02:29:10 +00:00
void generic_bcctrx(PPCDisasmContext* ctx, uint32_t bo, uint32_t bi)
2020-01-22 11:28:42 +00:00
{
2020-01-29 02:29:10 +00:00
char opcode[10] = "bcctr";
2020-01-25 22:24:08 +00:00
2020-01-29 02:29:10 +00:00
if (ctx->instr_code & 1) {
2020-02-06 14:01:27 +00:00
strcat(opcode, "l"); /* add suffix "l" if the LK bit is set */
2020-01-29 02:29:10 +00:00
}
2020-01-25 22:24:08 +00:00
2020-01-29 02:29:10 +00:00
ctx->instr_str = my_sprintf("%-8s%d, %d, 0x%08X", opcode, bo, bi);
2020-01-25 04:40:00 +00:00
}
2020-01-29 02:29:10 +00:00
void generic_bclrx(PPCDisasmContext* ctx, uint32_t bo, uint32_t bi)
2020-01-25 04:40:00 +00:00
{
2020-01-29 02:29:10 +00:00
char opcode[10] = "bclr";
2020-01-25 22:24:08 +00:00
2020-01-29 02:29:10 +00:00
if (ctx->instr_code & 1) {
2020-02-06 14:01:27 +00:00
strcat(opcode, "l"); /* add suffix "l" if the LK bit is set */
2020-01-29 02:29:10 +00:00
}
2020-01-25 22:24:08 +00:00
2020-01-29 02:29:10 +00:00
ctx->instr_str = my_sprintf("%-8s%d, %d, 0x%08X", opcode, bo, bi);
2020-01-25 22:24:08 +00:00
}
2020-01-29 02:29:10 +00:00
void opc_bcx(PPCDisasmContext* ctx)
2020-01-25 22:24:08 +00:00
{
2020-01-29 02:29:10 +00:00
uint32_t bo, bi, dst, cr;
char opcode[10] = "b";
char operands[12] = "";
2020-01-25 22:24:08 +00:00
2020-01-29 02:29:10 +00:00
bo = (ctx->instr_code >> 21) & 0x1F;
bi = (ctx->instr_code >> 16) & 0x1F;
cr = bi >> 2;
dst = ((ctx->instr_code & 2) ? 0 : ctx->instr_addr) +
SIGNEXT(ctx->instr_code & 0xFFFC, 15);
2020-01-25 22:24:08 +00:00
2020-01-29 02:29:10 +00:00
if (!ctx->simplified || ((bo & 0x10) && bi) ||
(((bo & 0x14) == 0x14) && (bo & 0xB) && bi)) {
generic_bcx(ctx, bo, bi, dst);
return;
}
2020-01-25 22:24:08 +00:00
2020-01-29 02:29:10 +00:00
if ((bo & 0x14) == 0x14) {
ctx->instr_str = my_sprintf("%-8s0x%08X", bx_mnem[0], dst);
return;
}
2020-01-25 22:24:08 +00:00
2020-01-29 02:29:10 +00:00
if (!(bo & 4)) {
2020-02-06 14:01:27 +00:00
strcat(opcode, "d");
strcat(opcode, (bo & 2) ? "z" : "nz");
2020-01-29 02:29:10 +00:00
if (!(bo & 0x10)) {
2020-02-06 14:01:27 +00:00
strcat(opcode, (bo & 8) ? "t" : "f");
2020-01-29 02:29:10 +00:00
if (cr) {
2020-02-06 14:01:27 +00:00
strcat(operands, "4*cr0+");
2020-01-29 02:29:10 +00:00
operands[4] = cr + '0';
}
2020-02-06 14:01:27 +00:00
strcat(operands, br_cond[4 + (bi & 3)]);
strcat(operands, ", ");
2020-01-29 02:29:10 +00:00
}
}
else { /* CTR ignored */
2020-02-06 14:01:27 +00:00
strcat(opcode, br_cond[((bo >> 1) & 4) | (bi & 3)]);
2020-01-29 02:29:10 +00:00
if (cr) {
2020-02-06 14:01:27 +00:00
strcat(operands, "cr0, ");
2020-01-29 02:29:10 +00:00
operands[2] = cr + '0';
}
}
2020-01-25 22:24:08 +00:00
2020-01-29 02:29:10 +00:00
if (ctx->instr_code & 1) {
2020-02-06 14:01:27 +00:00
strcat(opcode, "l"); /* add suffix "l" if the LK bit is set */
2020-01-29 02:29:10 +00:00
}
if (ctx->instr_code & 2) {
2020-02-06 14:01:27 +00:00
strcat(opcode, "a"); /* add suffix "a" if the AA bit is set */
2020-01-29 02:29:10 +00:00
}
if (bo & 1) { /* incorporate prediction bit if set */
2020-02-06 14:01:27 +00:00
strcat(opcode, (ctx->instr_code & 0x8000) ? "-" : "+");
2020-01-29 02:29:10 +00:00
}
ctx->instr_str = my_sprintf("%-8s%s0x%08X", opcode, operands, dst);
2020-01-25 22:24:08 +00:00
}
2020-01-29 02:29:10 +00:00
void opc_bcctrx(PPCDisasmContext* ctx)
2020-01-25 22:24:08 +00:00
{
2020-01-29 02:29:10 +00:00
uint32_t bo, bi, cr;
char opcode[10] = "b";
char operands[4] = "";
2020-01-25 22:24:08 +00:00
2020-01-29 02:29:10 +00:00
bo = (ctx->instr_code >> 21) & 0x1F;
bi = (ctx->instr_code >> 16) & 0x1F;
cr = bi >> 2;
2020-01-25 22:24:08 +00:00
if (!(bo & 4)) { /* bcctr with BO[2] = 0 is invalid */
opc_illegal(ctx);
}
2020-01-29 02:29:10 +00:00
if (!ctx->simplified || ((bo & 0x10) && bi) ||
(((bo & 0x14) == 0x14) && (bo & 0xB) && bi)) {
generic_bcctrx(ctx, bo, bi);
return;
}
2020-01-25 22:24:08 +00:00
2020-01-29 02:29:10 +00:00
if ((bo & 0x14) == 0x14) {
ctx->instr_str = my_sprintf("%-8s", bcctrx_mnem[ctx->instr_code & 1]);
2020-01-29 02:29:10 +00:00
return;
}
2020-01-25 04:40:00 +00:00
strcat(opcode, br_cond[((bo >> 1) & 4) | (bi & 3)]);
strcat(opcode, "ctr");
if (cr) {
strcat(operands, "cr0");
operands[2] = cr + '0';
2020-01-29 02:29:10 +00:00
}
2020-01-22 11:28:42 +00:00
if (ctx->instr_code & 1) {
2020-02-06 14:01:27 +00:00
strcat(opcode, "l"); /* add suffix "l" if the LK bit is set */
2020-01-22 11:28:42 +00:00
}
2020-01-29 02:29:10 +00:00
if (bo & 1) { /* incorporate prediction bit if set */
strcat(opcode, "+");
2020-01-22 11:28:42 +00:00
}
2020-01-29 02:29:10 +00:00
ctx->instr_str = my_sprintf("%-8s%s", opcode, operands);
2020-01-22 11:28:42 +00:00
}
2020-01-29 02:29:10 +00:00
void opc_bclrx(PPCDisasmContext* ctx)
2020-01-22 11:28:42 +00:00
{
2020-01-29 02:29:10 +00:00
uint32_t bo, bi, cr;
2020-01-22 11:28:42 +00:00
char opcode[10] = "b";
char operands[12] = "";
2020-01-22 11:28:42 +00:00
2020-01-22 11:28:42 +00:00
bo = (ctx->instr_code >> 21) & 0x1F;
bi = (ctx->instr_code >> 16) & 0x1F;
cr = bi >> 2;
2020-01-22 11:28:42 +00:00
if (!ctx->simplified || ((bo & 0x10) && bi) ||
(((bo & 0x14) == 0x14) && (bo & 0xB) && bi)) {
generic_bclrx(ctx, bo, bi);
2020-01-22 11:28:42 +00:00
return;
}
if ((bo & 0x14) == 0x14) {
ctx->instr_str = my_sprintf("%-8s", bclrx_mnem[ctx->instr_code & 1]);
2020-01-22 11:28:42 +00:00
return;
}
if (!(bo & 4)) {
2020-02-06 14:01:27 +00:00
strcat(opcode, "d");
strcat(opcode, (bo & 2) ? "z" : "nz");
2020-01-22 11:28:42 +00:00
if (!(bo & 0x10)) {
strcat(opcode, (bo & 8) ? "t" : "f");
2020-01-22 11:28:42 +00:00
if (cr) {
2020-02-06 14:01:27 +00:00
strcat(operands, "4*cr0+");
2020-01-22 11:28:42 +00:00
operands[4] = cr + '0';
}
2020-02-06 14:01:27 +00:00
strcat(operands, br_cond[4 + (bi & 3)]);
2020-01-22 11:28:42 +00:00
}
2020-01-22 11:28:42 +00:00
}
else { /* CTR ignored */
2020-02-06 14:01:27 +00:00
strcat(opcode, br_cond[((bo >> 1) & 4) | (bi & 3)]);
2020-01-22 11:28:42 +00:00
if (cr) {
strcat(operands, "cr0");
2020-01-22 11:28:42 +00:00
operands[2] = cr + '0';
}
}
strcat(opcode, "lr");
2020-01-22 11:28:42 +00:00
if (ctx->instr_code & 1) {
2020-02-06 14:01:27 +00:00
strcat(opcode, "l"); /* add suffix "l" if the LK bit is set */
2020-01-22 11:28:42 +00:00
}
if (bo & 1) { /* incorporate prediction bit if set */
strcat(opcode, "+");
2020-01-22 11:28:42 +00:00
}
ctx->instr_str = my_sprintf("%-8s%s", opcode, operands);
2020-01-22 11:28:42 +00:00
}
2020-01-22 11:28:42 +00:00
void opc_bx(PPCDisasmContext* ctx)
2020-01-22 11:28:42 +00:00
{
uint32_t dst = ((ctx->instr_code & 2) ? 0 : ctx->instr_addr)
2020-01-22 11:28:42 +00:00
+ SIGNEXT(ctx->instr_code & 0x3FFFFFC, 25);
2020-01-22 11:28:42 +00:00
ctx->instr_str = my_sprintf("%-8s0x%08X", bx_mnem[ctx->instr_code & 3], dst);
}
2020-01-29 02:29:10 +00:00
void opc_ori(PPCDisasmContext* ctx)
2020-01-25 22:24:08 +00:00
{
auto ra = (ctx->instr_code >> 16) & 0x1F;
auto rs = (ctx->instr_code >> 21) & 0x1F;
auto imm = ctx->instr_code & 0xFFFF;
2020-01-29 02:29:10 +00:00
if (!ra && !rs && !imm && ctx->simplified) {
ctx->instr_str = my_sprintf("%-8s", "nop");
2020-01-29 02:29:10 +00:00
return;
}
if (imm == 0 && ctx->simplified) { /* inofficial, produced by IDA */
fmt_twoop(ctx->instr_str, "mr", ra, rs);
return;
}
fmt_threeop_uimm(ctx->instr_str, "ori", ra, rs, imm);
2020-01-25 22:24:08 +00:00
}
2020-01-29 02:29:10 +00:00
void opc_oris(PPCDisasmContext* ctx)
2020-01-25 22:24:08 +00:00
{
auto ra = (ctx->instr_code >> 16) & 0x1F;
auto rs = (ctx->instr_code >> 21) & 0x1F;
auto imm = ctx->instr_code & 0xFFFF;
2020-01-29 02:29:10 +00:00
fmt_threeop_uimm(ctx->instr_str, "oris", ra, rs, imm);
2020-01-25 22:24:08 +00:00
}
2020-01-29 02:29:10 +00:00
void opc_xori(PPCDisasmContext* ctx)
2020-01-22 11:28:42 +00:00
{
2020-01-22 11:28:42 +00:00
auto ra = (ctx->instr_code >> 16) & 0x1F;
auto rs = (ctx->instr_code >> 21) & 0x1F;
2020-01-22 11:28:42 +00:00
auto imm = ctx->instr_code & 0xFFFF;
2020-01-29 02:29:10 +00:00
fmt_threeop_uimm(ctx->instr_str, "xori", ra, rs, imm);
2020-01-25 22:24:08 +00:00
}
2020-01-29 02:29:10 +00:00
void opc_xoris(PPCDisasmContext* ctx)
2020-01-25 22:24:08 +00:00
{
auto ra = (ctx->instr_code >> 16) & 0x1F;
auto rs = (ctx->instr_code >> 21) & 0x1F;
auto imm = ctx->instr_code & 0xFFFF;
2020-01-29 02:29:10 +00:00
fmt_threeop_uimm(ctx->instr_str, "xoris", ra, rs, imm);
2020-01-25 22:24:08 +00:00
}
2020-01-29 02:29:10 +00:00
void opc_andidot(PPCDisasmContext* ctx)
2020-01-25 22:24:08 +00:00
{
auto ra = (ctx->instr_code >> 16) & 0x1F;
auto rs = (ctx->instr_code >> 21) & 0x1F;
auto imm = ctx->instr_code & 0xFFFF;
2020-01-29 02:29:10 +00:00
fmt_threeop_uimm(ctx->instr_str, "andi.", ra, rs, imm);
2020-01-25 22:24:08 +00:00
}
2020-01-29 02:29:10 +00:00
void opc_andisdot(PPCDisasmContext* ctx)
2020-01-25 22:24:08 +00:00
{
auto ra = (ctx->instr_code >> 16) & 0x1F;
auto rs = (ctx->instr_code >> 21) & 0x1F;
auto imm = ctx->instr_code & 0xFFFF;
2020-01-29 02:29:10 +00:00
fmt_threeop_uimm(ctx->instr_str, "andis.", ra, rs, imm);
}
void opc_sc(PPCDisasmContext* ctx)
{
ctx->instr_str = my_sprintf("%-8s", "sc");
2020-01-25 22:24:08 +00:00
}
void opc_group19(PPCDisasmContext* ctx)
{
2020-01-29 02:29:10 +00:00
auto rb = (ctx->instr_code >> 11) & 0x1F;
auto ra = (ctx->instr_code >> 16) & 0x1F;
auto rs = (ctx->instr_code >> 21) & 0x1F;
int ext_opc = (ctx->instr_code >> 1) & 0x3FF; /* extract extended opcode */
2020-01-25 22:24:08 +00:00
2020-01-29 02:29:10 +00:00
switch (ext_opc) {
case 0:
ctx->instr_str = my_sprintf("%-8scr%d, cr%d", "mcrf", (rs >> 2), (ra >> 2));
2020-01-29 02:29:10 +00:00
return;
case 16:
opc_bclrx(ctx);
return;
case 33:
2020-02-08 03:54:10 +00:00
if (ctx->simplified && (ra == rb)) {
ctx->instr_str = my_sprintf("%-8scrb%d, crb%d", "crnot", rs, ra);
}
2020-01-29 02:29:10 +00:00
fmt_threeop_crb(ctx->instr_str, "crnor", rs, ra, rb);
return;
case 50:
2020-02-13 03:06:26 +00:00
ctx->instr_str = my_sprintf("%-8s", "rfi");
2020-01-29 02:29:10 +00:00
return;
case 129:
fmt_threeop_crb(ctx->instr_str, "crandc", rs, ra, rb);
return;
case 150:
2020-02-13 03:06:26 +00:00
ctx->instr_str = my_sprintf("%-8s", "isync");
2020-01-29 02:29:10 +00:00
return;
case 193:
2020-02-07 03:26:45 +00:00
if (ctx->simplified && (rs == ra) && (rs == rb)) {
ctx->instr_str = my_sprintf("%-8scrb%d", "crclr", rs);
}
2020-02-08 03:54:10 +00:00
fmt_threeop_crb(ctx->instr_str, "crxor", rs, ra, rb);
2020-01-29 02:29:10 +00:00
return;
case 225:
fmt_threeop_crb(ctx->instr_str, "crnand", rs, ra, rb);
return;
case 257:
fmt_threeop_crb(ctx->instr_str, "crand", rs, ra, rb);
return;
case 289:
2020-02-08 03:54:10 +00:00
if (ctx->simplified && (rs == ra) && (rs == rb)) {
ctx->instr_str = my_sprintf("%-8scrb%d", "crset", rs);
return;
}
2020-01-29 02:29:10 +00:00
fmt_threeop_crb(ctx->instr_str, "creqv", rs, ra, rb);
return;
case 417:
fmt_threeop_crb(ctx->instr_str, "crorc", rs, ra, rb);
return;
case 449:
2020-02-08 03:54:10 +00:00
if (ctx->simplified && (ra == rb)) {
ctx->instr_str = my_sprintf("%-8scrb%d, crb%d", "crmove", rs, ra);
return;
}
2020-01-29 02:29:10 +00:00
fmt_threeop_crb(ctx->instr_str, "cror", rs, ra, rb);
return;
case 528:
opc_bcctrx(ctx);
return;
}
2020-01-22 11:28:42 +00:00
}
2020-01-29 02:29:10 +00:00
2020-01-22 11:28:42 +00:00
void opc_group31(PPCDisasmContext* ctx)
2020-01-22 11:28:42 +00:00
{
char opcode[10] = "";
auto rb = (ctx->instr_code >> 11) & 0x1F;
auto ra = (ctx->instr_code >> 16) & 0x1F;
auto rs = (ctx->instr_code >> 21) & 0x1F;
int ext_opc = (ctx->instr_code >> 1) & 0x3FF; /* extract extended opcode */
2020-01-22 11:28:42 +00:00
int index = ext_opc >> 5;
bool rc_set = ctx->instr_code & 1;
2020-01-22 11:28:42 +00:00
2020-01-22 11:28:42 +00:00
switch (ext_opc & 0x1F) {
case 8: /* subtracts & friends */
index &= 0xF; /* strip OE bit */
if (!strlen(opc_subs[index])) {
opc_illegal(ctx);
}
else {
2020-02-06 14:01:27 +00:00
strcpy(opcode, opc_subs[index]);
2020-01-22 11:28:42 +00:00
if (ext_opc & 0x200) /* check OE bit */
2020-02-06 14:01:27 +00:00
strcat(opcode, "o");
2020-01-22 11:28:42 +00:00
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
2020-01-22 11:28:42 +00:00
if (index == 3 || index == 6 || index == 7 || index == 11 ||
index == 15) { /* ugly check for two-operands instructions */
if (rb != 0)
2020-01-22 11:28:42 +00:00
opc_illegal(ctx);
else
2020-01-22 11:28:42 +00:00
fmt_twoop(ctx->instr_str, opcode, rs, ra);
2020-01-22 11:28:42 +00:00
}
2020-01-22 11:28:42 +00:00
else
fmt_threeop(ctx->instr_str, opcode, rs, ra, rb);
}
return;
2020-01-22 11:28:42 +00:00
2020-01-22 11:28:42 +00:00
case 10: /* additions */
index &= 0xF; /* strip OE bit */
if (index > 8 || !strlen(opc_adds[index])) {
opc_illegal(ctx);
}
else {
2020-02-06 14:01:27 +00:00
strcpy(opcode, opc_adds[index]);
2020-01-22 11:28:42 +00:00
if (ext_opc & 0x200) /* check OE bit */
2020-02-06 14:01:27 +00:00
strcat(opcode, "o");
2020-01-22 11:28:42 +00:00
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
2020-01-22 11:28:42 +00:00
if (index == 6 || index == 7) {
if (rb != 0)
2020-01-22 11:28:42 +00:00
opc_illegal(ctx);
2020-01-22 11:28:42 +00:00
else
fmt_twoop(ctx->instr_str, opcode, rs, ra);
2020-01-22 11:28:42 +00:00
}
else
2020-01-22 11:28:42 +00:00
fmt_threeop(ctx->instr_str, opcode, rs, ra, rb);
}
return;
2020-01-25 04:40:00 +00:00
2020-01-22 11:28:42 +00:00
case 11: /* integer multiplications and divisions */
index &= 0xF; /* strip OE bit */
if (!strlen(opc_muldivs[index])) {
opc_illegal(ctx);
}
else {
2020-02-06 14:01:27 +00:00
strcpy(opcode, opc_muldivs[index]);
2020-01-22 11:28:42 +00:00
if (ext_opc & 0x200) /* check OE bit */
2020-02-06 14:01:27 +00:00
strcat(opcode, "o");
2020-01-22 11:28:42 +00:00
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
2020-01-22 11:28:42 +00:00
if ((!index || index == 2) && (ext_opc & 0x200))
2020-01-22 11:28:42 +00:00
opc_illegal(ctx);
else
2020-02-08 03:54:10 +00:00
fmt_threeop(ctx->instr_str, opcode, rs, ra, rb);
2020-01-22 11:28:42 +00:00
}
return;
2020-02-07 03:26:45 +00:00
case 0x12: /* tlb instructions */
if (index == 11) {
if (!rs & !ra & !rb)
opc_illegal(ctx);
else
ctx->instr_str = my_sprintf("%-8s", "tlbia");
2020-02-07 03:26:45 +00:00
}
else if (index == 18) {
if (!rs & !ra)
opc_illegal(ctx);
else
ctx->instr_str = my_sprintf("%-8sr%s", "tlbie", rb);
2020-02-07 03:26:45 +00:00
}
else if (index == 30) { /* tlbld - 603 only */
if (!rs & !ra)
opc_illegal(ctx);
else
ctx->instr_str = my_sprintf("%-8sr%s", "tlbld", rb);
}
else if (index == 30) { /* tlbli - 603 only */
if (!rs & !ra)
opc_illegal(ctx);
else
ctx->instr_str = my_sprintf("%-8sr%s", "tlbli", rb);
}
2020-02-07 03:26:45 +00:00
return;
case 0x18: /* Shifting instructions */
strcpy(opcode, opc_shft_reg[index]);
if (rc_set)
strcat(opcode, ".");
2020-02-13 03:26:12 +00:00
switch (index) {
case 0: case 4: case 6: case 16:
case 20: case 22: case 24: case 28:
2020-02-13 03:26:12 +00:00
fmt_threeop(ctx->instr_str, opcode, ra, rs, rb);
break;
case 5: case 7: case 21: case 23:
case 25: case 29:
2020-02-13 03:26:12 +00:00
fmt_threeop_simm(ctx->instr_str, opcode, ra, rs, rb);
break;
default:
opc_illegal(ctx);
}
return;
case 0x19: /* (Extended) Shifting instructions - 601 only*/
strcpy(opcode, opc_shft_ext[index]);
if (rc_set)
strcat(opcode, ".");
switch (index) {
case 4: case 6: case 16:
case 20: case 22: case 28:
fmt_threeop(ctx->instr_str, opcode, rs, ra, rb);
default:
opc_illegal(ctx);
}
2020-02-07 03:26:45 +00:00
return;
2020-02-06 05:33:49 +00:00
case 0x1A: /* Byte sign extend instructions */
2020-02-06 05:33:49 +00:00
if (index == 28)
strcpy(opcode, "extsh");
2020-02-06 05:33:49 +00:00
else if (index == 29)
strcpy(opcode, "extsb");
if (rc_set)
strcat(opcode, ".");
fmt_twoop(ctx->instr_str, opcode, rs, ra);
2020-02-06 05:33:49 +00:00
return;
2020-01-22 11:28:42 +00:00
case 0x1C: /* logical instructions */
if (index == 13 && rs == rb && ctx->simplified) {
fmt_twoop(ctx->instr_str, rc_set ? "mr." : "mr", ra, rs);
}
else {
2020-02-06 14:01:27 +00:00
strcpy(opcode, opc_logic[index]);
2020-01-22 11:28:42 +00:00
if (!strlen(opcode)) {
2020-01-22 11:28:42 +00:00
opc_illegal(ctx);
2020-01-22 11:28:42 +00:00
}
2020-01-22 11:28:42 +00:00
else {
2020-01-22 11:28:42 +00:00
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
2020-01-22 11:28:42 +00:00
fmt_threeop(ctx->instr_str, opcode, ra, rs, rb);
2020-01-22 11:28:42 +00:00
}
2020-01-22 11:28:42 +00:00
}
return;
2020-02-07 03:26:45 +00:00
2020-01-22 11:28:42 +00:00
case 0x17: /* indexed load/store instructions */
2020-02-14 04:04:14 +00:00
if (index == 30) { /* stfiwx sneaks in here */
if (rc_set) {
opc_illegal(ctx);
return;
}
else {
if (ra == 0)
ctx->instr_str = my_sprintf("%-8sf%d, 0, r%d", opc_idx_ldst[index], rs, rb);
else {
ctx->instr_str = my_sprintf("%-8sf%d, r%d, r%d", opc_idx_ldst[index], rs, ra, rb);
}
return;
}
}
2020-01-22 11:28:42 +00:00
if (index > 23 || rc_set || strlen(opc_idx_ldst[index]) == 0) {
opc_illegal(ctx);
return;
}
if (index < 16) {
2020-02-14 04:04:14 +00:00
fmt_threeop(ctx->instr_str, opc_idx_ldst[index], rs, ra, rb);
}
else {
2020-02-14 04:04:14 +00:00
ctx->instr_str = my_sprintf("%-8sfp%d, r%d, r%d", \
2020-01-22 11:28:42 +00:00
opc_idx_ldst[index], rs, ra, rb);
}
2020-01-22 11:28:42 +00:00
return;
2020-02-07 03:26:45 +00:00
case 0x16: /* processor mgmt + byte reversed load and store instructions */
strcpy(opcode, proc_mgmt_str[index]);
if (index == 4){ /* stwcx.*/
2020-02-13 03:58:51 +00:00
if (!rc_set) {
opc_illegal(ctx);
return;
}
else {
if (ra == 0)
ctx->instr_str = my_sprintf("%-8sr%d, 0, r%d", opcode, rs, rb);
else
fmt_threeop(ctx->instr_str, opcode, rs, ra, rb);
return;
}
}
/* eciwx, ecowx, lhbrx, lwbrx, stwbrx, sthbrx */
else if ((index == 9) | (index == 13) | (index == 16) \
2020-02-07 03:26:45 +00:00
| (index == 20) | (index == 24) | (index == 28)) {
if (rc_set) {
opc_illegal(ctx);
return;
}
else {
if (ra == 0)
ctx->instr_str = my_sprintf("%-8sr%d, 0, r%d", opcode, rs, rb);
else
fmt_threeop(ctx->instr_str, opcode, rs, ra, rb);
return;
}
2020-02-07 03:26:45 +00:00
}
else if ((index == 18) | (index == 26)) { /* sync, eieio */
2020-02-07 03:26:45 +00:00
ctx->instr_str = my_sprintf("%-8s", opcode);
return;
}
2020-02-14 04:04:14 +00:00
/* dcba, dcbf, dcbi, dcbst, dcbt, dcbz */
else if ((index == 1) | (index == 2) | (index == 7) \
| (index == 8) | (index == 14) \
2020-02-14 04:04:14 +00:00
| (index == 23) | (index == 31)) {
if (rc_set | (rs != 0)) {
opc_illegal(ctx);
return;
}
else {
if (ra == 0)
ctx->instr_str = my_sprintf("%-8sr%d, 0, r%d", opcode, rb);
else
fmt_twoop(ctx->instr_str, opcode, ra, rb);
return;
}
}
2020-02-14 04:04:14 +00:00
else if (index == 30) { /* icbi */
if (rs == 0)
opc_illegal(ctx);
else
fmt_twoop(ctx->instr_str, opcode, ra, rb);
}
else if (index == 17) { /* tlbsync */
ctx->instr_str = my_sprintf("%-8s", opcode);
}
2020-02-07 03:26:45 +00:00
else {
opc_illegal(ctx);
2020-02-07 03:26:45 +00:00
}
return;
2020-01-22 11:28:42 +00:00
break;
2020-01-22 11:28:42 +00:00
}
2020-01-25 22:24:08 +00:00
auto ref_spr = (((ctx->instr_code >> 11) & 31) << 5) | ((ctx->instr_code >> 16) & 31);
2020-01-22 11:28:42 +00:00
switch (ext_opc) {
case 0: /* cmp */
if (rc_set)
opc_illegal(ctx);
else
2020-02-14 04:04:14 +00:00
ctx->instr_str = my_sprintf("%-8scr%d, %d, r%d, r%d", "cmp", (rs >> 2), (rs & 1), ra, rb);
break;
case 4: /* tw */
if (rc_set) {
2020-01-22 11:28:42 +00:00
opc_illegal(ctx);
}
else {
if (ctx->simplified) {
strcpy(opcode, trap_cond[rs]);
2020-02-13 03:58:51 +00:00
if (strlen(opcode) != 0) {
ctx->instr_str = my_sprintf("%-8sr%d, r%d", opcode, ra, rb);
2020-02-14 04:04:14 +00:00
break;
}
}
2020-02-13 03:58:51 +00:00
ctx->instr_str = my_sprintf("%-8s%d, r%d, r%d", "tw", rs, ra, rb);
}
2020-01-22 11:28:42 +00:00
break;
2020-01-25 22:24:08 +00:00
case 19: /* mfcr */
fmt_oneop(ctx->instr_str, "mfcr", rs);
break;
case 20: /* lwarx */
if (rc_set) {
opc_illegal(ctx);
}
else {
if (ra == 0)
ctx->instr_str = my_sprintf("%-8sr%d, 0, r%d", "lwarx", rs, rb);
else
fmt_threeop(ctx->instr_str, "lwarx", rs, ra, rb);
}
break;
case 26: /* cntlzw */
2020-02-14 04:04:14 +00:00
printf("CASE REACH! \n");
if (rc_set)
2020-02-14 04:04:14 +00:00
fmt_twoop(ctx->instr_str, "cntlzw.", rs, ra);
else
fmt_twoop(ctx->instr_str, "cntlzw", rs, ra);
break;
case 29: /* maskg */
strcpy(opcode, "maskg");
if (rc_set)
strcat(opcode, ".");
fmt_threeop(ctx->instr_str, opcode, rs, ra, rb);
break;
2020-02-06 05:33:49 +00:00
case 32: /* cmpl */
if (rc_set)
opc_illegal(ctx);
else
2020-02-14 04:04:14 +00:00
ctx->instr_str = my_sprintf("%-8scr%d, %d, r%d, r%d", "cmpl", (rs >> 2), (rs & 1), ra, rb);
break;
2020-01-29 02:29:10 +00:00
case 83: /* mfmsr */
2020-02-07 03:26:45 +00:00
ctx->instr_str = my_sprintf("%-8sr%d", "mfmsr",
2020-01-29 02:29:10 +00:00
(ctx->instr_code >> 21) & 0x1F);
break;
2020-01-22 11:28:42 +00:00
case 144: /* mtcrf */
if (ctx->instr_code & 0x100801)
opc_illegal(ctx);
else {
ctx->instr_str = my_sprintf("%-8s0x%02X, r%d", "mtcrf",
(ctx->instr_code >> 12) & 0xFF, rs);
}
break;
2020-01-25 22:24:08 +00:00
case 146: /* mtmsr */
fmt_oneop(ctx->instr_str, "mtmsr", rs);
break;
2020-02-14 04:04:14 +00:00
case 210: /* mtsr */
if (ra & 16)
opc_illegal(ctx);
else
ctx->instr_str = my_sprintf("%-8%d, r%d", "mtsr", ra, rs);
break;
case 242: /* mtsrin */
if (rb & 16)
opc_illegal(ctx);
else
ctx->instr_str = my_sprintf("%-8r%d, r%d", "mtsr", rs, rb);
break;
case 277: /* lscbx */
strcpy(opcode, "lscbx");
if (rc_set)
strcat(opcode, ".");
fmt_threeop(ctx->instr_str, opcode, rs, ra, rb);
break;
2020-01-25 22:24:08 +00:00
case 339: /* mfspr */
2020-02-07 03:26:45 +00:00
if (ctx->simplified) {
switch (ref_spr) {
case 0: //case 0 is 601 only
ctx->instr_str = my_sprintf("%-8sr%d", "mfmq", rs);
return;
2020-02-07 03:26:45 +00:00
case 1:
ctx->instr_str = my_sprintf("%-8sr%d", "mfxer", rs);
return;
case 8:
ctx->instr_str = my_sprintf("%-8sr%d", "mflr", rs);
return;
case 9:
ctx->instr_str = my_sprintf("%-8sr%d", "mfctr", rs);
return;
case 18:
ctx->instr_str = my_sprintf("%-8sr%d", "mfdsisr", rs);
return;
case 19:
ctx->instr_str = my_sprintf("%-8sr%d", "mfdar", rs);
return;
case 22:
ctx->instr_str = my_sprintf("%-8sr%d", "mfdec", rs);
return;
2020-02-07 03:26:45 +00:00
}
}
2020-01-25 22:24:08 +00:00
fmt_twoop_fromspr(ctx->instr_str, "mfspr", rs, ref_spr);
break;
case 371: /* mftb */
fmt_twoop_tospr(ctx->instr_str, "mftb", ref_spr, rs);
break;
2020-01-25 22:24:08 +00:00
case 467: /* mtspr */
2020-02-07 03:26:45 +00:00
if (ctx->simplified) {
switch (ref_spr) {
case 0: //case 0 is 601 only
ctx->instr_str = my_sprintf("%-8sr%d", "mtmq", rs);
return;
2020-02-07 03:26:45 +00:00
case 1:
ctx->instr_str = my_sprintf("%-8sr%d", "mtxer", rs);
return;
case 8:
ctx->instr_str = my_sprintf("%-8sr%d", "mtlr", rs);
return;
case 9:
ctx->instr_str = my_sprintf("%-8sr%d", "mtctr", rs);
return;
case 18:
ctx->instr_str = my_sprintf("%-8sr%d", "mtdsisr", rs);
return;
case 19:
ctx->instr_str = my_sprintf("%-8sr%d", "mtdar", rs);
return;
case 27:
ctx->instr_str = my_sprintf("%-8sr%d", "mtdec", rs);
return;
2020-02-07 03:26:45 +00:00
}
}
2020-01-25 22:24:08 +00:00
fmt_twoop_tospr(ctx->instr_str, "mtspr", ref_spr, rs);
break;
2020-02-07 14:54:15 +00:00
case 512: /* mcrxr */
ctx->instr_str = my_sprintf("%-8scr%d", "mcrxr", (rs >> 2));
2020-02-07 14:54:15 +00:00
break;
case 531: /* clcs */
strcpy(opcode, "clcs");
if (rc_set)
strcat(opcode, ".");
2020-02-14 04:04:14 +00:00
fmt_twoop(ctx->instr_str, opcode, rs, ra);
break;
2020-02-07 03:26:45 +00:00
case 533: /* lswx */
if (rc_set) {
opc_illegal(ctx);
}
else {
if (ra == 0)
ctx->instr_str = my_sprintf("%-8sr%d, 0, r%d", "lswx", rs, rb);
else
fmt_threeop(ctx->instr_str, "lswx", rs, ra, rb);
}
2020-02-07 03:26:45 +00:00
break;
case 541: /* maskir */
strcpy(opcode, "maskir");
if (rc_set)
strcat(opcode, ".");
2020-02-14 04:04:14 +00:00
fmt_threeop(ctx->instr_str, opcode, ra, rs, rb);
return;
2020-02-07 03:26:45 +00:00
case 597: /* lswi */
if (rc_set) {
opc_illegal(ctx);
}
else {
2020-02-14 04:04:14 +00:00
if (rb == 0)
rb = 32;
if (ra == 0)
ctx->instr_str = my_sprintf("%-8sr%d, 0, %x", "lswi", rs, rb);
else
fmt_threeop_simm(ctx->instr_str, "lswi", rs, ra, rb);
}
break;
case 661: /* stswx */
if (rc_set) {
opc_illegal(ctx);
return;
}
else {
if (ra == 0)
ctx->instr_str = my_sprintf("%-8sr%d, 0, r%d", "stswx", rs, rb);
else
fmt_threeop(ctx->instr_str, "stswx", rs, ra, rb);
return;
}
break;
case 725: /* stswi */
if (rc_set) {
opc_illegal(ctx);
return;
}
else {
2020-02-14 04:04:14 +00:00
if (rb == 0)
rb = 32;
if (ra == 0)
ctx->instr_str = my_sprintf("%-8sr%d, 0, %d", "stswi", rs, rb);
else
fmt_threeop_simm(ctx->instr_str, "stswi", rs, ra, rb);
return;
}
break;
default:
opc_illegal(ctx);
}
}
void opc_group59(PPCDisasmContext* ctx)
{
char opcode[10] = "";
auto rc = (ctx->instr_code >> 6) & 0x1F;
auto rb = (ctx->instr_code >> 11) & 0x1F;
auto ra = (ctx->instr_code >> 16) & 0x1F;
auto rs = (ctx->instr_code >> 21) & 0x1F;
int ext_opc = (ctx->instr_code >> 1) & 0x3FF; /* extract extended opcode */
bool rc_set = ctx->instr_code & 1;
switch (ext_opc & 0x1F) {
case 18: /* floating point division */
2020-02-06 14:01:27 +00:00
strcpy(opcode, "fdivs");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
if (rc != 0)
opc_illegal(ctx);
else
fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rb);
return;
case 20: /* floating point subtract */
2020-02-06 14:01:27 +00:00
strcpy(opcode, "fsubs");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
if (rc != 0)
opc_illegal(ctx);
else
fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rb);
return;
case 21: /* floating point addition */
2020-02-06 14:01:27 +00:00
strcpy(opcode, "fadds");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
if (rc != 0)
opc_illegal(ctx);
else
fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rb);
return;
case 22: /* floating point square root */
2020-02-06 14:01:27 +00:00
strcpy(opcode, "fsqrts");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
if ((rc != 0) | (ra != 0))
opc_illegal(ctx);
else
fmt_twoop_flt(ctx->instr_str, "fsqrts", rs, rb);
return;
case 24: /* fres */
2020-02-06 14:01:27 +00:00
strcpy(opcode, "fres");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
if ((rc != 0) | (ra != 0))
opc_illegal(ctx);
else
fmt_twoop_flt(ctx->instr_str, opcode, rs, rb);
return;
case 25: /* fmuls */
2020-02-06 14:01:27 +00:00
strcpy(opcode, opc_flt_ext_arith[25]);
strcat(opcode, "s");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
if (rb != 0)
opc_illegal(ctx);
else
fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rc);
return;
case 28: /* fmsubs */
2020-02-06 14:01:27 +00:00
strcpy(opcode, opc_flt_ext_arith[28]);
strcat(opcode, "s");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
2020-02-14 04:04:14 +00:00
fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb);
return;
case 29: /* fmadds */
2020-02-06 14:01:27 +00:00
strcpy(opcode, opc_flt_ext_arith[29]);
strcat(opcode, "s");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
2020-02-14 04:04:14 +00:00
fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb);
return;
case 30: /* fnmsubs */
2020-02-06 14:01:27 +00:00
strcpy(opcode, opc_flt_ext_arith[30]);
strcat(opcode, "s");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
2020-02-14 04:04:14 +00:00
fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb);
return;
case 31: /* fnmadds */
2020-02-06 14:01:27 +00:00
strcpy(opcode, opc_flt_ext_arith[31]);
strcat(opcode, "s");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
2020-02-14 04:04:14 +00:00
fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb);
return;
}
}
void opc_group63(PPCDisasmContext* ctx)
{
char opcode[10] = "";
auto rc = (ctx->instr_code >> 6) & 0x1F;
auto rb = (ctx->instr_code >> 11) & 0x1F;
auto ra = (ctx->instr_code >> 16) & 0x1F;
auto rs = (ctx->instr_code >> 21) & 0x1F;
int ext_opc = (ctx->instr_code >> 1) & 0x3FF; /* extract extended opcode */
bool rc_set = ctx->instr_code & 1;
switch (ext_opc & 0x1F) {
case 18: /* floating point division */
2020-02-06 14:01:27 +00:00
strcpy(opcode, "fdiv");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
if (rc != 0)
opc_illegal(ctx);
else
fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rb);
return;
case 20: /* floating point subtract */
2020-02-06 14:01:27 +00:00
strcpy(opcode, "fsub");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
if (rc != 0)
opc_illegal(ctx);
else
fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rb);
return;
case 21: /* floating point addition */
2020-02-06 14:01:27 +00:00
strcpy(opcode, "fadd");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
if (rc != 0)
opc_illegal(ctx);
else
fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rb);
return;
case 22: /* floating point square root */
2020-02-06 14:01:27 +00:00
strcpy(opcode, "fsqrt");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
if ((rc != 0) | (ra != 0))
opc_illegal(ctx);
else
fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rb);
return;
2020-02-07 03:26:45 +00:00
case 23: /* fsel */
strcpy(opcode, "fsel");
if (rc_set)
strcat(opcode, ".");
2020-02-07 03:26:45 +00:00
if ((rc != 0) | (ra != 0))
opc_illegal(ctx);
else
fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rb, rc);
return;
case 25: /* fmul */
2020-02-06 14:01:27 +00:00
strcpy(opcode, opc_flt_ext_arith[25]);
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
if (rb != 0)
opc_illegal(ctx);
else
fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rc);
return;
case 26: /* frsqrte */
2020-02-06 14:01:27 +00:00
strcpy(opcode, "frsqrte");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
if ((rc != 0) | (ra != 0))
opc_illegal(ctx);
else
2020-02-14 04:04:14 +00:00
ctx->instr_str = my_sprintf("%-8sf%d, f%d", opcode, rs, rb);
return;
case 28: /* fmsub */
2020-02-06 14:01:27 +00:00
strcpy(opcode, opc_flt_ext_arith[28]);
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
2020-02-14 04:04:14 +00:00
fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb);
return;
case 29: /* fmadd */
2020-02-06 14:01:27 +00:00
strcpy(opcode, opc_flt_ext_arith[29]);
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
2020-02-14 04:04:14 +00:00
fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb);
return;
case 30: /* fnmsub */
2020-02-06 14:01:27 +00:00
strcpy(opcode, opc_flt_ext_arith[30]);
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
2020-02-14 04:04:14 +00:00
fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb);
return;
case 31: /* fnmadd */
2020-02-06 14:01:27 +00:00
strcpy(opcode, opc_flt_ext_arith[31]);
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
2020-02-14 04:04:14 +00:00
fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb);
return;
}
auto fm = (ctx->instr_code >> 17) & 0xFF;
switch (ext_opc) {
case 0: /* fcmpu */
if (rs & 3)
opc_illegal(ctx);
else
2020-02-14 04:04:14 +00:00
ctx->instr_str = my_sprintf("%-8scr%d, f%d, f%d", "fcmpu", (rs >> 2), ra, rb);
break;
case 12: /* frsp */
if (ra != 0)
opc_illegal(ctx);
else
ctx->instr_str = my_sprintf("%-8s%d, r%d, r%d", "frsp", rs, rb);
break;
case 14: /* fctiw */
if (ra != 0)
opc_illegal(ctx);
else
ctx->instr_str = my_sprintf("%-8s%d, r%d, r%d", "fctiw", rs, rb);
break;
case 15: /* fctiwz */
if (ra != 0)
opc_illegal(ctx);
else
ctx->instr_str = my_sprintf("%-8s%d, r%d, r%d", "fctiwz", rs, rb);
break;
case 32: /* fcmpo */
if (rs & 3)
opc_illegal(ctx);
else
2020-02-14 04:04:14 +00:00
ctx->instr_str = my_sprintf("%-8scr%d, f%d, f%d", "fcmpo", (rs >> 2), ra, rb);
2020-02-07 03:26:45 +00:00
break;
case 38: /* mtfsb1 */
strcpy(opcode, "mtfsb1");
if (rc_set)
strcat(opcode, ".");
2020-02-14 04:04:14 +00:00
ctx->instr_str = my_sprintf("%-8s%d", opcode, rs);
break;
case 40: /* fneg */
2020-02-06 14:01:27 +00:00
strcpy(opcode, "fneg");
if (rc_set)
2020-02-06 14:01:27 +00:00
strcat(opcode, ".");
if (ra != 0)
opc_illegal(ctx);
else
ctx->instr_str = my_sprintf("%-8sr%d, r%d", opcode, rs, rb);
break;
2020-02-07 14:54:15 +00:00
case 64:
strcpy(opcode, "mcrfs");
ctx->instr_str = my_sprintf("%-8scr%d, cr%d", opcode, (rs >> 2), (ra >> 2));
2020-02-07 14:54:15 +00:00
break;
2020-02-07 03:26:45 +00:00
case 70: /* mtfsb0 */
strcpy(opcode, "mtfsb0");
if (rc_set)
strcat(opcode, ".");
ctx->instr_str = my_sprintf("%-8scrb%d", opcode, rs);
break;
case 72: /* fmr */
if (ra != 0)
opc_illegal(ctx);
else
ctx->instr_str = my_sprintf("%-8sr%d, r%d", "fmr", rs, rb);
break;
case 134: /* mtfsfi */
if (ra != 0)
opc_illegal(ctx);
else
ctx->instr_str = my_sprintf("%-8scr%d, r%d", "mtfsfi", (rs >> 2), (rb >> 1));
break;
case 136: /* fnabs */
if (ra != 0)
opc_illegal(ctx);
else
2020-02-14 04:04:14 +00:00
ctx->instr_str = my_sprintf("%-8sf%d, f%d", "fnabs", rs, rb);
break;
case 264: /* fabs */
if (ra != 0)
opc_illegal(ctx);
else
2020-02-14 04:04:14 +00:00
ctx->instr_str = my_sprintf("%-8s%d, f%d, f%d", "fabs", rs, rb);
break;
2020-02-07 14:54:15 +00:00
case 583: /* mffs */
strcpy(opcode, "mffs");
if (rc_set)
strcat(opcode, ".");
if ((ra != 0) | (rb != 0))
opc_illegal(ctx);
else
2020-02-14 04:04:14 +00:00
ctx->instr_str = my_sprintf("%-8sf%d", opcode, rs);
break;
case 711: /* mtfsf */
ctx->instr_str = my_sprintf("%-8sfm%d, r%d", "mtfsf", fm, rb);
break;
2020-01-22 11:28:42 +00:00
default:
opc_illegal(ctx);
}
}
2020-01-29 02:29:10 +00:00
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));
}
}
void opc_fltldst(PPCDisasmContext* ctx)
{
int32_t opcode = (ctx->instr_code >> 26) - 48;
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 == 1) || (opcode == 3)) && ra == rd) || ((opcode & 1) && !ra))
{
opc_illegal(ctx);
return;
}
if (ra) {
2020-02-14 04:04:14 +00:00
ctx->instr_str = my_sprintf("%-8sf%d, %s0x%X(r%d)", opc_flt_ldst[opcode],
rd, ((imm < 0) ? "-" : ""), abs(imm), ra);
}
else {
2020-02-14 04:04:14 +00:00
ctx->instr_str = my_sprintf("%-8sf%d, %s0x%X", opc_flt_ldst[opcode],
rd, ((imm < 0) ? "-" : ""), abs(imm));
}
}
2020-01-22 11:28:42 +00:00
/** main dispatch table. */
static std::function<void(PPCDisasmContext*)> OpcodeDispatchTable[64] = {
opc_illegal, opc_illegal, opc_illegal, opc_twi,
2020-01-29 02:29:10 +00:00
opc_group4, opc_illegal, opc_illegal, opc_ar_im,
opc_ar_im, power_dozi, opc_cmp_i_li, opc_cmp_i_li,
opc_ar_im, opc_ar_im, opc_ar_im, opc_ar_im,
opc_bcx, opc_sc, opc_bx, opc_group19,
opc_rlwimi, opc_rlwinm, opc_rlmi, opc_rlwnm,
2020-02-08 03:54:10 +00:00
opc_bool_im, opc_bool_im, opc_bool_im, opc_bool_im,
opc_bool_im, opc_bool_im, opc_illegal, opc_group31,
2020-01-29 02:29:10 +00:00
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_fltldst, opc_fltldst, opc_fltldst, opc_fltldst,
opc_fltldst, opc_fltldst, opc_fltldst, opc_fltldst,
opc_illegal, opc_illegal, opc_illegal, opc_group59,
opc_illegal, opc_illegal, opc_illegal, opc_group63
2020-01-22 11:28:42 +00:00
};
2020-01-22 11:28:42 +00:00
string disassemble_single(PPCDisasmContext* ctx)
2020-01-22 11:28:42 +00:00
{
OpcodeDispatchTable[ctx->instr_code >> 26](ctx);
ctx->instr_addr += 4;
return ctx->instr_str;
2020-02-13 03:06:26 +00:00
}