// SPDX-FileCopyrightText: 2015-2017 pancake <pancake@nopcode.org>
// SPDX-FileCopyrightText: 2018-2021 deroad <wargio@libero.it>
// SPDX-License-Identifier: LGPL-3.0-only

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <rz_lib.h>
#include <rz_util.h>
#include <rz_flag.h>
#include <rz_analysis.h>
#include <rz_parse.h>

#ifndef PFMT32x
#define PFMT32x "lx"
#endif

#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))
#define PPC_UT32(x) ((ut32)PPC_UT64(x))

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;
}

#define SPR_CONST(o, x) \
	strcpy((o), (x)); \
	return (strlen((x)) - 1)
static int getspr_pseudo(const char *reg, char *output) {
	char cspr[32];
	ut32 spr = 0;
	if (!reg) {
		return 0;
	}
	spr = strtol(reg, NULL, 16);
	if (spr > 9999) {
		return 0; // just to avoid overflows..
	}

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

static int replace(int argc, const char *argv[], char *newstr) {
	int i, j, k;
	struct {
		char *op;
		char *str;
		int max_operands;
	} ops[] = {
		{ "cmpb", "A = ((byte) B == (byte) C)", 3 }, // 0
		{ "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 }, // 26
		{ "rldic", "A = rol64(B, C) & D", 4 }, // 27
		{ "rldcl", "A = rol64(B, C) & D", 4 }, // 28
		{ "rldicl", "A = rol64(B, C) & D", 4 }, // 29
		{ "rldcr", "A = rol64(B, C) & D", 4 }, // 30
		{ "rldicr", "A = rol64(B, C) & D", 4 }, // 31
		{ "rldimi", "A = (rol64(B, C) & D) | (A & E)", 5 }, // 32
		{ "rlwimi", "A = (rol32(B, C) & D) | (A & E)", 5 }, // 33
		{ "rlwimi.", "A = (rol32(B, C) & D) | (A & E)", 5 }, // 33
		{ "rlwinm", "A = rol32(B, C) & D", 5 }, // 34
		{ "rlwinm.", "A = rol32(B, C) & D", 5 }, // 34
		{ "rlwnm", "A = rol32(B, C) & D", 5 }, // 35
		{ "rlwnm.", "A = rol32(B, C) & D", 5 }, // 35
		{ "td", "if (B A C) trap", 3 }, // 36
		{ "tdi", "if (B A C) trap", 3 },
		{ "tdu", "if (B A C) trap", 3 },
		{ "tdui", "if (B A C) trap", 3 },
		{ "tw", "if ((word) B A (word) C) trap", 3 },
		{ "twi", "if ((word) B A (word) C) trap", 3 },
		{ "twu", "if ((word) B A (word) C) trap", 3 },
		{ "twui", "if ((word) B A (word) C) trap", 3 }, // 43
		{ "mfspr", "A = B", 2 }, // 44
		{ "mtspr", "A = B", 2 }, // 45
		{ "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 },
		//{ "bc", "if (a ?? b) goto C", 3},
		//{ "bca", "if (a ?? b) goto C", 3},
		//{ "bcctr", "if (a ?? b) goto ctr", 2},
		//{ "bcctrl", "if (a ?? b) goto ctr", 2},
		//{ "bcl", "if (a ?? b) call C", 3},
		//{ "bcla", "if (a ?? b) call 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 && !cond) goto A", 1 },
		{ "bdnzfa", "if (ctr != 0 && !cond) goto A", 1 },
		{ "bdnzfl", "if (ctr != 0 && !cond) call A", 1 },
		{ "bdnzfla", "if (ctr != 0 && !cond) call A", 1 },
		{ "bdnzflrl", "if (ctr != 0 && !cond) call A", 1 },
		{ "bdnzl", "if (ctr != 0) call A", 1 },
		{ "bdnzla", "if (ctr != 0) call A", 1 },
		{ "bdnzlr", "if (ctr != 0) return", 1 },
		{ "bdnzlrl", "if (ctr != 0) return", 1 },
		{ "bdnzt", "if (ctr != 0 && cond) goto A", 1 },
		{ "bdnzta", "if (ctr != 0 && cond) goto A", 1 },
		{ "bdnztl", "if (ctr != 0 && cond) call A", 1 },
		{ "bdnztla", "if (ctr != 0 && cond) call A", 1 },
		{ "bdnztlr", "if (ctr != 0 && cond) return", 1 },
		{ "bdnztlrl", "if (ctr != 0 && cond) return", 1 },
		{ "bdz", "if (ctr == 0) goto A", 1 },
		{ "bdza", "if (ctr == 0) goto A", 1 },
		{ "bdzf", "if (ctr == 0 && !cond) goto A", 1 },
		{ "bdzfa", "if (ctr == 0 && !cond) goto A", 1 },
		{ "bdzfl", "if (ctr == 0 && !cond) call A", 1 },
		{ "bdzfla", "if (ctr == 0 && !cond) call A", 1 },
		{ "bdzflr", "if (ctr == 0 && !cond) return", 1 },
		{ "bdzflrl", "if (ctr == 0 && !cond) returnA", 1 },
		{ "bdzl", "if (ctr == 0) call A", 1 },
		{ "bdzla", "if (ctr == 0) call A", 1 },
		{ "bdzlr", "if (ctr == 0) return", 1 },
		{ "bdzlrl", "if (ctr == 0) return", 1 },
		{ "bdzt", "if (ctr == 0 && cond) goto A", 1 },
		{ "bdzta", "if (ctr == 0 && cond) goto A", 1 },
		{ "bdztl", "if (ctr == 0 && cond) call A", 1 },
		{ "bdztla", "if (ctr == 0 && cond) call A", 1 },
		{ "bdztlr", "if (ctr == 0 && cond) return", 1 },
		{ "bdztlrl", "if (ctr == 0 && cond) return", 1 },
		{ "bf", "if (!A) goto B", 1 },
		{ "bfa", "if (!cond) goto A", 1 },
		{ "bfctr", "if (!cond) goto ctr", 0 },
		{ "bfctrl", "if (!cond) call ctr", 0 },
		{ "bfl", "if (!A) call B", 1 },
		{ "bfla", "if (!cond) call A", 1 },
		{ "bflr", "if (!A) return", 1 },
		{ "bflrl", "if (!A) return", 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 (A) goto B", 1 },
		{ "bta", "if (cond) goto A", 1 },
		{ "btctr", "if (cond) goto ctr", 1 },
		{ "btctrl", "if (cond) call ctr", 1 },
		{ "btl", "if (A) call B", 1 },
		{ "btla", "if (cond) call A", 1 },
		{ "btlr", "if (A) return", 1 },
		{ "btlrl", "if (A) return", 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 lt   Rx,Ry,Rz (equivalent to: isel Rx,Ry,Rz,0)
		// isel gt  Rx,Ry,Rz (equivalent to: isel Rx,Ry,Rz,1)
		// isel eq Rx,Ry,Rz (equivalent to: isel Rx,Ry,Rz,2)
		//  { "isel", "", 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) sign_extend(B, 8)", 3 },
		{ "vspltish", "A = (vector) sign_extend(B, 16)", 3 },
		{ "vspltisw", "A = (vector) sign_extend(B, 32)", 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
	for (i = 0; ops[i].op != NULL; i++) {
		if (!strcmp(ops[i].op, argv[0])) {
			if (newstr) {
				for (j = k = 0; ops[i].str[j] != '\0'; j++, k++) {
					if (can_replace(ops[i].str, j, ops[i].max_operands)) {
						if (i >= 0 && i <= 26 && 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);
						if (letter == 4 && !strncmp(argv[0], "rlwinm", 6)) {
							// { "rlwinm", "A = rol32(B, C) & D", 5},
							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 && (!strncmp(argv[0], "rldcl", 5) || !strncmp(argv[0], "rldicl", 6))) {
							// { "rld[i]cl", "A = rol64(B, C) & D", 4},
							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 && !strncmp(argv[0], "rldic", 5)) {
							// { "rldic", "A = rol64(B, C) & D", 4},
							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 && (!strncmp(argv[0], "rldcr", 5) || !strncmp(argv[0], "rldicr", 6))) {
							// { "rld[i]cr", "A = rol64(B, C) & D", 4},
							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 && !strncmp(argv[0], "rldimi", 6)) {
							// { "rldimi", "A = (rol64(B, C) & D) | (A & E)", 5}, //32
							// 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 && !strncmp(argv[0], "rldimi", 6)) {
							// { "rldimi", "A = (rol64(B, C) & D) | (A & E)", 5}, //32
							// 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 == 4 && !strncmp(argv[0], "rlwimi", 6)) {
							// { "rlwimi", "A = (rol64(B, C) & D) | (A & E)", 5}, //32
							// first mask (normal)
							w = ppc_mask;
							// MASK(MB, ME)
							ut32 MB = PPC_UT32(argv[4]);
							ut32 ME = PPC_UT32(argv[5]);
							snprintf(ppc_mask, sizeof(ppc_mask), "0x%" PFMT32x "", mask32(MB, ME));
						} else if (letter == 5 && !strncmp(argv[0], "rlwimi", 6)) {
							// { "rlwimi", "A = (rol32(B, C) & D) | (A & E)", 5}, //32
							// second mask (inverted)
							w = ppc_mask;
							// MASK(MB, ME)
							ut32 MB = PPC_UT32(argv[4]);
							ut32 ME = PPC_UT32(argv[5]);
							ut32 inverted = ~mask32(MB, ME);
							snprintf(ppc_mask, sizeof(ppc_mask), "0x%" PFMT32x "", inverted);
						} else if (letter == 4 && !strncmp(argv[0], "rlwnm", 5)) {
							// { "rlwnm", "A = rol32(B, C) & D", 5}, //32
							w = ppc_mask;
							// MASK(MB, ME)
							ut32 MB = PPC_UT32(argv[4]);
							ut32 ME = PPC_UT32(argv[5]);
							snprintf(ppc_mask, sizeof(ppc_mask), "0x%" PFMT32x "", mask32(MB, ME));
						} else if (letter == 1 && i >= 36 && i <= 43) {
							int to = atoi(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 ((i == 44 && letter == 2) || (i == 45 && letter == 1)) { // spr
							k += getspr_pseudo(w, newstr + k);
						}
						if (w != NULL) {
							strcpy(newstr + k, w);
							k += strlen(w) - 1;
						}
					} else {
						newstr[k] = ops[i].str[j];
					}
				}
				newstr[k] = '\0';
			}
			return true;
		}
	}

	/* TODO: this is slow */
	if (newstr) {
		newstr[0] = '\0';
		for (i = 0; i < argc; i++) {
			strcat(newstr, argv[i]);
			strcat(newstr, (i == 0 || i == argc - 1) ? " " : ", ");
		}
	}

	return false;
}

#define WSZ 128
static bool parse(RzParse *p, const char *data, RzStrBuf *sb) {
	int i, len = strlen(data);
	char w0[WSZ];
	char w1[WSZ];
	char w2[WSZ];
	char w3[WSZ];
	char w4[WSZ];
	char w5[WSZ];
	char str[1024] = { 0 };
	char *buf, *ptr, *optr;

	if (!strcmp(data, "jr ra")) {
		rz_strbuf_set(sb, "return");
		return true;
	}

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

	rz_str_replace_char(buf, '(', ',');
	rz_str_replace_char(buf, ')', ' ');
	rz_str_trim(buf);
	if (*buf) {
		w0[0] = '\0';
		w1[0] = '\0';
		w2[0] = '\0';
		w3[0] = '\0';
		w4[0] = '\0';
		ptr = strchr(buf, ' ');
		if (!ptr) {
			ptr = strchr(buf, '\t');
		}
		if (ptr) {
			*ptr = '\0';
			for (++ptr; *ptr == ' '; ptr++) {
				// nothing to see here
			}
			strncpy(w0, buf, WSZ - 1);
			strncpy(w1, ptr, WSZ - 1);

			optr = ptr;
			ptr = strchr(ptr, ',');
			if (ptr) {
				*ptr = '\0';
				for (++ptr; *ptr == ' '; ptr++) {
					// nothing to see here
				}
				strncpy(w1, optr, WSZ - 1);
				strncpy(w2, ptr, WSZ - 1);
				optr = ptr;
				ptr = strchr(ptr, ',');
				if (ptr) {
					*ptr = '\0';
					for (++ptr; *ptr == ' '; ptr++) {
						// nothing to see here
					}
					strncpy(w2, optr, WSZ - 1);
					strncpy(w3, ptr, WSZ - 1);
					optr = ptr;
					// bonus
					ptr = strchr(ptr, ',');
					if (ptr) {
						*ptr = '\0';
						for (++ptr; *ptr == ' '; ptr++) {
							// nothing to see here
						}
						strncpy(w3, optr, WSZ - 1);
						strncpy(w4, ptr, WSZ - 1);
						optr = ptr;
						// bonus
						ptr = strchr(ptr, ',');
						if (ptr) {
							*ptr = '\0';
							for (++ptr; *ptr == ' '; ptr++) {
								// nothing to see here
							}
							strncpy(w4, optr, WSZ - 1);
							strncpy(w5, ptr, WSZ - 1);
						}
					}
				}
			}
		} else {
			strncpy(w0, buf, WSZ - 1);
		}
		{
			const char *wa[] = { w0, w1, w2, w3, w4, w5 };
			int nw = 0;
			for (i = 0; i < 4; i++) {
				if (wa[i][0] != '\0') {
					nw++;
				}
			}
			replace(nw, wa, str);
			{
				char *p = rz_str_dup(str);
				p = rz_str_replace(p, "+ -", "- ", 0);
				p = rz_str_replace(p, " + ]", "]  ", 0);
				//  p = rz_str_replace (p, "if (r0 == r0) trap", "trap            ", 0);
#if EXPERIMENTAL_ZERO
				p = rz_str_replace(p, "zero", "0", 0);
				if (!memcmp(p, "0 = ", 4))
					*p = 0; // nop
#endif
				if (!strcmp(w1, w2)) {
					char a[64], b[64];
#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 = rz_str_replace(p, a, b, 0); \
		} \
	} while (0)

					// 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 <<=");
				}
				p = rz_str_replace(p, ":", "0000", 0);
				strcpy(str, p);
				free(p);
			}
		}
	}
	free(buf);
	rz_strbuf_set(sb, str);
	return true;
}

RzParsePlugin rz_parse_plugin_ppc_cs_pseudo = {
	.name = "ppc.pseudo",
	.desc = "PowerPC pseudo syntax",
	.parse = parse,
};
