/* radare - LGPL - Copyright 2015-2024 - pancake */

#include <r_lib.h>
#include <r_asm.h>
#include <r_util.h>
#include <r_flag.h>
#include <r_anal.h>
#include <r_asm.h>

#define SPR_MQ          0x0
#define SPR_XER         0x1
#define SPR_RTCU        0x4
#define SPR_RTCL        0x5
#define SPR_LR          0x8
#define SPR_CTR         0x9
#define SPR_DSISR       0x12
#define SPR_DAR         0x13
#define SPR_DEC         0x16
#define SPR_SDR1        0x19
#define SPR_SRR0        0x1a
#define SPR_SRR1        0x1b
#define SPR_VRSAVE      0x100
#define SPR_TBRL        0x10c
#define SPR_TBRU        0x10d
#define SPR_SPRG0       0x110
#define SPR_SPRG1       0x111
#define SPR_SPRG2       0x112
#define SPR_SPRG3       0x113
#define SPR_EAR         0x11a
#define SPR_TBL         0x11c
#define SPR_TBU         0x11d
#define SPR_PVR         0x11f
#define SPR_SPEFSCR     0x200
#define SPR_IBAT0U      0x210
#define SPR_IBAT0L      0x211
#define SPR_IBAT1U      0x212
#define SPR_IBAT1L      0x213
#define SPR_IBAT2U      0x214
#define SPR_IBAT2L      0x215
#define SPR_IBAT3U      0x216
#define SPR_IBAT3L      0x217
#define SPR_DBAT0U      0x218
#define SPR_DBAT0L      0x219
#define SPR_DBAT1U      0x21a
#define SPR_DBAT1L      0x21b
#define SPR_DBAT2U      0x21c
#define SPR_DBAT2L      0x21d
#define SPR_DBAT3U      0x21e
#define SPR_DBAT3L      0x21f
#define SPR_UMMCR0      0x3a8
#define SPR_UMMCR1      0x3ac
#define SPR_UPMC1       0x3a9
#define SPR_UPMC2       0x3aa
#define SPR_USIA        0x3ab
#define SPR_UPMC3       0x3ad
#define SPR_UPMC4       0x3ae
#define SPR_MMCR0       0x3b8
#define SPR_PMC1        0x3b9
#define SPR_PMC2        0x3ba
#define SPR_SIA         0x3bb
#define SPR_MMCR1       0x3bc
#define SPR_PMC3        0x3bd
#define SPR_PMC4        0x3be
#define SPR_SDA         0x3bf
#define SPR_DMISS       0x3d0
#define SPR_DCMP        0x3d1
#define SPR_HASH1       0x3d2
#define SPR_HASH2       0x3d3
#define SPR_IMISS       0x3d4
#define SPR_ICMP        0x3d5
#define SPR_RPA         0x3d6
#define SPR_HID0        0x3f0 /* Hardware Implementation Register 0 */
#define SPR_HID1        0x3f1 /* Hardware Implementation Register 1 */
#define SPR_IABR        0x3f2
#define SPR_HID2        0x3f3 /* Hardware Implementation Register 2 */
#define SPR_HID4        0x3f4 /* Hardware Implementation Register 4 */
#define SPR_DABR        0x3f5
#define SPR_HID5        0x3f6 /* Hardware Implementation Register 5 */
#define SPR_HID6        0x3f9 /* Hardware Implementation Register 6 */
//#define SPR_L2CR        0x3f9
#define SPR_ICTC        0x3fb
#define SPR_THRM1       0x3fc
#define SPR_THRM2       0x3fd
#define SPR_THRM3       0x3fe
#define SPR_PIR         0x3ff

#define PPC_UT64(x) (strtol(x, NULL, 16))

static ut64 mask64(ut64 mb, ut64 me) {
	ut64 maskmb = UT64_MAX >> mb;
	ut64 maskme = UT64_MAX << (63 - me);
	return (mb <= me) ? maskmb & maskme : maskmb | maskme;
}

static int can_replace(const char *str, int idx, int max_operands) {
	if (str[idx] < 'A' || str[idx] > 'J') {
		return false;
	}
	if (str[idx + 1] != '\x00' && str[idx + 1] <= 'J' && str[idx + 1] >= 'A') {
		return false;
	}
	if ((int)((int)str[idx] - 0x41) > max_operands) {
		return false;
	}
	return true;
}

// cmp* and the cr0 conditional branches: b{eq,ge,gt,le,lt,ne} with an optional +/- hint
static bool op_needs_cr0(const char *op) {
	if (r_str_startswith (op, "cmp")) {
		return true;
	}
	if (op[0] != 'b' || !op[1] || !op[2] || (op[3] && (op[4] || !strchr ("+-", op[3])))) {
		return false;
	}
	const char cond[] = { op[1], op[2], 0 };
	return strstr ("eq ge gt le lt ne", cond) != NULL;
}

// only td/tdi/tw/twi carry a TO code operand, every named form (tweq, tdlgt, tdu..) encodes it in the mnemonic
static bool op_is_trap(const char *op) {
	return !strcmp (op, "td") || !strcmp (op, "tdi") || !strcmp (op, "tw") || !strcmp (op, "twi");
}

static const char* getspr(const char *reg) {
	static R_TH_LOCAL char cspr[16];
	ut32 spr = 0;
	if (!reg) {
		return NULL;
	}
	spr = strtol(reg, NULL, 16);
	if (spr > 9999) {
		return NULL; //just to avoid overflows..
	}

	switch (spr) {
	case SPR_MQ:
		return "mq";
	case SPR_XER:
		return "xer";
	case SPR_RTCU:
		return "rtcu";
	case SPR_RTCL:
		return "rtcl";
	case SPR_LR:
		return "lr";
	case SPR_CTR:
		return "ctr";
	case SPR_DSISR:
		return "dsisr";
	case SPR_DAR:
		return "dar";
	case SPR_DEC:
		return "dec";
	case SPR_SDR1:
		return "sdr1";
	case SPR_SRR0:
		return "srr0";
	case SPR_SRR1:
		return "srr1";
	case SPR_VRSAVE:
		return "vrsave";
	case SPR_TBRL:
		return "tbrl";
	case SPR_TBRU:
		return "tbru";
	case SPR_SPRG0:
		return "sprg0";
	case SPR_SPRG1:
		return "sprg1";
	case SPR_SPRG2:
		return "sprg2";
	case SPR_SPRG3:
		return "sprg3";
	case SPR_EAR:
		return "ear";
	case SPR_TBL:
		return "tbl";
	case SPR_TBU:
		return "tbu";
	case SPR_PVR:
		return "pvr";
	case SPR_SPEFSCR:
		return "spefscr";
	case SPR_IBAT0U:
		return "ibat0u";
	case SPR_IBAT0L:
		return "ibat0l";
	case SPR_IBAT1U:
		return "ibat1u";
	case SPR_IBAT1L:
		return "ibat1l";
	case SPR_IBAT2U:
		return "ibat2u";
	case SPR_IBAT2L:
		return "ibat2l";
	case SPR_IBAT3U:
		return "ibat3u";
	case SPR_IBAT3L:
		return "ibat3l";
	case SPR_DBAT0U:
		return "dbat0u";
	case SPR_DBAT0L:
		return "dbat0l";
	case SPR_DBAT1U:
		return "dbat1u";
	case SPR_DBAT1L:
		return "dbat1l";
	case SPR_DBAT2U:
		return "dbat2u";
	case SPR_DBAT2L:
		return "dbat2l";
	case SPR_DBAT3U:
		return "dbat3u";
	case SPR_DBAT3L:
		return "dbat3l";
	case SPR_UMMCR0:
		return "ummcr0";
	case SPR_UMMCR1:
		return "ummcr1";
	case SPR_UPMC1:
		return "upmc1";
	case SPR_UPMC2:
		return "upmc2";
	case SPR_USIA:
		return "usia";
	case SPR_UPMC3:
		return "upmc3";
	case SPR_UPMC4:
		return "upmc4";
	case SPR_MMCR0:
		return "mmcr0";
	case SPR_PMC1:
		return "pmc1";
	case SPR_PMC2:
		return "pmc2";
	case SPR_SIA:
		return "sia";
	case SPR_MMCR1:
		return "mmcr1";
	case SPR_PMC3:
		return "pmc3";
	case SPR_PMC4:
		return "pmc4";
	case SPR_SDA:
		return "sda";
	case SPR_DMISS:
		return "dmiss";
	case SPR_DCMP:
		return "dcmp";
	case SPR_HASH1:
		return "hash1";
	case SPR_HASH2:
		return "hash2";
	case SPR_IMISS:
		return "imiss";
	case SPR_ICMP:
		return "icmp";
	case SPR_RPA:
		return "rpa";
	case SPR_HID0:
		return "hid0";
	case SPR_HID1:
		return "hid1";
	case SPR_IABR:
		return "iabr";
	case SPR_HID2:
		return "hid2";
	case SPR_HID4:
		return "hid4";
	case SPR_DABR:
		return "dabr";
	case SPR_HID5:
		return "hid5";
	case SPR_HID6:
		return "hid6";
//		case SPR_L2CR:
//			return "l2cr";
	case SPR_ICTC:
		return "ictc";
	case SPR_THRM1:
		return "thrm1";
	case SPR_THRM2:
		return "thrm2";
	case SPR_THRM3:
		return "thrm3";
	case SPR_PIR:
		return "pir";
	default:
		snprintf (cspr, sizeof (cspr), "spr_%u", spr);
		break;
	}
	return cspr;
}

static char *replace(int argc, const char *argv[]) {
	int i, j;
	static struct {
		const char *op;
		const char *str;
		int max_operands;
	} ops[] = {
		{ "cmpb", "A = ((byte) B == (byte) C)", 3},
		{ "cmpd", "A = (B == C)", 3},
		{ "cmpdi", "A = (B == C)", 3},
		{ "cmpld", "A = ((unsigned) B == (unsigned) C)", 3},
		{ "cmpldi", "A = ((unsigned) B == (unsigned) C)", 3},
		{ "cmplw", "A = ((unsigned) B == (unsigned) C)", 3},
		{ "cmplwi", "A = ((unsigned) B == (unsigned) C)", 3},
		{ "cmpw", "A = (B == C)", 3},
		{ "cmpwi", "A = (B == C)", 3},
		{ "beq", "if (A & FLG_EQ) goto B", 2},
		{ "beq-", "if (A & FLG_EQ) goto B", 2},
		{ "beq+", "if (A & FLG_EQ) goto B", 2},
		{ "bge", "if (A & FLG_GE) goto B", 2},
		{ "bge-", "if (A & FLG_GE) goto B", 2},
		{ "bge+", "if (A & FLG_GE) goto B", 2},
		{ "bgt", "if (A & FLG_GT) goto B", 2},
		{ "bgt-", "if (A & FLG_GT) goto B", 2},
		{ "bgt+", "if (A & FLG_GT) goto B", 2},
		{ "ble", "if (A & FLG_LE) goto B", 2},
		{ "ble-", "if (A & FLG_LE) goto B", 2},
		{ "ble+", "if (A & FLG_LE) goto B", 2},
		{ "blt", "if (A & FLG_LT) goto B", 2},
		{ "blt-", "if (A & FLG_LT) goto B", 2},
		{ "blt+", "if (A & FLG_LT) goto B", 2},
		{ "bne", "if (A & FLG_NE) goto B", 2},
		{ "bne-", "if (A & FLG_NE) goto B", 2},
		{ "bne+", "if (A & FLG_NE) goto B", 2},
		{ "rldic", "A = rol64(B, C) & D", 4},
		{ "rldcl", "A = rol64(B, C) & D", 4},
		{ "rldicl", "A = rol64(B, C) & D", 4},
		{ "rldcr", "A = rol64(B, C) & D", 4},
		{ "rldicr", "A = rol64(B, C) & D", 4},
		{ "rldimi", "A = (rol64(B, C) & D) | (A & E)", 5},
		{ "rlwimi", "A = (rol32(B, C) & D) | (A & E)", 5},
		{ "rlwimi.", "A = (rol32(B, C) & D) | (A & E)", 5},
		{ "rlwinm", "A = rol32(B, C) & D", 5},
		{ "rlwinm.", "A = rol32(B, C) & D", 5},
		{ "rlwnm", "A = rol32(B, C) & D", 5},
		{ "rlwnm.", "A = rol32(B, C) & D", 5},
		{ "td", "if (B A C) trap", 3},
		{ "tdi", "if (B A C) trap", 3},
		{ "tdu", "trap", 0},
		{ "tdui", "trap", 0},
		{ "tw", "if ((word) B A (word) C) trap", 3},
		{ "twi", "if ((word) B A (word) C) trap", 3},
		{ "twu", "trap", 0},
		{ "twui", "trap", 0},
		{ "mfspr", "A = B", 2},
		{ "mtspr", "A = B", 2},
		{ "add", "A = B + C", 3},
		{ "addc", "A = B + C", 3},
		{ "adde", "A = B + C", 3},
		{ "addi", "A = B + C", 3},
		{ "addic", "A = B + C", 3},
		{ "addis", "A = B + (C << 16)", 3},
		{ "addme", "A = B - A", 2},
		{ "addze", "A = zero extended(B)", 2},
		{ "and", "A = B & C", 3},
		{ "andc", "A = B & C", 3},
		{ "andi", "A = B & C", 3},
		{ "andis", "A = B & (C << 16)", 3},
		{ "attn", "attention A", 1},
		{ "b", "goto A", 1},
		{ "ba", "goto A", 1},
		// only branch-always forms keep the bc spelling (see ppc_cs)
		{ "bc", "goto C", 3},
		{ "bca", "goto C", 3},
		//{ "bcctr", "if (a ?? b) goto ctr", 2},
		//{ "bcctrl", "if (a ?? b) goto ctr", 2},
		{ "bcl", "lr = pc + 4; goto C", 3},
		{ "bcla", "lr = pc + 4; goto C", 3},
		//{ "bclr", "if (a ?? b) goto C", 3},
		//{ "bclrl", "if (a ?? b) call C", 3},
		{ "bct", "goto ct", 0},
		{ "bctr", "goto ctr", 3},
		{ "bctrl", "call ctr", 3},
		{ "bdnz", "if (ctr != 0) goto A", 1},
		{ "bdnza", "if (ctr != 0) goto A", 1},
		{ "bdnzf", "if (ctr != 0 && !A) goto B", 2},
		{ "bdnzfa", "if (ctr != 0 && !A) goto B", 2},
		{ "bdnzfl", "if (ctr != 0 && !A) call B", 2},
		{ "bdnzfla", "if (ctr != 0 && !A) call B", 2},
		{ "bdnzflr", "if (ctr != 0 && !A) return", 1},
		{ "bdnzflrl", "if (ctr != 0 && !A) return", 1},
		{ "bdnzl", "if (ctr != 0) call A", 1},
		{ "bdnzla", "if (ctr != 0) call A", 1},
		{ "bdnzlr", "if (ctr != 0) return", 0},
		{ "bdnzlrl", "if (ctr != 0) return", 0},
		{ "bdnzt", "if (ctr != 0 && A) goto B", 2},
		{ "bdnzta", "if (ctr != 0 && A) goto B", 2},
		{ "bdnztl", "if (ctr != 0 && A) call B", 2},
		{ "bdnztla", "if (ctr != 0 && A) call B", 2},
		{ "bdnztlr", "if (ctr != 0 && A) return", 1},
		{ "bdnztlrl", "if (ctr != 0 && A) return", 1},
		{ "bdz", "if (ctr == 0) goto A", 1},
		{ "bdza", "if (ctr == 0) goto A", 1},
		{ "bdzf", "if (ctr == 0 && !A) goto B", 2},
		{ "bdzfa", "if (ctr == 0 && !A) goto B", 2},
		{ "bdzfl", "if (ctr == 0 && !A) call B", 2},
		{ "bdzfla", "if (ctr == 0 && !A) call B", 2},
		{ "bdzflr", "if (ctr == 0 && !A) return", 1},
		{ "bdzflrl", "if (ctr == 0 && !A) return", 1},
		{ "bdzl", "if (ctr == 0) call A", 1},
		{ "bdzla", "if (ctr == 0) call A", 1},
		{ "bdzlr", "if (ctr == 0) return", 0},
		{ "bdzlrl", "if (ctr == 0) return", 0},
		{ "bdzt", "if (ctr == 0 && A) goto B", 2},
		{ "bdzta", "if (ctr == 0 && A) goto B", 2},
		{ "bdztl", "if (ctr == 0 && A) call B", 2},
		{ "bdztla", "if (ctr == 0 && A) call B", 2},
		{ "bdztlr", "if (ctr == 0 && A) return", 1},
		{ "bdztlrl", "if (ctr == 0 && A) return", 1},
		{ "bf", "if (!cond) goto A", 1},
		{ "bfa", "if (!cond) goto A", 1},
		{ "bfctr", "if (!cond) goto ctr", 0},
		{ "bfctrl", "if (!cond) call ctr", 0},
		{ "bfl", "if (!cond) call A", 1},
		{ "bfla", "if (!cond) call A", 1},
		{ "bflr", "if (!cond) call A", 1},
		{ "bflrl", "if (!cond) call A", 1},
		{ "bl", "call A", 1},
		{ "bla", "call A", 1},
		{ "blr", "return", 0},
		{ "blrl", "return", 0},
		{ "bltlr", "if (A & FLG_LT) return", 1},
		{ "blelr", "if (A & FLG_LE) return", 1},
		{ "bgtlr", "if (A & FLG_GT) return", 1},
		{ "bgelr", "if (A & FLG_GE) return", 1},
		{ "bnelr", "if (A & FLG_NE) return", 1},
		{ "beqlr", "if (A & FLG_EQ) return", 1},
		{ "brinc", "A = bit_revese(B, C)", 3},
		{ "bt", "if (cond) goto A", 1},
		{ "bta", "if (cond) goto A", 1},
		{ "btctr", "if (cond) goto ctr", 1},
		{ "btctrl", "if (cond) call ctr", 1},
		{ "btl", "if (cond) call A", 1},
		{ "btla", "if (cond) call A", 1},
		{ "btlr", "if (cond) call A", 1},
		{ "btlrl", "if (cond) call A", 1},
		{ "clrldi", "A = B & mask(0, C)", 2},
		{ "clrlwi", "A = B & mask(0, C)", 2},
		{ "cntlzd", "A = cnt_leading_zeros(B)", 2},
		{ "cntlzw", "A = cnt_leading_zeros(B)", 2},
		{ "crand", "A = B & C", 3},
		{ "crandc", "A = B & C", 3},
		{ "crclr", "A = A ^ A", 1},
		{ "creqv", "A = B == C", 3},
		{ "crmove", "A = B", 2},
		{ "crnand", "A = B & !C", 3},
		{ "crnor", "A = B | !C", 3},
		{ "crnot", "A = !B", 2},
		{ "cror", "A = B | C", 3},
		{ "crorc", "A = B | C", 3},
		{ "crset", "A = B", 2},
		{ "crxor", "A = B ^ C", 3},
		{ "dcba", "dcb_alloc(A,B)", 2},
		{ "dcbf", "dcb_flush(A,B)", 2},
		{ "dcbi", "dcb_inval(A,B)", 2},
		{ "dcbst", "dcb_store(A,B)", 2},
		{ "dcbt", "dcb_touch(A,B)", 2},
		{ "dcbtst", "dcb_touch_store(A, B)", 2},
		{ "dcbz", "dcb_zero(A,B)", 2},
		{ "dcbzl", "dcb_zero_line(A, B)", 2},
		{ "dccci", "dcc_inval(A, B)", 3}, // Data Cache Congruence Class Invalidate
		{ "divd", "A = B / C", 3},
		{ "divdu", "A = (unsigned) B / C", 3},
		{ "divw", "A = (word) B / C", 3},
		{ "divwu", "A = (word unsigned) B / C", 3},
		{ "dss", "altivec_ds_stop(A)", 1},
		{ "dssall", "altivec_ds_stop_all", 0},
		{ "dst", "altivec_ds_touch(A,B,C)", 3},
		{ "dstst", "altivec_ds_touch_store(A, B, C)", 3},
		{ "dststt", "altivec_ds_touch_store_tran(A, B, C)", 3},
		{ "dstt", "altivec_ds_touch_tran(A, B, C)", 3},
		{ "eieio", "enforce_in_order_exec_io", 0},
		{ "eqv", "A = B ^ C", 3},
		{ "evabs", "A = (vector) abs(B)", 2},
		{ "evaddiw", "A =  (vector) B + C", 3},
		{ "evaddsmiaaw", "A =  (vector) B + C", 3},
		{ "evaddssiaaw", "A = (vector) B + C", 3},
		{ "evaddumiaaw", "A = (vector) B + C", 3},
		{ "evaddusiaaw", "A = (vector) B + C", 3},
		{ "evaddw", "A = (vector) B + C", 3},
		{ "evand", "A = (vector) B + C", 3},
		{ "evandc", "A = (vector) B + C", 3},
		{ "evcmpeq", "A = (vector) B == C", 3},
		{ "evcmpgts", "A = (vector) B > C", 3},
		{ "evcmpgtu", "A = (unsigned vector) B > C", 3},
		{ "evcmplts", "A = (vector) B < C", 3},
		{ "evcmpltu", "A =  (unsigned vector) B <> C", 3},
		{ "evcntlsw", "A = (vector) cnt_sign_bits(B)", 2},
		{ "evcntlzw", "A = (vector) cnt_zero_bits(B)", 2},
		{ "evdivws", "A = (vector) B / C", 3},
		{ "evdivwu", "A = (unsigned vector) B + C", 3},
		{ "eveqv", "A = (vector) B ^ C", 3},
		//{ "evextsb", "", 0}, //extend sign byte
		//{ "evextsh", "", 0}, //extend sign half
		{ "evldd", "A = vector[C + B]", 3},
		{ "evlddx", "A = vector[C + B]", 3},
		{ "evldh", "A = vector[C + B]", 3},
		{ "evldhx", "A = vector[C + B]", 3},
		{ "evldw", "A = vector[C + B]", 3},
		{ "evldwx", "A = vector[C + B]", 3},
		//Vector Load Half Word into Half Words Even and Splat  ??
		/*
		   { "evlhhesplat", "A = B + C", 3},
		   { "evlhhesplatx", "A = B + C", 3},
		   { "evlhhossplat", "A = B + C", 3},
		   { "evlhhossplatx", "A = B + C", 3},
		   { "evlhhousplat", "A = B + C", 3},
		   { "evlhhousplatx", "A = B + C", 3},
		 */
		{ "evlwhe", "A = vector[C + B]", 3},
		{ "evlwhex", "A = vector[C + B]", 3},
		{ "evlwhos", "A = vector[C + B]", 3},
		{ "evlwhosx", "A = vector[C + B]", 3},
		{ "evlwhou", "A = vector[C + B]", 3},
		{ "evlwhoux", "A = vector[C + B]", 3},
		/*
		   { "evlwhsplat", "A = vector[C + B]", 3},
		   { "evlwhsplatx", "A = vector[C + B]", 3},
		   { "evlwwsplat", "A = vector[C + B]", 3},
		   { "evlwwsplatx", "A = vector[C + B]", 3},
		   { "evmergehi", "A = lo | hi", 3},
		   { "evmergehilo", "A = B + C", 3},
		   { "evmergelo", "A = B + C", 3},
		   { "evmergelohi", "A = B + C", 3},
		   { "evmhegsmfaa", "A = B + C", 3},
		   { "evmhegsmfan", "A = B + C", 3},
		   { "evmhegsmiaa", "A = B + C", 3},
		   { "evmhegsmian", "A = B + C", 3},
		   { "evmhegumiaa", "A = B + C", 3},
		   { "evmhegumian", "A = B + C", 3},
		   { "evmhesmf", "A = B + C", 3},
		   { "evmhesmfa", "A = B + C", 3},
		   { "evmhesmfaaw", "A = B + C", 3},
		   { "evmhesmfanw", "A = B + C", 3},
		   { "evmhesmi", "A = B + C", 3},
		   { "evmhesmia", "A = B + C", 3},
		   { "evmhesmiaaw", "A = B + C", 3},
		   { "evmhesmianw", "A = B + C", 3},
		   { "evmhessf", "A = B + C", 3},
		   { "evmhessfa", "A = B + C", 3},
		   { "evmhessfaaw", "A = B + C", 3},
		   { "evmhessfanw", "A = B + C", 3},
		   { "evmhessiaaw", "A = B + C", 3},
		   { "evmhessianw", "A = B + C", 3},
		   { "evmheumi", "A = B + C", 3},
		   { "evmheumia", "A = B + C", 3},
		   { "evmheumiaaw", "A = B + C", 3},
		   { "evmheumianw", "A = B + C", 3},
		   { "evmheusiaaw", "A = B + C", 3},
		   { "evmheusianw", "A = B + C", 3},
		   { "evmhogsmfaa", "A = B + C", 3},
		   { "evmhogsmfan", "A = B + C", 3},
		   { "evmhogsmiaa", "A = B + C", 3},
		   { "evmhogsmian", "A = B + C", 3},
		   { "evmhogumiaa", "A = B + C", 3},
		   { "evmhogumian", "A = B + C", 3},
		   { "evmhosmf", "A = B + C", 3},
		   { "evmhosmfa", "A = B + C", 3},
		   { "evmhosmfaaw", "A = B + C", 3},
		   { "evmhosmfanw", "A = B + C", 3},
		   { "evmhosmi", "A = B + C", 3},
		   { "evmhosmia", "A = B + C", 3},
		   { "evmhosmiaaw", "A = B + C", 3},
		   { "evmhosmianw", "A = B + C", 3},
		   { "evmhossf", "A = B + C", 3},
		   { "evmhossfa", "A = B + C", 3},
		   { "evmhossfaaw", "A = B + C", 3},
		   { "evmhossfanw", "A = B + C", 3},
		   { "evmhossiaaw", "A = B + C", 3},
		   { "evmhossianw", "A = B + C", 3},
		   { "evmhoumi", "A = B + C", 3},
		   { "evmhoumia", "A = B + C", 3},
		   { "evmhoumiaaw", "A = B + C", 3},
		   { "evmhoumianw", "A = B + C", 3},
		   { "evmhousiaaw", "A = B + C", 3},
		   { "evmhousianw", "A = B + C", 3},
		   { "evmra", "A = B + C", 3},
		   { "evmwhsmf", "A = B + C", 3},
		   { "evmwhsmfa", "A = B + C", 3},
		   { "evmwhsmi", "A = B + C", 3},
		   { "evmwhsmia", "A = B + C", 3},
		   { "evmwhssf", "A = B + C", 3},
		   { "evmwhssfa", "A = B + C", 3},
		   { "evmwhumi", "A = B + C", 3},
		   { "evmwhumia", "A = B + C", 3},
		   { "evmwlsmiaaw", "A = B + C", 3},
		{ "evmwlsmianw", "A = B + C", 3},
		{ "evmwlssiaaw", "A = B + C", 3},
		{ "evmwlssianw", "A = B + C", 3},
		{ "evmwlumi", "A = B + C", 3},
		{ "evmwlumia", "A = B + C", 3},
		{ "evmwlumiaaw", "A = B + C", 3},
		{ "evmwlumianw", "A = B + C", 3},
		{ "evmwlusiaaw", "A = B + C", 3},
		{ "evmwlusianw", "A = B + C", 3},
		{ "evmwsmf", "A = B + C", 3},
		{ "evmwsmfa", "A = B + C", 3},
		{ "evmwsmfaa", "A = B + C", 3},
		{ "evmwsmfan", "A = B + C", 3},
		{ "evmwsmi", "A = B + C", 3},
		{ "evmwsmia", "A = B + C", 3},
		{ "evmwsmiaa", "A = B + C", 3},
		{ "evmwsmian", "A = B + C", 3},
		{ "evmwssf", "A = B + C", 3},
		{ "evmwssfa", "A = B + C", 3},
		{ "evmwssfaa", "A = B + C", 3},
		{ "evmwssfan", "A = B + C", 3},
		{ "evmwumi", "A = B + C", 3},
		{ "evmwumia", "A = B + C", 3},
		{ "evmwumiaa", "A = B + C", 3},
		{ "evmwumian", "A = B + C", 3},
		{ "evnand", "A = B + C", 3},
		{ "evneg", "A = B + C", 3},
		{ "evnor", "A = B + C", 3},
		{ "evor", "A = B + C", 3},
		{ "evorc", "A = B + C", 3},
		{ "evrlw", "A = B + C", 3},
		{ "evrlwi", "A = B + C", 3},
		{ "evrndw", "A = B + C", 3},
		{ "evslw", "A = B + C", 3},
		{ "evslwi", "A = B + C", 3},
		{ "evsplatfi", "A = B + C", 3},
		{ "evsplati", "A = B + C", 3},
		{ "evsrwis", "A = B + C", 3},
		{ "evsrwiu", "A = B + C", 3},
		{ "evsrws", "A = B + C", 3},
		{ "evsrwu", "A = B + C", 3},
		{ "evstdd", "A = B + C", 3},
		{ "evstddx", "A = B + C", 3},
		{ "evstdh", "A = B + C", 3},
		{ "evstdhx", "A = B + C", 3},
		{ "evstdw", "A = B + C", 3},
		{ "evstdwx", "A = B + C", 3},
		{ "evstwhe", "A = B + C", 3},
		{ "evstwhex", "A = B + C", 3},
		{ "evstwho", "A = B + C", 3},
		{ "evstwhox", "A = B + C", 3},
		{ "evstwwe", "A = B + C", 3},
		{ "evstwwex", "A = B + C", 3},
		{ "evstwwo", "A = B + C", 3},
		{ "evstwwox", "A = B + C", 3},
		{ "evsubfsmiaaw", "A = B + C", 3},
		{ "evsubfssiaaw", "A = B + C", 3},
		{ "evsubfumiaaw", "A = B + C", 3},
		{ "evsubfusiaaw", "A = B + C", 3},
		{ "evsubfw", "A = B + C", 3},
		{ "evsubifw", "A = B + C", 3},
		{ "evxor", "A = B + C", 3},
		*/
		{ "extsb", "A = extend_sign(B)", 2},
		{ "extsh", "A = extend_sign(B)", 2},
		{ "extsw", "A = extend_sign(B)", 2},
		{ "fabs", "A = abs(B)", 2},
		{ "fadd", "A = B + C", 3},
		{ "fadds", "A = (float) B + C", 3},
		{ "fcfid", "A = (double) B", 2},
		{ "fcfids", "A = (float) B", 2},
		{ "fcfidu", "A = (double) B", 2},
		{ "fcfidus", "A = (float) B", 2},
		{ "fcmpu", "A = B == C", 3},
		// This should copy the sign of bit 0 of reg B & c
		{ "fcpsgn", "A = flt_copy_sign(B,C)", 3},
		{ "fctid", "A = (int64) B", 2},
		{ "fctiduz", "A = (uint64) B + C", 3},
		{ "fctidz", "A = (int64) B + C", 3},
		{ "fctiw", "A = (int32) B + C", 3},
		{ "fctiwuz", "A = (uint32) B + C", 3},
		{ "fctiwz", "A = (int32) B + C", 3},
		{ "fdiv", "A = B / C", 3},
		{ "fdivs", "A = (float) B / C", 3},
		{ "fmadd", "A = (B * C) + D", 4},
		{ "fmadds", "A = (float) (B * C) + D", 3},
		{ "fmr", "A = B", 2},
		{ "fmsub", "A = (B * C) - d", 4},
		{ "fmsubs", "A = (float) (B * C) - D", 4},
		{ "fmul", "A = B * C", 3},
		{ "fmuls", "A = (float) B * C", 3},
		{ "fnabs", "A = - abs(B)", 2},
		{ "fneg", "A = - B", 2},
		{ "fnmadd", "A = -((B * C) + D)", 4},
		{ "fnmadds", "A = (float) -((B * C) + D)", 4},
		{ "fnmsub", "A = -((B * C) - D)", 4},
		{ "fnmsubs", "A = (float) -((B * C) - D)", 4},
		{ "fre", "A = 1/B", 2},
		{ "fres", "A = (float) 1/B", 2},
		{ "frim", "A = trunc(B)", 2},
		{ "frin", "A = floor(B)", 2},
		{ "frip", "A = ceil(B)", 2},
		{ "friz", "A = trunc(B)", 2},
		{ "frsp", "A = (float) B", 3},
		{ "frsqrte", "A = 1/sqrt(B)", 2},
		{ "frsqrtes", "A = (float) 1/sqrt(B)", 2},
		{ "fsel", "if (B >= 0.0) A = C; else A = D", 4},
		{ "fsqrt", "A = sqrt(B)", 2},
		{ "fsqrts", "A = (float) sqrt(B)", 3},
		{ "fsub", "A = B - C", 3},
		{ "fsubs", "A = (float) B - C", 3},
		{ "icbi", "inst_cache_block_inval", 0},
		{ "icbt", "inst_cache_block_touch", 3},
		{ "iccci", "inst_cache_inval(A,B)", 2},
		{ "isel", "A = select(D, B, C)", 4},
		{ "isync", "sync_instr_cache", 0},
		{ "la", "A = C + B", 3},
		{ "lbz", "A = byte[C + B]", 3},
		{ "lbzcix", "A = byte[C + B]", 3},
		{ "lbzu", "A = byte[C + B]", 3},
		{ "lbzux", "A = Byte[C + B]", 3},
		{ "lbzx", "A = byte[C + B]", 3},
		{ "ld", "A = [C + B]", 3},
		// No clue how to represent them since they are kinda complex..
		//  { "ldarx", "A = [C + B]", 3},
		//  { "ldbrx", "A = [C + B]", 3},
		//  { "ldcix", "A = B + C", 3},
		{ "ldu", "A = [C + B]", 3},
		{ "ldux", "A = [C + B]", 3},
		{ "ldx", "A = [C + B]", 3},
		{ "lfd", "A = double[C + B]", 3},
		{ "lfdu", "A = double[C + B]", 3},
		{ "lfdux", "A = double[C + B]", 3},
		{ "lfdx", "A = double[C + B]", 3},
		{ "lfiwax", "A = float[C + B]", 3},
		{ "lfiwzx", "A = float[C + B]", 3},
		{ "lfs", "A = float[C + B]", 3},
		{ "lfsu", "A = float[C + B]", 3},
		{ "lfsux", "A = float[C + B]", 3},
		{ "lfsx", "A = float[C + B]", 3},
		{ "lha", "A = half[C + B]", 3},
		{ "lhau", "A = half[C + B]", 3},
		{ "lhaux", "A = half[C + B]", 3},
		{ "lhax", "A = half[C + B]", 3},
		{ "lhbrx", "A = half[C + B]", 3},
		{ "lhz", "A = half[C + B]", 3},
		{ "lhzcix", "A = half[C + B]", 3},
		{ "lhzu", "A = half[C + B]", 3},
		{ "lhzux", "A = half[C + B]", 3},
		{ "lhzx", "A = half[C + B]", 3},
		{ "li", "A = B", 2},
		{ "lis", "A = (B << 16)", 2},
		{ "lmw", "A = multiple word[C + B]", 3},
		{ "lswi", "A = string word[C + B]", 3},
		{ "lvebx", "A = vector[C + B]", 3},
		{ "lvehx", "A = vector[C + B]", 3},
		{ "lvewx", "A = vector[C + B]", 3},
		{ "lvsl", "A = vector[C + B]", 3},
		{ "lvsr", "A = vector[C + B]", 3},
		{ "lvx", "A = vector[C + B]", 3},
		{ "lvxl", "A = vector[C + B]", 3},
		{ "lwa", "A = word[C + B]", 3},
		{ "lwarx", "A = word[C + B]", 3},
		{ "lwaux", "A = word[C + B]", 3},
		{ "lwax", "A = word[C + B]", 3},
		{ "lwbrx", "A = word[C + B]", 3},
		{ "lwsync", "sync_load_store", 0},
		{ "lwz", "A = word[C + B]", 3},
		{ "lwzcix", "A = word[C + B]", 3},
		{ "lwzu", "A = word[C + B]", 3},
		{ "lwzux", "A = word[C + B]", 3},
		{ "lwzx", "A = word[C + B]", 3},
		//      { "lxsdx", "A = ???[C + B]", 3},
		{ "lxvdbx", "A = vector[C + B]", 3},
		{ "lxvdsx", "A = vector[C + B]", 3},
		{ "lxvwdx", "A = vector[C + B]", 3},
		{ "mbar", "memory_barrier(A)", 1},
		{ "mcrf", "A = B", 2},
		{ "mcrfs", "A = B", 2},
		{ "mfamr", "A = amr", 1},
		{ "mfasr", "A = asr", 1},
		{ "mfbr0", "A = br0", 1},
		{ "mfbra", "A = br1", 1},
		{ "mfbrb", "A = br2", 1},
		{ "mfbrc", "A = br3", 1},
		{ "mfbrd", "A = br4", 1},
		{ "mfbr5", "A = br5", 1},
		{ "mfbr6", "A = br6", 1},
		{ "mfbr7", "A = br7", 1},
		{ "mfcfar", "A = cfar", 3},
		{ "mfcr", "A = crB", 2},
		{ "mfctr", "A = ctr", 3},
		{ "mfdar", "A = dar", 1},
		{ "mfdbatl", "A = dbatBl", 1},
		{ "mfdbatu", "A = dbatBu", 1},
		{ "mfdccr", "A = dccr", 1},
		{ "mfdcr", "A = dcr", 1},
		{ "mfdear", "A = dear", 1},
		{ "mfdscr", "A = dscr", 1},
		{ "mfdsisr", "A = dsisr", 1},
		{ "mfesr", "A = esr", 1},
		{ "mffs", "A = fs", 1},
		{ "mfibatl", "A = ibatBl", 2},
		{ "mfibatu", "A = ibatBu", 2},
		{ "mficcr", "A = iccr", 1},
		{ "mflr", "A = lr", 1},
		{ "mfmsr", "A = msr", 1},
		{ "mfocrf", "A = ocrf", 1},
		{ "mfpid", "A = pid", 1},
		{ "mfpvr", "A = pvr", 1},
		{ "mfrtcl", "A = rtc_lo", 1},
		{ "mfrtcu", "A = rtc_hi", 1},
		{ "mfspefscr", "A = fscr",1},
		{ "mfsr", "A = srB", 3},
		{ "mfsrin", "A = sr_indirect(B)", 2},
		{ "mfsrr2", "A = srr2", 1},
		{ "mfsrr3", "A = srr3", 1},
		{ "mftb", "A = tb(B)", 2},
		{ "mftbhi", "A = tb_hi(B)", 2},
		{ "mftblo", "A = tb_lo(B)", 2},
		{ "mftbu", "A = tbu", 1},
		{ "mftcr", "A = tcr", 1},
		{ "mfvscr", "A = vscr", 1},
		{ "mfxer", "A = xer", 1},
		{ "mr", "A = B", 2},
		{ "msync", "sync_memory", 3},
		{ "mtamr", "amr = A", 1},
		{ "mtbr0", "br0 = A", 1},
		{ "mtbr1", "br1 = A", 1},
		{ "mtbr2", "br2 = A", 1},
		{ "mtbr3", "br3 = A", 1},
		{ "mtbr4", "br4 = A", 1},
		{ "mtbr5", "br5 = A", 1},
		{ "mtbr6", "br6 = A", 1},
		{ "mtbr7", "br7 = A", 1},
		{ "mtcfar", "cfar = A", 1},
		{ "mtcr", "tcr = A", 1},
		{ "mtcrf", "crf = A", 1},
		{ "mtctr", "ctr = A", 1},
		{ "mtdar", "dar = A", 1},
		{ "mtdbatl", "dbatBl = A", 2},
		{ "mtdbatu", "dbatBu = A", 2},
		{ "mtdccr", "dccr = A", 1},
		{ "mtdcr", "dcr = A", 1},
		{ "mtdear", "dear = A", 1},
		{ "mtdscr", "dscr = A", 1},
		{ "mtdsisr", "dsisr = A", 1},
		{ "mtesr", "esr = A", 1},
		{ "mtfsb0", "fsb0 = A", 1},
		{ "mtfsb1", "fsb1 = A", 1},
		{ "mtfsf", "fsf = A", 1},
		{ "mtfsfi", "fsfi = A", 1},
		{ "mtibatl", "ibatBl = A", 2},
		{ "mtibatu", "ibatBu = A", 2},
		{ "mticcr", "iccr = A", 1},
		{ "mtlr", "lr = A", 1},
		{ "mtmsr", "msr = A", 1},
		{ "mtmsrd", "msr = A", 1},
		{ "mtocrf", "cr0 = B & fxm_mask(A)", 2},
		{ "mtpid", "pid = A", 1},
		{ "mtspefscr", "fscr = A", 1},
		{ "mtsr", "srA = B", 2},
		{ "mtsrin", "sr_indirect(A) = B", 2},
		{ "mtsrr2", "srr2 = A", 1},
		{ "mtsrr3", "srr3 = A ", 1},
		{ "mttbhi", "tb_hi(A) = B", 2},
		{ "mttbl", "tbl(A) = B", 2},
		{ "mttblo", "tb_lo(A) = B", 2},
		{ "mttbu", "tbu = A", 1},
		{ "mtvscr", "vscr = A", 1},
		{ "mtxer", "xer = A", 1},
		{ "mulhd", "A = hi(B) * hi(C)", 3},
		{ "mulhdu", "A = (unsigned) hi(B) * hi(C)", 3},
		{ "mulhw", "A = (word) hi(B) * hi(C)", 3},
		{ "mulhwu", "A = (unsigned word) hi(B) * hi(C)", 3},
		{ "mulld", "A = lo(B) * lo(C)", 3},
		{ "mulli", "A = lo(B) * lo(C)", 3},
		{ "mullw", "A = (word) lo(B) * lo(C)", 3},
		{ "nand", "A = B & !C", 3},
		{ "neg", "A = -B", 2},
		{ "nop", "", 0},
		{ "nor", "A = B | !C", 3},
		{ "not", "A = !B", 2},
		{ "or", "A = B | C", 3},
		{ "orc", "A = B | C", 3},
		{ "ori", "A = B | C", 3},
		{ "oris", "A = B | (C << 16)", 3},
		{ "popcntd", "A = count_bits(B)", 2},
		{ "popcntw", "A = count_bits(B)", 2},
		{ "ptesync", "sync_page_tbl", 0},
		// Are you kidding? QPX Architecture totally NO.
		/*
		   { "qvaligni", "A = B + C", 3},
		   { "qvesplati", "A = B + C", 3},
		   { "qvfabs", "A = B + C", 3},
		   { "qvfadd", "A = B + C", 3},
		   { "qvfadds", "A = B + C", 3},
		   { "qvfand", "A = B + C", 3},
		   { "qvfandc", "A = B + C", 3},
		   { "qvfcfid", "A = B + C", 3},
		   { "qvfcfids", "A = B + C", 3},
		   { "qvfcfidu", "A = B + C", 3},
		   { "qvfcfidus", "A = B + C", 3},
		   { "qvfclr", "A = B + C", 3},
		   { "qvfcmpeq", "A = B + C", 3},
		   { "qvfcmpgt", "A = B + C", 3},
		   { "qvfcmplt", "A = B + C", 3},
		   { "qvfcpsgn", "A = B + C", 3},
		   { "qvfctfb", "A = B + C", 3},
		   { "qvfctid", "A = B + C", 3},
		   { "qvfctidu", "A = B + C", 3},
		   { "qvfctiduz", "A = B + C", 3},
		   { "qvfctidz", "A = B + C", 3},
		   { "qvfctiw", "A = B + C", 3},
		   { "qvfctiwu", "A = B + C", 3},
		   { "qvfctiwuz", "A = B + C", 3},
		   { "qvfctiwz", "A = B + C", 3},
		   { "qvfequ", "A = B + C", 3},
		   { "qvflogical", "A = B + C", 3},
		   { "qvfmadd", "A = B + C", 3},
		   { "qvfmadds", "A = B + C", 3},
		   { "qvfmr", "A = B + C", 3},
		   { "qvfmsub", "A = B + C", 3},
		   { "qvfmsubs", "A = B + C", 3},
		   { "qvfmul", "A = B + C", 3},
		   { "qvfmuls", "A = B + C", 3},
		   { "qvfnabs", "A = B + C", 3},
		   { "qvfnand", "A = B + C", 3},
		   { "qvfneg", "A = B + C", 3},
		   { "qvfnmadd", "A = B + C", 3},
		   { "qvfnmadds", "A = B + C", 3},
		   { "qvfnmsub", "A = B + C", 3},
		   { "qvfnmsubs", "A = B + C", 3},
		   { "qvfnor", "A = B + C", 3},
		   { "qvfnot", "A = B + C", 3},
		   { "qvfor", "A = B + C", 3},
		   { "qvforc", "A = B + C", 3},
		   { "qvfperm", "A = B + C", 3},
		   { "qvfre", "A = B + C", 3},
		   { "qvfres", "A = B + C", 3},
		   { "qvfrim", "A = B + C", 3},
		   { "qvfrin", "A = B + C", 3},
		   { "qvfrip", "A = B + C", 3},
		   { "qvfriz", "A = B + C", 3},
		   { "qvfrsp", "A = B + C", 3},
		   { "qvfrsqrte", "A = B + C", 3},
		   { "qvfrsqrtes", "A = B + C", 3},
		   { "qvfsel", "A = B + C", 3},
		   { "qvfset", "A = B + C", 3},
		   { "qvfsub", "A = B + C", 3},
		   { "qvfsubs", "A = B + C", 3},
		   { "qvftstnan", "A = B + C", 3},
		   { "qvfxmadd", "A = B + C", 3},
		   { "qvfxmadds", "A = B + C", 3},
		   { "qvfxmul", "A = B + C", 3},
		   { "qvfxmuls", "A = B + C", 3},
		   { "qvfxor", "A = B + C", 3},
		   { "qvfxxcpnmadd", "A = B + C", 3},
		   { "qvfxxcpnmadds", "A = B + C", 3},
		   { "qvfxxmadd", "A = B + C", 3},
		   { "qvfxxmadds", "A = B + C", 3},
		   { "qvfxxnpmadd", "A = B + C", 3},
		{ "qvfxxnpmadds", "A = B + C", 3},
		{ "qvgpci", "A = B + C", 3},
		{ "qvlfcdux", "A = B + C", 3},
		{ "qvlfcduxa", "A = B + C", 3},
		{ "qvlfcdx", "A = B + C", 3},
		{ "qvlfcdxa", "A = B + C", 3},
		{ "qvlfcsux", "A = B + C", 3},
		{ "qvlfcsuxa", "A = B + C", 3},
		{ "qvlfcsx", "A = B + C", 3},
		{ "qvlfcsxa", "A = B + C", 3},
		{ "qvlfdux", "A = B + C", 3},
		{ "qvlfduxa", "A = B + C", 3},
		{ "qvlfdx", "A = B + C", 3},
		{ "qvlfdxa", "A = B + C", 3},
		{ "qvlfiwax", "A = B + C", 3},
		{ "qvlfiwaxa", "A = B + C", 3},
		{ "qvlfiwzx", "A = B + C", 3},
		{ "qvlfiwzxa", "A = B + C", 3},
		{ "qvlfsux", "A = B + C", 3},
		{ "qvlfsuxa", "A = B + C", 3},
		{ "qvlfsx", "A = B + C", 3},
		{ "qvlfsxa", "A = B + C", 3},
		{ "qvlpcldx", "A = B + C", 3},
		{ "qvlpclsx", "A = B + C", 3},
		{ "qvlpcrdx", "A = B + C", 3},
		{ "qvlpcrsx", "A = B + C", 3},
		{ "qvstfcdux", "A = B + C", 3},
		{ "qvstfcduxa", "A = B + C", 3},
		{ "qvstfcduxi", "A = B + C", 3},
		{ "qvstfcduxia", "A = B + C", 3},
		{ "qvstfcdx", "A = B + C", 3},
		{ "qvstfcdxa", "A = B + C", 3},
		{ "qvstfcdxi", "A = B + C", 3},
		{ "qvstfcdxia", "A = B + C", 3},
		{ "qvstfcsux", "A = B + C", 3},
		{ "qvstfcsuxa", "A = B + C", 3},
		{ "qvstfcsuxi", "A = B + C", 3},
		{ "qvstfcsuxia", "A = B + C", 3},
		{ "qvstfcsx", "A = B + C", 3},
		{ "qvstfcsxa", "A = B + C", 3},
		{ "qvstfcsxi", "A = B + C", 3},
		{ "qvstfcsxia", "A = B + C", 3},
		{ "qvstfdux", "A = B + C", 3},
		{ "qvstfduxa", "A = B + C", 3},
		{ "qvstfduxi", "A = B + C", 3},
		{ "qvstfduxia", "A = B + C", 3},
		{ "qvstfdx", "A = B + C", 3},
		{ "qvstfdxa", "A = B + C", 3},
		{ "qvstfdxi", "A = B + C", 3},
		{ "qvstfdxia", "A = B + C", 3},
		{ "qvstfiwx", "A = B + C", 3},
		{ "qvstfiwxa", "A = B + C", 3},
		{ "qvstfsux", "A = B + C", 3},
		{ "qvstfsuxa", "A = B + C", 3},
		{ "qvstfsuxi", "A = B + C", 3},
		{ "qvstfsuxia", "A = B + C", 3},
		{ "qvstfsx", "A = B + C", 3},
		{ "qvstfsxa", "A = B + C", 3},
		{ "qvstfsxi", "A = B + C", 3},
		{ "qvstfsxia", "A = B + C", 3},
		*/
		{ "rfci", "msr = csrr1; nia = csrr0; ret", 0},
		{ "rfdi", "msr = drr1; nia = drr0; ret", 0},
		{ "rfi", "msr = srr1; nia = srr0; ret", 0},
		{ "rfid", "msr = srr1; nia = srr0; ret", 0},
		{ "rfmci", "msr = mcrr1; nia = mcrr0; ret", 3},
		{ "rotld", "A = rot64(B,C)", 3},
		{ "rotldi", "A = rot64(B,C)", 3},
		{ "rotlw", "A = rot32(B,C)", 3},
		{ "rotlwi", "A = rot32(B,C)", 3},
		{ "sc", "syscall", 0},
		{ "slbia", "slb_inval_all", 0},
		{ "slbie", "slb_inval_entry(A)", 1},
		{ "slbmfee", "A = slb[B]", 2},
		{ "slbmte", "slb[A] = B", 2},
		{ "sld", "A = B << C", 3},
		{ "sldi", "A = B << C", 3},
		{ "slw", "A = (word) B << C", 3},
		{ "slwi", "A = (word) B << C", 3},
		{ "srad", "A = B >> C", 3},
		{ "sradi", "A = B >> C", 3},
		{ "sraw", "A = (word) B >> C", 3},
		{ "srawi", "A = (word) B >> C", 3},
		{ "srd", "A = B >> C", 3},
		{ "srw", "A = (word) B >> C", 3},
		{ "srwi", "A = (word) B >> C", 3},
		{ "stb", "byte[C + B] = A", 3},
		{ "stbcix", "byte[C + B] = A", 3},
		{ "stbu", "byte[C + B] = A", 3},
		{ "stbux", "byte[C + B] = A", 3},
		{ "stbx", "byte[C + B] = A", 3},
		{ "std", "[C + B] = A", 3},
		{ "stdbrx", "[C + B] = A", 3},
		{ "stdcix", "[C + B] = A", 3},
		{ "stdcx", "[C + B] = A", 3},
		{ "stdu", "[C + B] = A", 3},
		{ "stdux", "[C + B] = A", 3},
		{ "stdx", "[C + B] = A", 3},
		{ "stfd", "float[C + B] = A", 3},
		{ "stfdu", "float[C + B] = A", 3},
		{ "stfdux", "float[C + B] = A", 3},
		{ "stfdx", "float[C + B] = A", 3},
		{ "stfiwx", "float[C + B] = A", 3},
		{ "stfs", "float[C + B] = A", 3},
		{ "stfsu", "float[C + B] = A", 3},
		{ "stfsux", "float[C + B] = A", 3},
		{ "stfsx", "float[C + B] = A", 3},
		{ "sth", "half[C + B] = A", 3},
		{ "sthbrx", "half[C + B] = A", 3},
		{ "sthcix", "half[C + B] = A", 3},
		{ "sthu", "half[C + B] = A", 3},
		{ "sthux", "half[C + B] = A", 3},
		{ "sthx", "half[C + B] = A", 3},
		{ "stmw", "multiple word[C + B] = A", 3},
		{ "stswi", "string word[C + B] = A", 3},
		{ "stvebx", "vector byte[C + B] = A", 3},
		{ "stvehx", "vector half[C + B] = A", 3},
		{ "stvewx", "vector word[C + B] = A", 3},
		{ "stvx", "vector[C + B] = A", 3},
		{ "stvxl", "vector[C + B] = A", 3},
		{ "stw", "word[C + B] = A", 3},
		{ "stwbrx", "word[C + B] = A", 3},
		{ "stwcix", "word[C + B] = A", 3},
		{ "stwcx", "word[C + B] = A", 3},
		{ "stwu", "word[C + B] = A", 3},
		{ "stwux", "word[C + B] = A", 3},
		{ "stwx", "word[C + B] = A", 3},
		{ "stxsdx", "vsx[C + B] = A", 3},
		{ "stxvdbx", "vector double[C + B] = A", 3},
		{ "stxvwdx", "vector word[C + B] = A", 3},
		{ "sub", "A = C - B", 3},
		{ "subc", "A = C - B", 3},
		{ "subf", "A = C - B", 3},
		{ "subfc", "A = C - B", 3},
		{ "subfe", "A = C - B", 3},
		{ "subfic", "A = C - B", 3},
		{ "subfme", "A = C - B", 3},
		{ "subfze", "A = C - B", 3},
		{ "sync", "sync_instr_cache", 0},
		{ "tdeq", "if (A == B) trap", 2},
		{ "tdeqi", "if (A == B) trap",2},
		{ "tdgt", "if (A > B) trap", 2},
		{ "tdgti", "if (A > B) trap", 2},
		{ "tdlgt", "if (A > B) trap", 2},
		{ "tdlgti", "if (A > B) trap", 2},
		{ "tdllt", "if (A < B) trap", 2},
		{ "tdllti", "if (A < B) trap", 2},
		{ "tdlt", "if (A < B) trap", 2},
		{ "tdlti", "if (A < B) trap", 2},
		{ "tdne", "if (A != B) trap", 2},
		{ "tdnei", "if (A != B) trap", 2},
		{ "tlbia", "inval_all_tlb", 0},
		{ "tlbie", "inval_tbl(A, B)", 2},
		{ "tlbiel", "inval_tbl(A)", 1},
		{ "tlbivax", "inval_va(A, B)", 2},
		{ "tlbld", "tlb_data_load(A)", 1},
		{ "tlbli", "tlb_instr_load(A)", 1},
		{ "tlbre", "A = tlb_read_entry(B,C)", 3},
		{ "tlbrehi", "A = tlb_read_entry_hi(B)", 2},
		{ "tlbrelo", "A = tlb_read_entry_lo(B)", 2},
		{ "tlbsx", "A = tlb_search(B)", 2},
		{ "tlbsync", "sync_tlb", 3},
		{ "tlbwe", "tlb_write_entry(B,C) = A", 3},
		{ "tlbwehi", "tlb_write_entry_hi(B) = A", 2},
		{ "tlbwelo", "tlb_write_entry_lo(B) = A", 2},
		{ "trap", "trap", 3},
		{ "tweq", "if ((word) A == (word) B) trap", 2},
		{ "tweqi", "if ((word) A == (word) B) trap",2},
		{ "twgt", "if ((word) A > (word) B) trap", 2},
		{ "twgti", "if ((word) A > (word) B) trap", 2},
		{ "twlgt", "if ((word) A > (word) B) trap", 2},
		{ "twlgti", "if ((word) A > (word) B) trap", 2},
		{ "twllt", "if ((word) A < (word) B) trap", 2},
		{ "twllti", "if ((word) A < (word) B) trap", 2},
		{ "twlt", "if ((word) A < (word) B) trap", 2},
		{ "twlti", "if ((word) A < (word) B) trap", 2},
		{ "twne", "if ((word) A != (word) B) trap", 2},
		{ "twnei", "if ((word) A != (word) B) trap", 2},
		{ "vaddcuw", "A = (unsigned vector) B + C", 3},
		{ "vaddfp", "A =  (float vector) B + C", 3},
		{ "vaddsbs", "A = (byte vector) B + C", 3},
		{ "vaddshs", "A = (half vector) B + C", 3},
		{ "vaddsws", "A = (word vector) B + C", 3},
		/* too much complexity to represent
		   { "vaddubm", "A = (byte vector) B + C + (modulo?)", 3},
		   { "vaddubs", "A = (byte vector) B + C", 3},
		   { "vaddudm", "A = (vector) B + C + (modulo?)", 3},
		   { "vadduhm", "A = (half vector) B + C", 3},
		   { "vadduhs", "A = (half vector) B + C", 3},
		   { "vadduwm", "A = (word vector) B + C", 3},
		   { "vadduws", "A = (word vector) B + C", 3},
		 */
		{ "vand", "A = B & C", 3},
		{ "vandc", "A = B & C", 3},
		{ "vavgsb", "A = (byte vector) avg(B, C)", 3},
		{ "vavgsh", "A = (half vector) avg(B, C)", 3},
		{ "vavgsw", "A = (word vector) avg(B, C)", 3},
		{ "vavgub", "A = (unsigned byte vector) avg(B, C)", 3},
		{ "vavguh", "A = (unsigned  half vector) avg(B, C)", 3},
		{ "vavguw", "A = (unsigned word vector) avg(B, C)", 3},
		{ "vcfsx", "A = (float vector) B", 2},
		{ "vcfux", "A = (float vector) B", 2},
		{ "vclzb", "A = (byte vector) count_zeros(B)", 2},
		{ "vclzd", "A = (vector) count_zeros(B)", 2},
		{ "vclzh", "A = (half vector) count_zeros(B)", 2},
		{ "vclzw", "A = (word vector) count_zeros(B)", 2},
		{ "vcmpbfp", "A = !(B < C) | (B == C) | !(B > C)", 3},
		{ "vcmpeqfp", "A = (float) B == (float) C", 3},
		{ "vcmpequb", "A = (unsigned byte) B == (byte) C", 3},
		{ "vcmpequd", "A = (unsigned) B ==  (unsigned) C", 3},
		{ "vcmpequh", "A = (unsigned half) B == (unsigned half) C", 3},
		{ "vcmpequw", "A = (unsigned word) B == (unsigned word) C", 3},
		{ "vcmpgefp", "A = (float) B >= (float) C", 3},
		{ "vcmpgtsb", "A = (byte) B > (byte) C", 3},
		{ "vcmpgtsd", "A = B > C", 3},
		{ "vcmpgtsh", "A = (half) B > (half) C", 3},
		{ "vcmpgtsw", "A = (word) B > (word) C", 3},
		{ "vcmpgtub", "A = (unsigned byte) B > (byte) C", 3},
		{ "vcmpgtud", "A = (unsigned) B >  (unsigned) C", 3},
		{ "vcmpgtuh", "A = (unsigned half) B > (unsigned half) C", 3},
		{ "vcmpgtuw", "A = (unsigned word) B > (unsigned word) C", 3},
		{ "vctsxs", "A = (word) B", 2},
		{ "vctuxs", "A = (unsigned word) B", 2},
		{ "veqv", "A = (vector) B ^ C", 3},
		{ "vexptefp", "A = (float vector) pow(2, B)", 2},
		{ "vlogefp", "A = (float vector)  log2(B)", 2},
		{ "vmaddfp", "A = (float vector)  (B * C) + round(D)", 4},
		{ "vmaxfp", "A = (float vector) max(B, C)", 3},
		{ "vmaxsb", "A = (byte vector) max(B, C)", 3},
		{ "vmaxsd", "A = (vector) max(B, C)", 3},
		{ "vmaxsh", "A = (half vector) max(B, C)", 3},
		{ "vmaxsw", "A = (word vector) max(B, C)", 3},
		{ "vmaxub", "A = (unsigned byte vector) max(B, C)", 3},
		{ "vmaxud", "A = (vector) max(B, C)", 3},
		{ "vmaxuh", "A = (unsigned half vector) max(B, C)", 3},
		{ "vmaxuw", "A = (unsigned word vector) max(B, C)", 3},
		//    { "vmhaddshs", "A = (vector)  B + C + D", 4},
		//    { "vmhraddshs", "A = (vector) B + C + D", 4},
		{ "vminfp", "A = (float vector) min(B, C)", 3},
		{ "vminsb", "A = (byte vector) min(B, C)", 3},
		{ "vminsd", "A = (vector) min(B, C)", 3},
		{ "vminsh", "A = (half vector) min(B, C)", 3},
		{ "vminsw", "A = (word vector) min(B, C)", 3},
		{ "vminub", "A = (unsigned byte vector) min(B, C)", 3},
		{ "vminud", "A = (vector) min(B, C)", 3},
		{ "vminuh", "A = (unsigned half vector) min(B, C)", 3},
		{ "vminuw", "A = (unsigned word vector) min(B, C)", 3},
		//    { "vmladduhm", "A = (unsigned half vector) B + C", 3},
		{ "vmrghb", "A = (byte vector) merge_hi(B, C)", 3},
		{ "vmrghh", "A = (half vector) merge_hi(B, C)", 3},
		{ "vmrghw", "A = (word vector) merge_hi(B, C)", 3},
		{ "vmrglb", "A = (byte vector) merge_lo(B, C)", 3},
		{ "vmrglh", "A = (half vector) merge_lo(B, C)", 3},
		{ "vmrglw", "A = (word vector) merge_lo(B, C)", 3},
		{ "vmsummbm", "A = (byte vector) B + C", 3},
		{ "vmsumshm", "A = (half vector) B + C", 3},
		{ "vmsumshs", "A = (half vector) B + C", 3},
		{ "vmsumubm", "A = (unsigned byte vector) B + C", 3},
		{ "vmsumuhm", "A = (unsigned half vector) B + C", 3},
		{ "vmsumuhs", "A = (unsigned half vector) B + C", 3},
		{ "vmulesb", "A = (byte vector) B * C", 3},
		{ "vmulesh", "A = (half vector) B * C", 3},
		{ "vmulesw", "A = (word vector) B * C", 3},
		{ "vmuleub", "A = (unsigned byte vector) B * C", 3},
		{ "vmuleuh", "A = (unsigned half vector) B * C", 3},
		{ "vmuleuw", "A = (unsigned word vector) B * C", 3},
		{ "vmulosb", "A = (byte vector) B * C", 3},
		{ "vmulosh", "A = (byte vector) B * C", 3},
		{ "vmulosw", "A = (byte vector) B * C", 3},
		{ "vmuloub", "A = (byte vector) B * C", 3},
		{ "vmulouh", "A = (unsigned byte vector) B * C", 3},
		{ "vmulouw", "A = (unsigned byte vector) B * C", 3},
		{ "vmuluwm", "A = (unsigned word vector) B * C", 3},
		{ "vnand", "A = (vector) B & C", 3},
		{ "vnmsubfp", "A = (float vector) (B * C) - round(D)", 4},
		{ "vnor", "A = (vector) B | !C", 3},
		{ "vor", "A = (vector) B | C", 3},
		{ "vorc", "A = (vector) B | C", 3},
		// This should be represented as a for loop of bits comparing.. too much complex for pseudo
		//    { "vperm", "A = (vector) B + C", 3},
		{ "vpkpx", "A = (vector) pack_pixel(B, C)", 3},
		{ "vpkshss", "A = (half vector) pack_pixel_saturate(B, C)", 3},
		{ "vpkshus", "A = (unsigned half vector) pack_pixel_saturate(B, C)", 3},
		{ "vpkswss", "A = (word vector) pack_pixel_saturate(B, C)", 3},
		{ "vpkswus", "A = (unsigned word vector) pack_pixel_saturate(B, C)", 3},
		//    { "vpkuhum", "A = (vector) B + C", 3},
		//    { "vpkuhus", "A = (vector) B + C", 3},
		//    { "vpkuwum", "A = (vector) B + C", 3},
		//    { "vpkuwus", "A = (vector) B + C", 3},
		{ "vpopcntb", "A = (vector) count_8bits(B)", 2},
		{ "vpopcntd", "A = (vector) count_64bits(B)", 2},
		{ "vpopcnth", "A = (vector) count_16bits(B)", 2},
		{ "vpopcntw", "A = (vector) count_32bits(B)", 2},
		{ "vrefp", "A = (float vector) 1/B", 2},
		{ "vrfim", "A = (vector) floor(B)", 2},
		{ "vrfin", "A = (vector) near(B)", 2},
		{ "vrfip", "A = (vector) ceil(B)", 2},
		{ "vrfiz", "A = (vector) trunc(B)", 2},
		{ "vrlb", "A = (vector) rotl_byte(B, C)", 3},
		{ "vrld", "A = (vector) rotl(B, C)", 3},
		{ "vrlh", "A = (vector) rotl_half(B, C)", 3},
		{ "vrlw", "A = (vector) rotl_word(B, C)", 3},
		{ "vrsqrtefp", "A = (vector) sqrt(B)", 2},
		{ "vsel", "A = (vector) if (D & 1) B else C", 4},
		{ "vsl", "A = (vector) B << C", 3},
		{ "vslb", "A = (byte vector) B << C", 3},
		{ "vsld", "A = (vector) B << C", 3},
		{ "vsldoi", "A = (vector) B << (octet) C", 3},
		{ "vslh", "A = (half vector) B << C", 3},
		{ "vslo", "A = (vector) B <<< (octet) C", 3},
		{ "vslw", "A = (word vector) B + C", 3},
		{ "vspltb", "A = (vector) splat_byte(B, C)", 3},
		{ "vsplth", "A = (vector) splat_half(B, C)", 3},
		{ "vspltisb", "A = (vector) splat_byte(B, C)", 3},
		{ "vspltish", "A = (vector) splat_half(B, C)", 3},
		{ "vspltisw", "A = (vector) splat_word(B, C)", 3},
		{ "vspltw", "A = (vector) splat_word(B, C)", 3},
		{ "vsr", "A = (vector) B >> C", 3},
		{ "vsrab", "A = (byte vector) B >> C", 3},
		{ "vsrad", "A = (vector) B >> C", 3},
		{ "vsrah", "A = (half vector) B >> C", 3},
		{ "vsraw", "A = (word vector) B >> C", 3},
		{ "vsrb", "A = (byte vector) B >> C", 3},
		{ "vsrd", "A = (vector) B >> C", 3},
		{ "vsrh", "A = (half vector) B >> C", 3},
		{ "vsro", "A = (vector) B >> (octet) C", 3},
		{ "vsrw", "A = (word vector) B >> C", 3},
		{ "vsubcuw", "A = (unsigned word vector) (C - B) & 1", 3},
		{ "vsubfp", "A = (float vector) C - B", 3},
		{ "vsubsbs", "A = (byte vector) C - B", 3},
		{ "vsubshs", "A = (half vector) C - B", 3},
		{ "vsubsws", "A = (word vector) C - B", 3},
		{ "vsububm", "A = (byte vector) C - B", 3},
		{ "vsububs", "A = (byte vector) C - B", 3},
		{ "vsubudm", "A = (unsigned vector) C - B", 3},
		{ "vsubuhm", "A = (unsigned half vector) C - B", 3},
		{ "vsubuhs", "A = (unsigned half vector) C - B", 3},
		{ "vsubuwm", "A = (unsigned word vector) C - B", 3},
		{ "vsubuws", "A = (unsigned word vector) C - B", 3},
		{ "vsumbsws", "A = (word vector) B + C", 3},
		{ "vsumdsbs", "A = (byte vector) B + C", 3},
		{ "vsumdshs", "A = (half vector) B + C", 3},
		{ "vsumdubs", "A = (unsigned vector) B + C", 3},
		{ "vsumsws", "A = (word vector) B + C", 3},
		{ "vupkhpx", "A = (vector) unpack_hi_pixel(B)", 3},
		{ "vupkhsb", "A = (byte vector) unpack_hi_pixel(B)", 3},
		{ "vupkhsh", "A = (half vector) unpack_hi_pixel(B)", 3},
		{ "vupklpx", "A = (vector) unpack_lo_pixel(B)", 3},
		{ "vupklsb", "A = (byte vector) unpack_lo_pixel(B)", 3},
		{ "vupklsh", "A = (half vector) unpack_lo_pixel(B)", 3},
		{ "vxor", "A = (vector) B ^ C", 3},
		{ "wait", "wait_interrupt", 0},
		{ "waitimpl", "wait_interrupt_thread_reservation", 0},
		{ "waitrsv", "wait_interrupt_implemention", 0},
		{ "wrtee", "msr &= A", 1},
		{ "wrteei", "msr &= A", 1},
		{ "xnop", "", 0},
		{ "xor", "A = B ^ C", 3},
		{ "xori", "A = B ^ C", 3},
		{ "xoris", "A = B ^ (C << 16)", 3},
		{ "xsabsdp", "A = (double vector) abs(B)", 2},
		{ "xsadddp", "A = (double vector) B + C", 3},
		{ "xscmpodp", "A = (double vector) B == C", 3},
		{ "xscmpudp", "A = (double vector) B == C", 3},
		{ "xscpsgndp", "A = (double vector) copy_sign(B, C)", 3},
		{ "xscvdpsp", "A = (double vector) round(B)", 2},
		{ "xscvdpsxds", "A = (vector) ((double) B)", 2},
		{ "xscvdpsxws", "A = (word vector) ((double) B)", 2},
		{ "xscvdpuxds", "A = (unsigned vector) ((double) B)", 2},
		{ "xscvdpuxws", "A = (unsigned word vector) ((double) B)", 2},
		{ "xscvspdp", "A = (double vector) ((float) B)", 2},
		{ "xscvsxddp", "A = (double vector) B", 2},
		{ "xscvuxddp", "A = (double vector) ((unsigned) B)", 2},
		{ "xsdivdp", "A = (double vector) B / C", 3},
		// multiply add
		//    { "xsmaddadp", "A = (double vector) B * C + ?", 3},
		//    { "xsmaddmdp", "A = (double vector) B * C + ?", 3},
		{ "xsmaxdp", "A = (double vector) max(B, C)", 3},
		{ "xsmindp", "A = (double vector) min(B, C)", 3},
		// multiply sub
		//    { "xsmsubadp", "A = (double vector) B * C - ?", 3},
		//    { "xsmsubmdp", "A = (double vector) B * C - ?", 3},
		{ "xsmuldp", "A = (double vector) B * C", 3},
		{ "xsnabsdp", "A = (double vector) -abs(B)", 2},
		{ "xsnegdp", "A = (double vector) -B", 2},
		// negative multiply add
		//    { "xsnmaddadp", "A = (double vector) B * C + ?", 3},
		//    { "xsnmaddmdp", "A = (double vector) B + C + ?", 3},
		// negative multiply sub
		//    { "xsnmsubadp", "A = (double vector) B + C - ?", 3},
		//    { "xsnmsubmdp", "A = (double vector) B + C - ?", 3},
		{ "xsrdpi",  "A = (double vector) round(B)", 2},
		{ "xsrdpic", "A = (double vector) round(B)", 2},
		{ "xsrdpim", "A = (double vector) floor(B)", 2},
		{ "xsrdpip", "A = (double vector) ceil(B)", 2},
		{ "xsrdpiz", "A = (double vector) trunc(B)", 2},
		{ "xsredp", "A = (double vector) 1/B", 2},
		{ "xsrsqrtedp", "A = (double vector) 1/sqrt(B)", 2},
		{ "xssqrtdp", "A = sqrt(B)", 2},
		{ "xssubdp", "A = C - B", 3},
		{ "xstdivdp", "A = test_sw_divide(B, C)", 3},
		{ "xstsqrtdp", "A = test_sw_sqrt(B)", 2},
		{ "xvabsdp", "A = (double vector) abs(B)", 2},
		{ "xvabssp", "A = (float vector) abs(B)", 2},
		{ "xvadddp", "A = (double vector) B + C", 3},
		{ "xvaddsp", "A = (float vector) B + C", 3},
		{ "xvcmpeqdp", "A = (double vector) B == (double vector) C", 3},
		{ "xvcmpeqsp", "A = (float vector) B == (float vector) C", 3},
		{ "xvcmpgedp", "A = (double vector) B >= (double vector) C", 3},
		{ "xvcmpgesp", "A = (float vector) B >= (float vector) C", 3},
		{ "xvcmpgtdp", "A = (double vector) B > (double vector) C", 3},
		{ "xvcmpgtsp", "A = (float vector) B > (float vector) C", 3},
		{ "xvcpsgndp", "A = (double vector) copy_sign(B, C)", 3},
		{ "xvcpsgnsp", "A = (float vector) copy_sign(B, C)", 3},
		{ "xvcvdpsp", "A = (float vector) ((double vector)B)", 2},
		{ "xvcvdpsxds", "A = (vector) B", 2},
		{ "xvcvdpsxws", "A = (word vector) B", 2},
		{ "xvcvdpuxds", "A = (unsigned vector) B", 2},
		{ "xvcvdpuxws", "A = (unsigned word vector) B", 2},
		{ "xvcvspdp", "(double vector) ((float vector) B)", 2},
		{ "xvcvspsxds", "A = (vector) ((float vector) B)", 2},
		{ "xvcvspsxws", "A = (word vector) ((float vector) B)", 2},
		{ "xvcvspuxds", "A = (unsigned vector) ((float vector) B)", 2},
		{ "xvcvspuxws", "A = (unsigned word vector) ((float vector) B)", 2},
		{ "xvcvsxddp", "A = (double vector) B", 2},
		{ "xvcvsxdsp", "A = (float vector) B", 2},
		{ "xvcvsxwdp", "A = (double vector) ((word) B)", 2},
		{ "xvcvsxwsp", "A = (float vector) ((word) B)", 2},
		{ "xvcvuxddp", "A = (double vector) (unsigned) B", 2},
		{ "xvcvuxdsp", "A = (float vector) (unsigned) B", 2},
		{ "xvcvuxwdp", "A = (double vector) ((unsigned word) B)", 2},
		{ "xvcvuxwsp", "A = (float vector) ((unsigned word) B)", 2},
		{ "xvdivdp", "A = (double vector) B / C", 3},
		{ "xvdivsp", "A = (float vector) B / C", 3},
		//Multiply add (double & float)
		//    { "xvmaddadp", "A = B + C", 3},
		//    { "xvmaddasp", "A = B + C", 3},
		//    { "xvmaddmdp", "A = B + C", 3},
		//    { "xvmaddmsp", "A = B + C", 3},
		{ "xvmaxdp", "A = (double vector) max(B)", 2},
		{ "xvmaxsp", "A = (float vector) max(B)", 2},
		{ "xvmindp", "A = (double vector) min(B)", 2},
		{ "xvminsp", "A = (float vector) min(B)", 2},
		{ "xvmovdp", "A = (double vector) B", 2},
		{ "xvmovsp", "A = (float vector) B", 2},
		//Multiply sub (double & float)
		//    { "xvmsubadp", "A = B + C", 3},
		//    { "xvmsubasp", "A = B + C", 3},
		//    { "xvmsubmdp", "A = B + C", 3},
		//    { "xvmsubmsp", "A = B + C", 3},
		{ "xvmuldp", "A = (double vector) B * C", 3},
		{ "xvmulsp", "A = (float vector) B * C", 3},
		{ "xvnabsdp", "A = (double vector) -abs(B)", 2},
		{ "xvnabssp", "A = (float vector) -abs(B)", 2},
		{ "xvnegdp", "A = (double vector) -B", 2},
		{ "xvnegsp", "A = (float vector) -B", 2},
		//Negate multiply add (double & float)
		//    { "xvnmaddadp", "A = B + C", 3},
		//    { "xvnmaddasp", "A = B + C", 3},
		//    { "xvnmaddmdp", "A = B + C", 3},
		//    { "xvnmaddmsp", "A = B + C", 3},
		//Negate multiply sub (double & float)
		//    { "xvnmsubadp", "A = B + C", 3},
		//    { "xvnmsubasp", "A = B + C", 3},
		//    { "xvnmsubmdp", "A = B + C", 3},
		//    { "xvnmsubmsp", "A = B + C", 3},
		{ "xvrdpi", "A = (double vector) round(B)", 2},
		{ "xvrdpic", "A = (double vector) round(B)", 2},
		{ "xvrdpim", "A = (double vector) floor(B)", 2},
		{ "xvrdpip", "A = (double vector) ceil(B)", 2},
		{ "xvrdpiz", "A = (double vector) trunc(B)", 2},
		{ "xvredp", "A = (double vector) 1/B",2},
		{ "xvresp", "A = (float vector) B", 2},
		{ "xvrspi", "A = (float vector) round(B)", 2},
		{ "xvrspic", "A = (float vector) round(B)", 2},
		{ "xvrspim", "A = (float vector) floor(B)", 2},
		{ "xvrspip", "A = (float vector) ceil(B)", 2},
		{ "xvrspiz", "A = (float vector) trunc(B)", 2},
		{ "xvrsqrtedp", "A = (double vector) 1/sqrt(B)", 2},
		{ "xvrsqrtesp", "A = (float vector) 1/sqrt(B)", 2},
		{ "xvsqrtdp", "A = (double vector) sqrt(B)", 2},
		{ "xvsqrtsp", "A = (float vector) sqrt(B)", 2},
		{ "xvsubdp", "A = (double vector) C - B", 3},
		{ "xvsubsp", "A = (float vector) C - B", 3},
		{ "xvtdivdp", "A = (double vector) B / C", 3},
		{ "xvtdivsp", "A = (float vector) B / C", 3},
		{ "xvtsqrtdp", "A = (double vector) test_sw_sqrt(B)", 3},
		{ "xvtsqrtsp", "A = (float vector) test_sw_sqrt(B)", 3},
		{ "xxland", "A = B & C", 3},
		{ "xxlandc", "A = B & C", 3},
		{ "xxleqv", "A = B ^ C", 3},
		{ "xxlnand", "A = B & !C", 3},
		{ "xxlnor", "A = B + !C", 3},
		{ "xxlor", "A = B | C", 3},
		{ "xxlorc", "A = B | C", 3},
		{ "xxlxor", "A = B ^ C", 3},
		{ "xxmrghd", "A = hi(B) || hi(C)", 3},
		{ "xxmrghw", "A = (word vector) hi(B) || hi(C)", 3},
		{ "xxmrgld", "A = lo(B) || lo(C)", 3},
		{ "xxmrglw", "A = (word vector) lo(B) || lo(C)", 3},
		// Permute Doubleword Immediate
		//    { "xxpermdi", "A = B + C", 3},
		// Select (aka concat)
		//    { "xxsel", "A = B + C + D", 4},
		{ "xxsldwi", "A = B << C", 3},
		{ "xxspltd", "A = split(B)", 2},
		{ "xxspltw", "A = (word vector) split(B)", 2},
		{ "xxswapd", "swap(A,B)", 2},
		{ NULL }
	};

	char ppc_mask[32] = {0}; // enough to represent max val of 0xffffffffffffffff
	RStrBuf *sb = r_strbuf_new ("");
	for (i = 0; ops[i].op; i++) {
		if (!strcmp (ops[i].op, argv[0])) {
			for (j = 0; ops[i].str[j] != '\0'; j++) {
				if (can_replace(ops[i].str, j, ops[i].max_operands)) {
					if (op_needs_cr0 (argv[0]) && argv[ops[i].max_operands][0] == 0) {
						char* tmp = (char*) argv[ops[i].max_operands];
						argv[ops[i].max_operands] = argv[ops[i].max_operands - 1];
						if (ops[i].max_operands == 3) {
							argv[2] = argv[1];
						}
						tmp[0] = 'c';
						tmp[1] = 'r';
						tmp[2] = '0';
						tmp[3] = '\0';
						argv[1] = tmp;
					}
					int letter = ops[i].str[j] - '@';
					const char *w = argv[letter];
					// eprintf("%s:%d %s\n", ops[i].op, letter, w);
					// word rotates duplicate the word into both halves, so a wrapping mask keeps high bits
					if (letter == 4 && (r_str_startswith (argv[0], "rlwinm")
							|| r_str_startswith (argv[0], "rlwimi")
							|| r_str_startswith (argv[0], "rlwnm"))) {
						w = ppc_mask;
						//MASK(MB+32, ME+32)
						ut64 MB = PPC_UT64(argv[4]) + 32;
						ut64 ME = PPC_UT64(argv[5]) + 32;
						snprintf (ppc_mask, sizeof (ppc_mask), "0x%"PFMT64x, mask64 (MB, ME));
					} else if (letter == 4 && (r_str_startswith (argv[0], "rldcl") || r_str_startswith (argv[0], "rldicl"))) {
						w = ppc_mask;
						//MASK(MB, 63)
						ut64 MB = PPC_UT64(argv[4]);
						snprintf (ppc_mask, sizeof (ppc_mask), "0x%"PFMT64x, mask64 (MB, 63));
					} else if (letter == 4 && !strcmp (argv[0], "rldic")) {
						w = ppc_mask;
						//MASK(MB, 63 - SH)
						ut64 MB = PPC_UT64(argv[4]);
						ut64 ME = 63 - PPC_UT64(argv[3]);
						snprintf (ppc_mask, sizeof (ppc_mask), "0x%"PFMT64x, mask64 (MB, ME));
					} else if (letter == 4 && (r_str_startswith (argv[0], "rldcr") || r_str_startswith (argv[0], "rldicr"))) {
						w = ppc_mask;
						//MASK(0, ME)
						ut64 ME = PPC_UT64(argv[4]);
						snprintf (ppc_mask, sizeof (ppc_mask), "0x%"PFMT64x, mask64 (0, ME));
					} else if (letter == 4 && r_str_startswith (argv[0], "rldimi")) {
						// first mask (normal)
						w = ppc_mask;
						//MASK(MB, 63 - SH)
						ut64 MB = PPC_UT64(argv[4]);
						ut64 ME = 63 - PPC_UT64(argv[3]);
						snprintf (ppc_mask, sizeof (ppc_mask), "0x%"PFMT64x, mask64 (MB, ME));
					} else if (letter == 5 && r_str_startswith (argv[0], "rldimi")) {
						// second mask (inverted)
						w = ppc_mask;
						//MASK(MB, 63 - SH)
						ut64 MB = PPC_UT64(argv[4]);
						ut64 ME = 63 - PPC_UT64(argv[3]);
						ut64 inverted = ~ (mask64 (MB, ME));
						snprintf (ppc_mask, sizeof (ppc_mask), "0x%"PFMT64x, inverted);
					} else if (letter == 5 && r_str_startswith (argv[0], "rlwimi")) {
						w = ppc_mask;
						//MASK(MB+32, ME+32) inverted
						ut64 MB = PPC_UT64(argv[4]) + 32;
						ut64 ME = PPC_UT64(argv[5]) + 32;
						snprintf (ppc_mask, sizeof (ppc_mask), "0x%"PFMT64x, ~mask64 (MB, ME));
					} else if (letter == 1 && op_is_trap (argv[0])) {
						int to = PPC_UT64 (w);
						switch(to) {
							case 4:
								w = "==";
								break;
							case 1:
							case 8:
								w = ">";
								break;
							case 5:
							case 12:
								w = ">=";
								break;
							case 2:
							case 16:
								w = "<";
								break;
							case 6:
							case 20:
								w = "<=";
								break;
							case 24:
								w = "!=";
								break;
							case 31:
								// If no parameters t[dw][i] 32, 0, 0 just TRAP
								w = "==";
								break;
							default:
								w = "?";
								break;
						}
					} else if ((letter == 2 && !strcmp (argv[0], "mfspr")) || (letter == 1 && !strcmp (argv[0], "mtspr"))) {
						w = getspr (w);
					}
					if (w) {
						r_strbuf_append (sb, w);
					}
				} else {
					r_strbuf_append_n (sb, ops[i].str + j, 1);
				}
			}
			return r_strbuf_drain (sb);
		}
	}
	for (i = 0; i < argc; i++) {
		r_strbuf_append (sb, argv[i]);
		r_strbuf_append (sb, (i == 0 || i == argc - 1) ? " ":", ");
	}
	return r_strbuf_drain (sb);
}

#define WSZ 128
#define REPLACE(x,y) do { \
		int snprintf_len1_ = snprintf (a, 64, x, w1, w1); \
		int snprintf_len2_ = snprintf (b, 64, y, w1); \
		if (snprintf_len1_ < 64 && snprintf_len2_ < 64) { \
			p = r_str_replace (p, a, b, 0); \
		} \
	} while (0)

static int condition_bit(const char *arg) {
	int field = 0;
	if (r_str_startswith (arg, "4*cr") && arg[4] >= '0' && arg[4] <= '7' && arg[5] == '+') {
		field = arg[4] - '0';
		arg += 6;
	}
	const char *names[] = { "lt", "gt", "eq", "un" };
	int i;
	for (i = 0; i < R_ARRAY_SIZE (names); i++) {
		if (!strcmp (arg, names[i])) {
			return field * 4 + i;
		}
	}
	return -1;
}

static char *parse(RAsmPluginSession *aps, const char *data) {
	int len = strlen (data);
	char w0[WSZ];
	char w1[WSZ];
	char w2[WSZ];
	char w3[WSZ];
	char w4[WSZ];
	char w5[WSZ];
	char *buf, *ptr, *optr;

	if (!strcmp (data, "jr ra")) {
		return strdup ("return");
	}

	// malloc can be slow here :?
	if (!(buf = malloc (len + 1))) {
		return NULL;
	}
	memcpy (buf, data, len + 1);

	r_str_replace_char (buf, '(', ',');
	r_str_replace_char (buf, ')', ' ');
	r_str_trim (buf);
	char *str = NULL;
	if (*buf) {
		w0[0] = '\0';
		w1[0] = '\0';
		w2[0] = '\0';
		w3[0] = '\0';
		w4[0] = '\0';
		w5[0] = '\0';
		ptr = strchr (buf, ' ');
		if (!ptr) {
			ptr = strchr (buf, '\t');
		}
		if (ptr) {
			*ptr = '\0';
			for (ptr++; *ptr == ' '; ptr++) {
				//nothing to see here
			}
			r_str_ncpy (w0, buf, WSZ);
			r_str_ncpy (w1, ptr, WSZ);

			optr = ptr;
			ptr = strchr (ptr, ',');
			if (ptr) {
				*ptr = '\0';
				for (ptr++; *ptr == ' '; ptr++) {
					//nothing to see here
				}
				r_str_ncpy (w1, optr, WSZ);
				r_str_ncpy (w2, ptr, WSZ);
				optr = ptr;
				ptr = strchr (ptr, ',');
				if (ptr) {
					*ptr = '\0';
					for (ptr++; *ptr == ' '; ptr++) {
						//nothing to see here
					}
					r_str_ncpy (w2, optr, WSZ);
					r_str_ncpy (w3, ptr, WSZ);
					optr = ptr;
					// bonus
					ptr = strchr (ptr, ',');
					if (ptr) {
						*ptr = '\0';
						for (ptr++; *ptr == ' '; ptr++) {
							//nothing to see here
						}
						r_str_ncpy (w3, optr, WSZ);
						r_str_ncpy (w4, ptr, WSZ);
						optr = ptr;
						// bonus
						ptr = strchr (ptr, ',');
						if (ptr) {
							*ptr = '\0';
							for (ptr++; *ptr == ' '; ptr++) {
								//nothing to see here
							}
							r_str_ncpy (w4, optr, WSZ);
							r_str_ncpy (w5, ptr, WSZ);
						}
					}
				}
			}
		} else {
			r_str_ncpy (w0, buf, WSZ);
		}
		if ((!strcmp (w0, "bt") || !strcmp (w0, "bf")) && *w2) {
			int bit = condition_bit (w1);
			if (bit >= 0) {
				const char *taken[] = { "blt", "bgt", "beq", "bso" };
				const char *clear[] = { "bge", "ble", "bne", "bns" };
				r_str_ncpy (w0, w0[1] == 't'? taken[bit % 4]: clear[bit % 4], WSZ);
				snprintf (w1, WSZ, "cr%d", bit / 4);
			}
		}
		if (!strcmp (w0, "isellt") || !strcmp (w0, "iselgt") || !strcmp (w0, "iseleq")) {
			snprintf (w4, WSZ, "cr0%s", w0 + 4);
			r_str_ncpy (w0, "isel", WSZ);
		} else if (!strcmp (w0, "isel")) {
			int bit = condition_bit (w4);
			if (bit >= 0) {
				const char *names[] = { "lt", "gt", "eq", "so" };
				snprintf (w4, WSZ, "cr%d%s", bit / 4, names[bit % 4]);
			}
		}
		{
			const char *wa[] = { w0, w1, w2, w3, w4, w5 };
			size_t i, nw = 0;
			for (i = 0; i < R_ARRAY_SIZE (wa); i++) {
				if (wa[i][0] != '\0') {
					nw++;
				}
			}
			{
				char *p = replace (nw, wa);
				p = r_str_replace (p, "+ -", "- ", 0);
				p = r_str_replace (p, " + ]", "]  ", 0);
				//  p = r_str_replace (p, "if (r0 == r0) trap", "trap            ", 0);
#if EXPERIMENTAL_ZERO
				p = r_str_replace (p, "zero", "0", 0);
				if (!memcmp (p, "0 = ", 4)) *p = 0; // nop
#endif
				if (!strcmp (w1, w2)) {
					char a[64], b[64];

					// TODO: optimize
					REPLACE ("%s = %s +", "%s +=");
					REPLACE ("%s = %s -", "%s -=");
					REPLACE ("%s = %s &", "%s &=");
					REPLACE ("%s = %s |", "%s |=");
					REPLACE ("%s = %s ^", "%s ^=");
					REPLACE ("%s = %s >>", "%s >>=");
					REPLACE ("%s = %s <<", "%s <<=");
				}
				str = p;
			}
		}
	} else {
		str = strdup (data);
	}
	free (buf);
	return str;
}

RAsmPlugin r_asm_plugin_ppc = {
	.meta = {
		.name = "ppc",
		.desc = "Pseudocode for PowerPC assembly",
		.author = "pancake",
		.license = "LGPL-3.0-only",
	},
	.parse = parse,
};

#ifndef R2_PLUGIN_INCORE
R_API RLibStruct radare_plugin = {
	.type = R_LIB_TYPE_ASM,
	.data = &r_asm_plugin_ppc,
	.version = R2_VERSION
};
#endif
