summaryrefslogtreecommitdiff
path: root/arch/powerpc
diff options
context:
space:
mode:
authorGalen Williamson <galen@vector35.com>2025-06-29 11:23:58 -0400
committerGalen Williamson <galen@vector35.com>2025-06-29 18:28:48 -0400
commite8206bc27e1633c7e4c99907f43bf67d2f200cd5 (patch)
tree2315bec284e9bb692a0eb8986578fe18e2289d23 /arch/powerpc
parent91f1eccb6c41a7ef60fd66387ffae075f88141a4 (diff)
[powerpc] Full merge of PowerPC disassembler PRs, including:
* Remove dependency on capstone for PowerPC disassembly #6292 * Add support for PowerPC VLE instruction set #6740 * Add support for paired-single instructions #6821 * Various post-merge fixes and tweaks to disassembly and lifting * Removal of dependence on capstone for assembler's scoring mechanism (capstone currently disabled, but not removed from codebase yet)
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/CMakeLists.txt3
-rw-r--r--arch/powerpc/arch_ppc.cpp1153
-rw-r--r--arch/powerpc/assembler.cpp195
-rwxr-xr-xarch/powerpc/build_capstone_compare.sh2
-rw-r--r--arch/powerpc/capstone_compare_test.c1875
-rw-r--r--arch/powerpc/decode/decode.c6110
-rw-r--r--arch/powerpc/decode/decode.h1901
-rw-r--r--arch/powerpc/decode/mnemonic.c2188
-rw-r--r--arch/powerpc/decode/names.c296
-rw-r--r--arch/powerpc/decode/operands.c3288
-rw-r--r--arch/powerpc/decode/priv.c251
-rw-r--r--arch/powerpc/decode/priv.h54
-rw-r--r--arch/powerpc/decode/vle16.c790
-rw-r--r--arch/powerpc/decode/vle32.c715
-rw-r--r--arch/powerpc/disassembler.cpp467
-rw-r--r--arch/powerpc/disassembler.h99
-rw-r--r--arch/powerpc/il.cpp2352
-rw-r--r--arch/powerpc/il.h4
-rw-r--r--arch/powerpc/util.cpp101
-rw-r--r--arch/powerpc/util.h10
20 files changed, 19337 insertions, 2517 deletions
diff --git a/arch/powerpc/CMakeLists.txt b/arch/powerpc/CMakeLists.txt
index 7eff1eb1..a58a0dd2 100644
--- a/arch/powerpc/CMakeLists.txt
+++ b/arch/powerpc/CMakeLists.txt
@@ -11,8 +11,9 @@ file(GLOB SOURCES
assembler.cpp
disassembler.cpp
il.cpp
- util.cpp
*.h
+ decode/*.c
+ decode/*.h
)
if(DEMO)
diff --git a/arch/powerpc/arch_ppc.cpp b/arch/powerpc/arch_ppc.cpp
index ed95488f..f10757d5 100644
--- a/arch/powerpc/arch_ppc.cpp
+++ b/arch/powerpc/arch_ppc.cpp
@@ -12,9 +12,10 @@
#include "lowlevelilinstruction.h"
using namespace BinaryNinja; // for ::LogDebug, etc.
-#include "disassembler.h"
#include "assembler.h"
+#include "decode/decode.h"
+
#include "il.h"
#include "util.h"
@@ -281,8 +282,8 @@ class PowerpcArchitecture: public Architecture
{
private:
BNEndianness endian;
- int cs_mode_local;
size_t addressSize;
+ uint32_t decodeFlags;
/* this can maybe be moved to the API later */
BNRegisterInfo RegisterInfo(uint32_t fullWidthReg, size_t offset, size_t size, bool zeroExtend = false)
@@ -298,11 +299,13 @@ class PowerpcArchitecture: public Architecture
public:
/* initialization list */
- PowerpcArchitecture(const char* name, BNEndianness endian_, size_t addressSize_=4, int cs_mode_=0): Architecture(name)
+ PowerpcArchitecture(const char* name, BNEndianness endian_, size_t addressSize_=4, uint32_t decodeFlags_=DECODE_FLAGS_ALTIVEC | DECODE_FLAGS_VSX): Architecture(name)
{
endian = endian_;
addressSize = addressSize_;
- cs_mode_local = cs_mode_;
+ decodeFlags = decodeFlags_;
+ if (addressSize == 8)
+ decodeFlags |= DECODE_FLAGS_PPC64;
}
/*************************************************************************/
@@ -327,7 +330,10 @@ class PowerpcArchitecture: public Architecture
virtual size_t GetInstructionAlignment() const override
{
- return 4;
+ if ((decodeFlags & DECODE_FLAGS_VLE) != 0)
+ return 2;
+ else
+ return 4;
}
virtual size_t GetMaxInstructionLength() const override
@@ -335,6 +341,37 @@ class PowerpcArchitecture: public Architecture
return 4;
}
+ bool FillInstruction(Instruction* instruction, const uint8_t* data, size_t length, uint64_t address, uint32_t extraFlags = 0)
+ {
+ instruction->numBytes = length;
+ switch (instruction->numBytes)
+ {
+ case 2:
+ {
+ uint16_t word16 = *(const uint16_t *) data;
+ // VLE is always big-endian
+ word16 = bswap16(word16);
+
+ return Decompose16(instruction, word16, address, decodeFlags | extraFlags);
+ }
+
+ case 4:
+ {
+ uint32_t word32 = *(const uint32_t *) data;
+
+ // VLE is always big endian
+ if (((decodeFlags & DECODE_FLAGS_VLE) != 0) || endian == BigEndian)
+ word32 = bswap32(word32);
+
+ return Decompose32(instruction, word32, address, decodeFlags | extraFlags);
+ }
+
+ default:
+ MYLOG("FillInstruction: unrecognized length %d", length);
+ return false;
+ }
+ }
+
/* think "GetInstructionBranchBehavior()"
populates struct Instruction Info (api/binaryninjaapi.h)
@@ -348,168 +385,176 @@ class PowerpcArchitecture: public Architecture
virtual bool GetInstructionInfo(const uint8_t* data, uint64_t addr,
size_t maxLen, InstructionInfo& result) override
{
- struct decomp_result res;
- struct cs_insn *insn = &(res.insn);
-
- //MYLOG("%s()\n", __func__);
-
- if (maxLen < 4) {
- MYLOG("ERROR: need at least 4 bytes\n");
+ size_t instructionLength = GetInstructionLength(data, maxLen, decodeFlags);
+ if (instructionLength == 0)
+ {
+ MYLOG("ERROR: not enough bytes for instruction\n");
return false;
}
- if (DoesQualifyForLocalDisassembly(data, endian == BigEndian)) {
- result.length = 4;
- return true;
- }
+ result.length = instructionLength;
- /* decompose the instruction to get branch info */
- if(powerpc_decompose(data, 4, addr, endian == LittleEndian, &res, GetAddressSize() == 8, cs_mode_local)) {
- MYLOG("ERROR: powerpc_decompose()\n");
+ Instruction instruction;
+ if (!FillInstruction(&instruction, data, instructionLength, addr))
+ {
+ MYLOG("ERROR: FillInstruction()\n");
return false;
}
- uint32_t raw_insn = *(const uint32_t *) data;
+ uint32_t bo = instruction.operands[0].uimm;
- if (endian == BigEndian)
- raw_insn = bswap32(raw_insn);
-
- switch (raw_insn >> 26)
+ switch (instruction.id)
{
- case 18: /* b (b, ba, bl, bla) */
+ case PPC_ID_Bx:
+ case PPC_ID_VLE_E_Bx:
+ case PPC_ID_VLE_SE_Bx:
{
- uint64_t target = raw_insn & 0x03fffffc;
-
- /* sign extend target */
- target = sign_extend(addressSize, target, 25);
-
- /* account for absolute addressing */
- if (!(raw_insn & 2))
- {
- target += addr;
- ADDRMASK(addressSize, target);
- }
+ uint64_t target = instruction.operands[0].label;
- if (raw_insn & 1)
+ if (instruction.flags.lk)
result.AddBranch(CallDestination, target);
else
result.AddBranch(UnconditionalBranch, target);
-
break;
}
- case 16: /* bc */
- {
- uint64_t target = raw_insn & 0xfffc;
- uint8_t bo = (raw_insn >> 21) & 0x1f;
- bool lk = raw_insn & 1;
-
- /* sign extend target */
- target = sign_extend(addressSize, target, 15);
- /* account for absolute addressing */
- if (!(raw_insn & 2))
- {
- target += addr;
- ADDRMASK(addressSize, target);
- }
+ case PPC_ID_BCx:
+ case PPC_ID_VLE_E_BCx:
+ case PPC_ID_VLE_SE_BC:
+ {
+ uint64_t target = instruction.operands[2].label;
- if (target != addr + 4)
+ if (target != addr + instructionLength)
{
if ((bo & 0x14) == 0x14)
- result.AddBranch(lk ? CallDestination : UnconditionalBranch, target);
- else if (!lk)
{
- result.AddBranch(FalseBranch, addr + 4);
+ result.AddBranch(instruction.flags.lk ? CallDestination : UnconditionalBranch, target);
+ }
+ else if (!instruction.flags.lk)
+ {
+ result.AddBranch(FalseBranch, addr + instructionLength);
result.AddBranch(TrueBranch, target);
}
}
-
break;
}
- case 19: /* bcctr, bclr */
- {
- uint8_t bo = (raw_insn >> 21) & 0x1f;
- bool lk = raw_insn & 1;
- bool blr = false;
- switch ((raw_insn >> 1) & 0x3ff)
- {
- case 16:
- blr = true;
- FALL_THROUGH
- case 528:
- if ((bo & 0x14) == 0x14 && !lk)
- result.AddBranch(blr ? FunctionReturn : UnresolvedBranch);
-
- break;
- }
+ case PPC_ID_BCLRx:
+ case PPC_ID_VLE_SE_BLRx:
+ if (!instruction.flags.lk && (bo & 0x14) == 0x14)
+ result.AddBranch(FunctionReturn);
+ break;
+ case PPC_ID_BCCTRx:
+ case PPC_ID_VLE_SE_BCTRx:
+ if (!instruction.flags.lk && (bo & 0x14) == 0x14)
+ result.AddBranch(UnresolvedBranch);
break;
- }
- }
- switch(insn->id) {
- case PPC_INS_TRAP:
+ case PPC_ID_TWU:
result.AddBranch(UnresolvedBranch);
break;
- case PPC_INS_RFI:
- result.AddBranch(UnresolvedBranch);
+
+ case PPC_ID_RFI:
+ case PPC_ID_VLE_SE_RFI:
+ result.AddBranch(FunctionReturn);
+ break;
+ default:
break;
}
- result.length = 4;
return true;
}
- bool PrintLocalDisassembly(const uint8_t *data, uint64_t addr, size_t &len, vector<InstructionTextToken> &result, decomp_result* res)
+ // Returns whether any token was pushed (ie if operand is implied)
+ bool PushOperandTokens(vector<InstructionTextToken>& result, const Operand* op)
{
- (void)addr;
- char buf[16];
- uint32_t local_op = PPC_INS_INVALID;
+ char buf[32];
+ switch (op->cls)
+ {
+ case PPC_OP_REG_CRFD_IMPLY0:
+ case PPC_OP_REG_CRFS_IMPLY0:
+ if (op->reg == PPC_REG_CRF0)
+ return false;
- struct cs_detail *detail = 0;
- struct cs_ppc *ppc = 0;
- struct cs_insn *insn = &(res->insn);
+ result.emplace_back(RegisterToken, GetRegisterName(op->reg));
- detail = &(res->detail);
- ppc = &(detail->ppc);
+ break;
- if (len < 4)
- return false;
- len = 4;
+ case PPC_OP_REG_RA:
+ case PPC_OP_REG_RB:
+ case PPC_OP_REG_RD:
+ case PPC_OP_REG_RS:
+ case PPC_OP_REG_FRA:
+ case PPC_OP_REG_FRB:
+ case PPC_OP_REG_FRC:
+ case PPC_OP_REG_FRD:
+ case PPC_OP_REG_FRS:
+ case PPC_OP_REG_CRFD:
+ case PPC_OP_REG_CRFS:
+ case PPC_OP_REG_AV_VA:
+ case PPC_OP_REG_AV_VB:
+ case PPC_OP_REG_AV_VC:
+ case PPC_OP_REG_AV_VD:
+ case PPC_OP_REG_AV_VS:
+ case PPC_OP_REG_VSX_RA:
+ case PPC_OP_REG_VSX_RA_DWORD0:
+ case PPC_OP_REG_VSX_RB:
+ case PPC_OP_REG_VSX_RB_DWORD0:
+ case PPC_OP_REG_VSX_RC:
+ case PPC_OP_REG_VSX_RC_DWORD0:
+ case PPC_OP_REG_VSX_RD:
+ case PPC_OP_REG_VSX_RD_DWORD0:
+ case PPC_OP_REG_VSX_RS:
+ case PPC_OP_REG_VSX_RS_DWORD0:
+ result.emplace_back(RegisterToken, GetRegisterName(op->reg));
+ break;
- local_op = DoesQualifyForLocalDisassembly(data, endian == BigEndian);
- PerformLocalDisassembly(data, addr, len, res, endian == BigEndian);
+ case PPC_OP_UIMM:
+ snprintf(buf, sizeof(buf), "0x%" PRIx64, op->uimm);
+ result.emplace_back(IntegerToken, buf, op->uimm, 4);
+ break;
- switch (local_op)
- {
- case PPC_INS_BN_FCMPO:
- result.emplace_back(InstructionToken, insn->mnemonic);
- result.emplace_back(TextToken, " ");
- snprintf(buf, sizeof(buf), "cr%d", ppc->operands[0].reg - PPC_REG_CR0);
- result.emplace_back(RegisterToken, buf);
- result.emplace_back(OperandSeparatorToken, ", ");
- snprintf(buf, sizeof(buf), "f%d", ppc->operands[1].reg - PPC_REG_F0);
- result.emplace_back(RegisterToken, buf);
- result.emplace_back(OperandSeparatorToken, ", ");
- snprintf(buf, sizeof(buf), "f%d", ppc->operands[2].reg - PPC_REG_F0);
- result.emplace_back(RegisterToken, buf);
- break;
- case PPC_INS_BN_XXPERMR:
- result.emplace_back(InstructionToken, insn->mnemonic);
- result.emplace_back(TextToken, " ");
- snprintf(buf, sizeof(buf), "vs%d", ppc->operands[0].reg - PPC_REG_VS0);
- result.emplace_back(RegisterToken, buf);
- result.emplace_back(OperandSeparatorToken, ", ");
- snprintf(buf, sizeof(buf), "vs%d", ppc->operands[1].reg - PPC_REG_VS0);
- result.emplace_back(RegisterToken, buf);
- result.emplace_back(OperandSeparatorToken, ", ");
- snprintf(buf, sizeof(buf), "vs%d", ppc->operands[2].reg - PPC_REG_VS0);
- result.emplace_back(RegisterToken, buf);
- break;
- default:
- return false;
+ case PPC_OP_SIMM:
+ if (op->simm < 0 && op->simm > -0x10000)
+ snprintf(buf, sizeof(buf), "-0x%llx", -op->simm);
+ else
+ snprintf(buf, sizeof(buf), "0x%llx", op->simm);
+ result.emplace_back(IntegerToken, buf, op->simm, 4);
+ break;
+
+ case PPC_OP_LABEL:
+ snprintf(buf, sizeof(buf), "0x%llx", op->label);
+ result.emplace_back(CodeRelativeAddressToken, buf, op->label, 4);
+ break;
+
+ case PPC_OP_CRBIT_A:
+ case PPC_OP_CRBIT_B:
+ case PPC_OP_CRBIT_D:
+ result.emplace_back(RegisterToken, GetCRBitName(op->crbit));
+ break;
+
+ case PPC_OP_MEM_RA:
+ // eg: lwz r11, 8(r11)
+ //
+ // TODO: it would be nice to have the option to print these
+ // in hex; printed in decimal now for backwards compatibility
+ snprintf(buf, sizeof(buf), "%d", op->mem.offset);
+ result.emplace_back(IntegerToken, buf, op->mem.offset, 4);
+
+ result.emplace_back(BraceToken, "(");
+ if (op->mem.reg == PPC_REG_GPR0)
+ result.emplace_back(PossibleAddressToken, "0", 0, 4);
+ else
+ result.emplace_back(RegisterToken, GetRegisterName(op->mem.reg));
+ result.emplace_back(BraceToken, ")");
+ break;
+
+ default:
+ //MYLOG("pushing a ???\n");
+ result.emplace_back(TextToken, "???");
}
+
return true;
}
@@ -518,129 +563,88 @@ class PowerpcArchitecture: public Architecture
*/
virtual bool GetInstructionText(const uint8_t* data, uint64_t addr, size_t& len, vector<InstructionTextToken>& result) override
{
- bool rc = false;
- bool capstoneWorkaround = false;
char buf[32];
size_t strlenMnem;
- struct decomp_result res;
- struct cs_insn *insn = &(res.insn);
- struct cs_detail *detail = &(res.detail);
- struct cs_ppc *ppc = &(detail->ppc);
+ Instruction instruction;
+ const char* mnemonic = NULL;
//MYLOG("%s()\n", __func__);
-
- if (len < 4) {
- MYLOG("ERROR: need at least 4 bytes\n");
- goto cleanup;
- }
-
- if (DoesQualifyForLocalDisassembly(data, endian == BigEndian))
+ size_t instructionLength = GetInstructionLength(data, len, decodeFlags);
+ if (instructionLength == 0)
{
- // PerformLocalDisassembly(data, addr, len, &res, endian == BigEndian);
- return PrintLocalDisassembly(data, addr, len, result, &res);
- }
- if(powerpc_decompose(data, 4, addr, endian == LittleEndian, &res, GetAddressSize() == 8, cs_mode_local)) {
- MYLOG("ERROR: powerpc_decompose()\n");
- goto cleanup;
+ MYLOG("ERROR: not enough bytes for instruction\n");
+ return false;
}
- switch (insn->id)
+ len = instructionLength;
+ if (!FillInstruction(&instruction, data, instructionLength, addr))
{
- case PPC_INS_CRAND:
- case PPC_INS_CRANDC:
- case PPC_INS_CRNAND:
- case PPC_INS_CROR:
- case PPC_INS_CRORC:
- case PPC_INS_CRNOR:
- case PPC_INS_CREQV:
- case PPC_INS_CRXOR:
- case PPC_INS_CRSET:
- case PPC_INS_CRCLR:
- case PPC_INS_CRNOT:
- case PPC_INS_CRMOVE:
- capstoneWorkaround = true;
+ MYLOG("ERROR: FillInstruction()\n");
+ return false;
}
/* mnemonic */
- result.emplace_back(InstructionToken, insn->mnemonic);
+ mnemonic = GetMnemonic(&instruction);
+ result.emplace_back(InstructionToken, mnemonic);
/* padding between mnemonic and operands */
memset(buf, ' ', 8);
- strlenMnem = strlen(insn->mnemonic);
- if(strlenMnem < 8)
+ strlenMnem = strlen(mnemonic);
+ if (strlenMnem < 8)
buf[8-strlenMnem] = '\0';
else
buf[1] = '\0';
result.emplace_back(TextToken, buf);
- /* operands */
- for(int i=0; i<ppc->op_count; ++i) {
- struct cs_ppc_op *op = &(ppc->operands[i]);
-
- switch(op->type) {
- case PPC_OP_REG:
- //MYLOG("pushing a register\n");
- if (capstoneWorkaround || (insn->id == PPC_INS_ISEL && i == 3))
- result.emplace_back(RegisterToken, GetFlagName(op->reg));
- else
- result.emplace_back(RegisterToken, GetRegisterName(op->reg));
- break;
- case PPC_OP_IMM:
- //MYLOG("pushing an integer\n");
+ // To make IL easier to reason about, sometimes an instruction's
+ // internal representation always has an operand that's omitted
+ // in assembly; we take care of overriding those cases here
+ OperandsList operand_list;
+ memset(&operand_list, 0, sizeof(operand_list));
- switch(insn->id) {
- case PPC_INS_B:
- case PPC_INS_BA:
- case PPC_INS_BC:
- case PPC_INS_BCL:
- case PPC_INS_BL:
- case PPC_INS_BLA:
- snprintf(buf, sizeof(buf), "0x%" PRIx64, op->imm);
- result.emplace_back(CodeRelativeAddressToken, buf, (uint32_t) op->imm, 4);
- break;
- case PPC_INS_ORIS:
- case PPC_INS_XORIS:
- case PPC_INS_ORI:
- case PPC_INS_ANDI:
- case PPC_INS_ANDIS:
- snprintf(buf, sizeof(buf), "0x%x", (uint16_t)op->imm);
- result.emplace_back(IntegerToken, buf, (uint16_t) op->imm, 4);
- break;
- default:
- if (op->imm < 0 && op->imm > -0x10000)
- snprintf(buf, sizeof(buf), "-0x%" PRIx64, -op->imm);
- else
- snprintf(buf, sizeof(buf), "0x%" PRIx64, op->imm);
- result.emplace_back(IntegerToken, buf, op->imm, 4);
- }
+ // The default is to just copy every operand, to simplify the
+ // alternate code path for special cases
+ operand_list.numOperands = instruction.numOperands;
+ for (int i = 0; i < instruction.numOperands; ++i)
+ {
+ operand_list.operands[i] = instruction.operands[i];
+ }
- break;
- case PPC_OP_MEM:
- // eg: lwz r11, 8(r11)
- snprintf(buf, sizeof(buf), "%d", op->mem.disp);
- result.emplace_back(IntegerToken, buf, op->mem.disp, 4);
+ switch(instruction.id)
+ {
+ case PPC_ID_BCx:
+ FillBcxOperands(&operand_list, &instruction);
+ break;
+ case PPC_ID_BCCTRx:
+ FillBcctrxOperands(&operand_list, &instruction);
+ break;
+ case PPC_ID_BCLRx:
+ FillBclrxOperands(&operand_list, &instruction);
+ break;
+ case PPC_ID_VLE_SE_BC:
+ FillVle16BcOperands(&operand_list, &instruction);
+ break;
+ case PPC_ID_VLE_E_BCx:
+ FillVle32BcxOperands(&operand_list, &instruction);
+ break;
+ default:
+ // Already copied by default
+ ;
+ }
- result.emplace_back(BraceToken, "(");
- result.emplace_back(RegisterToken, GetRegisterName(op->mem.base));
- result.emplace_back(BraceToken, ")");
- break;
- case PPC_OP_CRX:
- case PPC_OP_INVALID:
- default:
- //MYLOG("pushing a ???\n");
- result.emplace_back(TextToken, "???");
- }
+ for (int i = 0; i < operand_list.numOperands; ++i)
+ {
+ Operand* op = &(operand_list.operands[i]);
+ bool was_pushed = PushOperandTokens(result, op);
- if(i < ppc->op_count-1) {
+ if (was_pushed && i < operand_list.numOperands - 1)
+ {
//MYLOG("pushing a comma\n");
result.emplace_back(OperandSeparatorToken, ", ");
}
}
- rc = true;
- len = 4;
- cleanup:
- return rc;
+ return true;
}
static string GetIntrinsicName_ppc_ps(uint32_t intrinsic)
@@ -666,7 +670,7 @@ class PowerpcArchitecture: public Architecture
case PPC_INTRIN_FRSP:
return "float_round";
default:
- if (cs_mode_local == CS_MODE_PS)
+ if ((decodeFlags & DECODE_FLAGS_PS))
{
return GetIntrinsicName_ppc_ps(intrinsic);
}
@@ -726,7 +730,7 @@ class PowerpcArchitecture: public Architecture
return {NameAndType(Type::FloatType(4))};
// for now, quantize is operating on the float in, and the gqr that holds the scale
default:
- if (cs_mode_local == CS_MODE_PS)
+ if ((decodeFlags & DECODE_FLAGS_PS))
{
return GetIntrinsicInputs_ppc_ps(intrinsic);
}
@@ -759,7 +763,7 @@ class PowerpcArchitecture: public Architecture
case PPC_INTRIN_FRSP:
return {Type::FloatType(4)};
default:
- if (cs_mode_local == CS_MODE_PS)
+ if ((decodeFlags & DECODE_FLAGS_PS))
{
return GetIntrinsicOutputs_ppc_ps(intrinsic);
}
@@ -771,33 +775,24 @@ class PowerpcArchitecture: public Architecture
virtual bool GetInstructionLowLevelIL(const uint8_t* data, uint64_t addr, size_t& len, LowLevelILFunction& il) override
{
- bool rc = false;
- struct decomp_result res = {0};
-
- if (len < 4) {
- MYLOG("ERROR: need at least 4 bytes\n");
- goto cleanup;
+ size_t instructionLength = GetInstructionLength(data, len, decodeFlags);
+ if (instructionLength == 0)
+ {
+ MYLOG("ERROR: not enough bytes for instruction\n");
+ return false;
}
- //if(addr >= 0x10000300 && addr <= 0x10000320) {
- // MYLOG("%s(data, 0x%llX, 0x%zX, il)\n", __func__, addr, len);
- //}
+ len = instructionLength;
- if (DoesQualifyForLocalDisassembly(data, endian == BigEndian)) {
- PerformLocalDisassembly(data, addr, len, &res, endian == BigEndian);
- }
- else if(powerpc_decompose(data, 4, addr, endian == LittleEndian, &res, GetAddressSize() == 8, cs_mode_local)) {
- MYLOG("ERROR: powerpc_decompose()\n");
+ Instruction instruction;
+ if (!FillInstruction(&instruction, data, instructionLength, addr, DECODE_FLAGS_VLE_TRANSLATE))
+ {
+ MYLOG("ERROR: FillInstruction()\n");
il.AddInstruction(il.Undefined());
- goto cleanup;
+ return false;
}
-// getil:
- rc = GetLowLevelILForPPCInstruction(this, il, data, addr, &res, endian == LittleEndian);
- len = 4;
-
- cleanup:
- return rc;
+ return GetLowLevelILForPPCInstruction(this, il, &instruction, addr);
}
virtual size_t GetFlagWriteLowLevelIL(BNLowLevelILOperation op, size_t size, uint32_t flagWriteType,
@@ -959,9 +954,9 @@ class PowerpcArchitecture: public Architecture
virtual string GetRegisterName(uint32_t regId) override
{
- const char *result = powerpc_reg_to_str(regId, cs_mode_local);
+ const char *result = PowerPCRegisterName(regId);
- if(result == NULL)
+ if (result == NULL)
result = "";
//MYLOG("%s(%d) returns %s\n", __func__, regId, result);
@@ -999,8 +994,7 @@ class PowerpcArchitecture: public Architecture
virtual string GetFlagName(uint32_t flag) override
{
// MYLOG("%s() flag:%d\n", __func__, flag);
-
- switch(powerpc_crx_to_reg(flag)) {
+ switch(flag) {
case IL_FLAG_LT: return "lt";
case IL_FLAG_GT: return "gt";
case IL_FLAG_EQ: return "eq";
@@ -1465,15 +1459,15 @@ class PowerpcArchitecture: public Architecture
case IL_FLAG_EQ_6:
case IL_FLAG_EQ_7:
return ZeroFlagRole;
- // case IL_FLAG_SO:
- // case IL_FLAG_SO_1:
- // case IL_FLAG_SO_2:
- // case IL_FLAG_SO_3:
- // case IL_FLAG_SO_4:
- // case IL_FLAG_SO_5:
- // case IL_FLAG_SO_6:
- // case IL_FLAG_SO_7:
- // case IL_FLAG_XER_SO:
+ case IL_FLAG_SO:
+ case IL_FLAG_SO_1:
+ case IL_FLAG_SO_2:
+ case IL_FLAG_SO_3:
+ case IL_FLAG_SO_4:
+ case IL_FLAG_SO_5:
+ case IL_FLAG_SO_6:
+ case IL_FLAG_SO_7:
+ case IL_FLAG_XER_SO:
case IL_FLAG_XER_OV:
return OverflowFlagRole;
case IL_FLAG_XER_CA:
@@ -1548,10 +1542,14 @@ class PowerpcArchitecture: public Architecture
// MYLOG("%s()\n", __func__);
return vector<uint32_t>{
- PPC_REG_R0, PPC_REG_R1, PPC_REG_R2, PPC_REG_R3, PPC_REG_R4, PPC_REG_R5, PPC_REG_R6, PPC_REG_R7,
- PPC_REG_R8, PPC_REG_R9, PPC_REG_R10, PPC_REG_R11, PPC_REG_R12, PPC_REG_R13, PPC_REG_R14, PPC_REG_R15,
- PPC_REG_R16, PPC_REG_R17, PPC_REG_R18, PPC_REG_R19, PPC_REG_R20, PPC_REG_R21, PPC_REG_R22, PPC_REG_R23,
- PPC_REG_R24, PPC_REG_R25, PPC_REG_R26, PPC_REG_R27, PPC_REG_R28, PPC_REG_R29, PPC_REG_R30, PPC_REG_R31
+ PPC_REG_GPR0, PPC_REG_GPR1, PPC_REG_GPR2, PPC_REG_GPR3,
+ PPC_REG_GPR4, PPC_REG_GPR5, PPC_REG_GPR6, PPC_REG_GPR7,
+ PPC_REG_GPR8, PPC_REG_GPR9, PPC_REG_GPR10, PPC_REG_GPR11,
+ PPC_REG_GPR12, PPC_REG_GPR13, PPC_REG_GPR14, PPC_REG_GPR15,
+ PPC_REG_GPR16, PPC_REG_GPR17, PPC_REG_GPR18, PPC_REG_GPR19,
+ PPC_REG_GPR20, PPC_REG_GPR21, PPC_REG_GPR22, PPC_REG_GPR23,
+ PPC_REG_GPR24, PPC_REG_GPR25, PPC_REG_GPR26, PPC_REG_GPR27,
+ PPC_REG_GPR28, PPC_REG_GPR29, PPC_REG_GPR30, PPC_REG_GPR31
};
}
@@ -1561,43 +1559,76 @@ class PowerpcArchitecture: public Architecture
vector<uint32_t> result = {
PPC_REG_CARRY,
- PPC_REG_CR0, PPC_REG_CR1, PPC_REG_CR2, PPC_REG_CR3, PPC_REG_CR4, PPC_REG_CR5, PPC_REG_CR6, PPC_REG_CR7,
+ PPC_REG_CRF0, PPC_REG_CRF1, PPC_REG_CRF2, PPC_REG_CRF3, PPC_REG_CRF4, PPC_REG_CRF5, PPC_REG_CRF6, PPC_REG_CRF7,
PPC_REG_CTR,
- PPC_REG_F0, PPC_REG_F1, PPC_REG_F2, PPC_REG_F3, PPC_REG_F4, PPC_REG_F5, PPC_REG_F6, PPC_REG_F7,
- PPC_REG_F8, PPC_REG_F9, PPC_REG_F10, PPC_REG_F11, PPC_REG_F12, PPC_REG_F13, PPC_REG_F14, PPC_REG_F15,
- PPC_REG_F16, PPC_REG_F17, PPC_REG_F18, PPC_REG_F19, PPC_REG_F20, PPC_REG_F21, PPC_REG_F22, PPC_REG_F23,
- PPC_REG_F24, PPC_REG_F25, PPC_REG_F26, PPC_REG_F27, PPC_REG_F28, PPC_REG_F29, PPC_REG_F30, PPC_REG_F31,
+ PPC_REG_FR0, PPC_REG_FR1, PPC_REG_FR2, PPC_REG_FR3,
+ PPC_REG_FR4, PPC_REG_FR5, PPC_REG_FR6, PPC_REG_FR7,
+ PPC_REG_FR8, PPC_REG_FR9, PPC_REG_FR10, PPC_REG_FR11,
+ PPC_REG_FR12, PPC_REG_FR13, PPC_REG_FR14, PPC_REG_FR15,
+ PPC_REG_FR16, PPC_REG_FR17, PPC_REG_FR18, PPC_REG_FR19,
+ PPC_REG_FR20, PPC_REG_FR21, PPC_REG_FR22, PPC_REG_FR23,
+ PPC_REG_FR24, PPC_REG_FR25, PPC_REG_FR26, PPC_REG_FR27,
+ PPC_REG_FR28, PPC_REG_FR29, PPC_REG_FR30, PPC_REG_FR31,
+
+ PPC_REG_GPR0, PPC_REG_GPR1, PPC_REG_GPR2, PPC_REG_GPR3,
+ PPC_REG_GPR4, PPC_REG_GPR5, PPC_REG_GPR6, PPC_REG_GPR7,
+ PPC_REG_GPR8, PPC_REG_GPR9, PPC_REG_GPR10, PPC_REG_GPR11,
+ PPC_REG_GPR12, PPC_REG_GPR13, PPC_REG_GPR14, PPC_REG_GPR15,
+ PPC_REG_GPR16, PPC_REG_GPR17, PPC_REG_GPR18, PPC_REG_GPR19,
+ PPC_REG_GPR20, PPC_REG_GPR21, PPC_REG_GPR22, PPC_REG_GPR23,
+ PPC_REG_GPR24, PPC_REG_GPR25, PPC_REG_GPR26, PPC_REG_GPR27,
+ PPC_REG_GPR28, PPC_REG_GPR29, PPC_REG_GPR30, PPC_REG_GPR31,
+
+ PPC_REG_XER, PPC_REG_LR, // PPC_REG_CTR,
- PPC_REG_LR,
+ // PPC_REG_FR0, PPC_REG_FR1, PPC_REG_FR2, PPC_REG_FR3,
+ // PPC_REG_FR4, PPC_REG_FR5, PPC_REG_FR6, PPC_REG_FR7,
+ // PPC_REG_FR8, PPC_REG_FR9, PPC_REG_FR10, PPC_REG_FR11,
+ // PPC_REG_FR12, PPC_REG_FR13, PPC_REG_FR14, PPC_REG_FR15,
+ // PPC_REG_FR16, PPC_REG_FR17, PPC_REG_FR18, PPC_REG_FR19,
+ // PPC_REG_FR20, PPC_REG_FR21, PPC_REG_FR22, PPC_REG_FR23,
+ // PPC_REG_FR24, PPC_REG_FR25, PPC_REG_FR26, PPC_REG_FR27,
+ // PPC_REG_FR28, PPC_REG_FR29, PPC_REG_FR30, PPC_REG_FR31,
- PPC_REG_R0, PPC_REG_R1, PPC_REG_R2, PPC_REG_R3, PPC_REG_R4, PPC_REG_R5, PPC_REG_R6, PPC_REG_R7,
- PPC_REG_R8, PPC_REG_R9, PPC_REG_R10, PPC_REG_R11, PPC_REG_R12, PPC_REG_R13, PPC_REG_R14, PPC_REG_R15,
- PPC_REG_R16, PPC_REG_R17, PPC_REG_R18, PPC_REG_R19, PPC_REG_R20, PPC_REG_R21, PPC_REG_R22, PPC_REG_R23,
- PPC_REG_R24, PPC_REG_R25, PPC_REG_R26, PPC_REG_R27, PPC_REG_R28, PPC_REG_R29, PPC_REG_R30, PPC_REG_R31,
+ // PPC_REG_CRF0, PPC_REG_CRF1, PPC_REG_CRF2, PPC_REG_CRF3,
+ // PPC_REG_CRF4, PPC_REG_CRF5, PPC_REG_CRF6, PPC_REG_CRF7,
- PPC_REG_V0, PPC_REG_V1, PPC_REG_V2, PPC_REG_V3, PPC_REG_V4, PPC_REG_V5, PPC_REG_V6, PPC_REG_V7,
- PPC_REG_V8, PPC_REG_V9, PPC_REG_V10, PPC_REG_V11, PPC_REG_V12, PPC_REG_V13, PPC_REG_V14, PPC_REG_V15,
- PPC_REG_V16, PPC_REG_V17, PPC_REG_V18, PPC_REG_V19, PPC_REG_V20, PPC_REG_V21, PPC_REG_V22, PPC_REG_V23,
- PPC_REG_V24, PPC_REG_V25, PPC_REG_V26, PPC_REG_V27, PPC_REG_V28, PPC_REG_V29, PPC_REG_V30, PPC_REG_V31,
+ PPC_REG_AV_VR0, PPC_REG_AV_VR1, PPC_REG_AV_VR2, PPC_REG_AV_VR3,
+ PPC_REG_AV_VR4, PPC_REG_AV_VR5, PPC_REG_AV_VR6, PPC_REG_AV_VR7,
+ PPC_REG_AV_VR8, PPC_REG_AV_VR9, PPC_REG_AV_VR10, PPC_REG_AV_VR11,
+ PPC_REG_AV_VR12, PPC_REG_AV_VR13, PPC_REG_AV_VR14, PPC_REG_AV_VR15,
+ PPC_REG_AV_VR16, PPC_REG_AV_VR17, PPC_REG_AV_VR18, PPC_REG_AV_VR19,
+ PPC_REG_AV_VR20, PPC_REG_AV_VR21, PPC_REG_AV_VR22, PPC_REG_AV_VR23,
+ PPC_REG_AV_VR24, PPC_REG_AV_VR25, PPC_REG_AV_VR26, PPC_REG_AV_VR27,
+ PPC_REG_AV_VR28, PPC_REG_AV_VR29, PPC_REG_AV_VR30, PPC_REG_AV_VR31,
PPC_REG_VRSAVE,
- PPC_REG_VS0, PPC_REG_VS1, PPC_REG_VS2, PPC_REG_VS3, PPC_REG_VS4, PPC_REG_VS5, PPC_REG_VS6, PPC_REG_VS7,
- PPC_REG_VS8, PPC_REG_VS9, PPC_REG_VS10, PPC_REG_VS11, PPC_REG_VS12, PPC_REG_VS13, PPC_REG_VS14, PPC_REG_VS15,
- PPC_REG_VS16, PPC_REG_VS17, PPC_REG_VS18, PPC_REG_VS19, PPC_REG_VS20, PPC_REG_VS21, PPC_REG_VS22, PPC_REG_VS23,
- PPC_REG_VS24, PPC_REG_VS25, PPC_REG_VS26, PPC_REG_VS27, PPC_REG_VS28, PPC_REG_VS29, PPC_REG_VS30, PPC_REG_VS31,
- PPC_REG_VS32, PPC_REG_VS33, PPC_REG_VS34, PPC_REG_VS35, PPC_REG_VS36, PPC_REG_VS37, PPC_REG_VS38, PPC_REG_VS39,
- PPC_REG_VS40, PPC_REG_VS41, PPC_REG_VS42, PPC_REG_VS43, PPC_REG_VS44, PPC_REG_VS45, PPC_REG_VS46, PPC_REG_VS47,
- PPC_REG_VS48, PPC_REG_VS49, PPC_REG_VS50, PPC_REG_VS51, PPC_REG_VS52, PPC_REG_VS53, PPC_REG_VS54, PPC_REG_VS55,
- PPC_REG_VS56, PPC_REG_VS57, PPC_REG_VS58, PPC_REG_VS59, PPC_REG_VS60, PPC_REG_VS61, PPC_REG_VS62, PPC_REG_VS63,
+ PPC_REG_VSX_VR0, PPC_REG_VSX_VR1, PPC_REG_VSX_VR2, PPC_REG_VSX_VR3,
+ PPC_REG_VSX_VR4, PPC_REG_VSX_VR5, PPC_REG_VSX_VR6, PPC_REG_VSX_VR7,
+ PPC_REG_VSX_VR8, PPC_REG_VSX_VR9, PPC_REG_VSX_VR10, PPC_REG_VSX_VR11,
+ PPC_REG_VSX_VR12, PPC_REG_VSX_VR13, PPC_REG_VSX_VR14, PPC_REG_VSX_VR15,
+ PPC_REG_VSX_VR16, PPC_REG_VSX_VR17, PPC_REG_VSX_VR18, PPC_REG_VSX_VR19,
+ PPC_REG_VSX_VR20, PPC_REG_VSX_VR21, PPC_REG_VSX_VR22, PPC_REG_VSX_VR23,
+ PPC_REG_VSX_VR24, PPC_REG_VSX_VR25, PPC_REG_VSX_VR26, PPC_REG_VSX_VR27,
+ PPC_REG_VSX_VR28, PPC_REG_VSX_VR29, PPC_REG_VSX_VR30, PPC_REG_VSX_VR31,
+ PPC_REG_VSX_VR32, PPC_REG_VSX_VR33, PPC_REG_VSX_VR34, PPC_REG_VSX_VR35,
+ PPC_REG_VSX_VR36, PPC_REG_VSX_VR37, PPC_REG_VSX_VR38, PPC_REG_VSX_VR39,
+ PPC_REG_VSX_VR40, PPC_REG_VSX_VR41, PPC_REG_VSX_VR42, PPC_REG_VSX_VR43,
+ PPC_REG_VSX_VR44, PPC_REG_VSX_VR45, PPC_REG_VSX_VR46, PPC_REG_VSX_VR47,
+ PPC_REG_VSX_VR48, PPC_REG_VSX_VR49, PPC_REG_VSX_VR50, PPC_REG_VSX_VR51,
+ PPC_REG_VSX_VR52, PPC_REG_VSX_VR53, PPC_REG_VSX_VR54, PPC_REG_VSX_VR55,
+ PPC_REG_VSX_VR56, PPC_REG_VSX_VR57, PPC_REG_VSX_VR58, PPC_REG_VSX_VR59,
+ PPC_REG_VSX_VR60, PPC_REG_VSX_VR61, PPC_REG_VSX_VR62, PPC_REG_VSX_VR63,
};
vector<uint32_t> gqrarray = {
- PPC_REG_BN_GQR0, PPC_REG_BN_GQR1, PPC_REG_BN_GQR2, PPC_REG_BN_GQR3,
- PPC_REG_BN_GQR4, PPC_REG_BN_GQR5, PPC_REG_BN_GQR6, PPC_REG_BN_GQR7};
+ PPC_REG_GQR0, PPC_REG_GQR1, PPC_REG_GQR2, PPC_REG_GQR3,
+ PPC_REG_GQR4, PPC_REG_GQR5, PPC_REG_GQR6, PPC_REG_GQR7
+ };
- if ((cs_mode_local & CS_MODE_PS) != 0)
+ if ((decodeFlags & DECODE_FLAGS_PS) != 0)
{
result.insert(result.end(), gqrarray.begin(), gqrarray.end());
}
@@ -1608,7 +1639,7 @@ class PowerpcArchitecture: public Architecture
virtual std::vector<uint32_t> GetGlobalRegisters() override
{
- return vector<uint32_t>{ PPC_REG_R2, PPC_REG_R13 };
+ return vector<uint32_t>{ PPC_REG_GPR2, PPC_REG_GPR13 };
}
@@ -1618,195 +1649,204 @@ class PowerpcArchitecture: public Architecture
and our size */
virtual BNRegisterInfo GetRegisterInfo(uint32_t regId) override
{
- //MYLOG("%s(%s)\n", __func__, powerpc_reg_to_str(regId));
+ //MYLOG("%s(%s)\n", __func__, PowerPCRegisterName(regId));
switch(regId) {
- // BNRegisterInfo RegisterInfo(uint32_t fullWidthReg, size_t offset,
- // size_t size, bool zeroExtend = false)
+
+ case PPC_REG_GPR0: return RegisterInfo(PPC_REG_GPR0, 0, addressSize);
+ case PPC_REG_GPR1: return RegisterInfo(PPC_REG_GPR1, 0, addressSize);
+ case PPC_REG_GPR2: return RegisterInfo(PPC_REG_GPR2, 0, addressSize);
+ case PPC_REG_GPR3: return RegisterInfo(PPC_REG_GPR3, 0, addressSize);
+ case PPC_REG_GPR4: return RegisterInfo(PPC_REG_GPR4, 0, addressSize);
+ case PPC_REG_GPR5: return RegisterInfo(PPC_REG_GPR5, 0, addressSize);
+ case PPC_REG_GPR6: return RegisterInfo(PPC_REG_GPR6, 0, addressSize);
+ case PPC_REG_GPR7: return RegisterInfo(PPC_REG_GPR7, 0, addressSize);
+ case PPC_REG_GPR8: return RegisterInfo(PPC_REG_GPR8, 0, addressSize);
+ case PPC_REG_GPR9: return RegisterInfo(PPC_REG_GPR9, 0, addressSize);
+ case PPC_REG_GPR10: return RegisterInfo(PPC_REG_GPR10, 0, addressSize);
+ case PPC_REG_GPR11: return RegisterInfo(PPC_REG_GPR11, 0, addressSize);
+ case PPC_REG_GPR12: return RegisterInfo(PPC_REG_GPR12, 0, addressSize);
+ case PPC_REG_GPR13: return RegisterInfo(PPC_REG_GPR13, 0, addressSize);
+ case PPC_REG_GPR14: return RegisterInfo(PPC_REG_GPR14, 0, addressSize);
+ case PPC_REG_GPR15: return RegisterInfo(PPC_REG_GPR15, 0, addressSize);
+ case PPC_REG_GPR16: return RegisterInfo(PPC_REG_GPR16, 0, addressSize);
+ case PPC_REG_GPR17: return RegisterInfo(PPC_REG_GPR17, 0, addressSize);
+ case PPC_REG_GPR18: return RegisterInfo(PPC_REG_GPR18, 0, addressSize);
+ case PPC_REG_GPR19: return RegisterInfo(PPC_REG_GPR19, 0, addressSize);
+ case PPC_REG_GPR20: return RegisterInfo(PPC_REG_GPR20, 0, addressSize);
+ case PPC_REG_GPR21: return RegisterInfo(PPC_REG_GPR21, 0, addressSize);
+ case PPC_REG_GPR22: return RegisterInfo(PPC_REG_GPR22, 0, addressSize);
+ case PPC_REG_GPR23: return RegisterInfo(PPC_REG_GPR23, 0, addressSize);
+ case PPC_REG_GPR24: return RegisterInfo(PPC_REG_GPR24, 0, addressSize);
+ case PPC_REG_GPR25: return RegisterInfo(PPC_REG_GPR25, 0, addressSize);
+ case PPC_REG_GPR26: return RegisterInfo(PPC_REG_GPR26, 0, addressSize);
+ case PPC_REG_GPR27: return RegisterInfo(PPC_REG_GPR27, 0, addressSize);
+ case PPC_REG_GPR28: return RegisterInfo(PPC_REG_GPR28, 0, addressSize);
+ case PPC_REG_GPR29: return RegisterInfo(PPC_REG_GPR29, 0, addressSize);
+ case PPC_REG_GPR30: return RegisterInfo(PPC_REG_GPR30, 0, addressSize);
+ case PPC_REG_GPR31: return RegisterInfo(PPC_REG_GPR31, 0, addressSize);
case PPC_REG_CARRY: return RegisterInfo(PPC_REG_CARRY, 0, 4);
- case PPC_REG_CR0: return RegisterInfo(PPC_REG_CR0, 0, 4);
- case PPC_REG_CR1: return RegisterInfo(PPC_REG_CR1, 0, 4);
- case PPC_REG_CR2: return RegisterInfo(PPC_REG_CR2, 0, 4);
- case PPC_REG_CR3: return RegisterInfo(PPC_REG_CR3, 0, 4);
- case PPC_REG_CR4: return RegisterInfo(PPC_REG_CR4, 0, 4);
- case PPC_REG_CR5: return RegisterInfo(PPC_REG_CR5, 0, 4);
- case PPC_REG_CR6: return RegisterInfo(PPC_REG_CR6, 0, 4);
- case PPC_REG_CR7: return RegisterInfo(PPC_REG_CR7, 0, 4);
- case PPC_REG_CTR: return RegisterInfo(PPC_REG_CTR, 0, addressSize);
- case PPC_REG_F0: return RegisterInfo(PPC_REG_F0, 0, 8);
- case PPC_REG_F1: return RegisterInfo(PPC_REG_F1, 0, 8);
- case PPC_REG_F2: return RegisterInfo(PPC_REG_F2, 0, 8);
- case PPC_REG_F3: return RegisterInfo(PPC_REG_F3, 0, 8);
- case PPC_REG_F4: return RegisterInfo(PPC_REG_F4, 0, 8);
- case PPC_REG_F5: return RegisterInfo(PPC_REG_F5, 0, 8);
- case PPC_REG_F6: return RegisterInfo(PPC_REG_F6, 0, 8);
- case PPC_REG_F7: return RegisterInfo(PPC_REG_F7, 0, 8);
- case PPC_REG_F8: return RegisterInfo(PPC_REG_F8, 0, 8);
- case PPC_REG_F9: return RegisterInfo(PPC_REG_F9, 0, 8);
- case PPC_REG_F10: return RegisterInfo(PPC_REG_F10, 0, 8);
- case PPC_REG_F11: return RegisterInfo(PPC_REG_F11, 0, 8);
- case PPC_REG_F12: return RegisterInfo(PPC_REG_F12, 0, 8);
- case PPC_REG_F13: return RegisterInfo(PPC_REG_F13, 0, 8);
- case PPC_REG_F14: return RegisterInfo(PPC_REG_F14, 0, 8);
- case PPC_REG_F15: return RegisterInfo(PPC_REG_F15, 0, 8);
- case PPC_REG_F16: return RegisterInfo(PPC_REG_F16, 0, 8);
- case PPC_REG_F17: return RegisterInfo(PPC_REG_F17, 0, 8);
- case PPC_REG_F18: return RegisterInfo(PPC_REG_F18, 0, 8);
- case PPC_REG_F19: return RegisterInfo(PPC_REG_F19, 0, 8);
- case PPC_REG_F20: return RegisterInfo(PPC_REG_F20, 0, 8);
- case PPC_REG_F21: return RegisterInfo(PPC_REG_F21, 0, 8);
- case PPC_REG_F22: return RegisterInfo(PPC_REG_F22, 0, 8);
- case PPC_REG_F23: return RegisterInfo(PPC_REG_F23, 0, 8);
- case PPC_REG_F24: return RegisterInfo(PPC_REG_F24, 0, 8);
- case PPC_REG_F25: return RegisterInfo(PPC_REG_F25, 0, 8);
- case PPC_REG_F26: return RegisterInfo(PPC_REG_F26, 0, 8);
- case PPC_REG_F27: return RegisterInfo(PPC_REG_F27, 0, 8);
- case PPC_REG_F28: return RegisterInfo(PPC_REG_F28, 0, 8);
- case PPC_REG_F29: return RegisterInfo(PPC_REG_F29, 0, 8);
- case PPC_REG_F30: return RegisterInfo(PPC_REG_F30, 0, 8);
- case PPC_REG_F31: return RegisterInfo(PPC_REG_F31, 0, 8);
+ case PPC_REG_XER: return RegisterInfo(PPC_REG_XER, 0, 4);
case PPC_REG_LR: return RegisterInfo(PPC_REG_LR, 0, addressSize);
- case PPC_REG_R0: return RegisterInfo(PPC_REG_R0, 0, addressSize);
- case PPC_REG_R1: return RegisterInfo(PPC_REG_R1, 0, addressSize);
- case PPC_REG_R2: return RegisterInfo(PPC_REG_R2, 0, addressSize);
- case PPC_REG_R3: return RegisterInfo(PPC_REG_R3, 0, addressSize);
- case PPC_REG_R4: return RegisterInfo(PPC_REG_R4, 0, addressSize);
- case PPC_REG_R5: return RegisterInfo(PPC_REG_R5, 0, addressSize);
- case PPC_REG_R6: return RegisterInfo(PPC_REG_R6, 0, addressSize);
- case PPC_REG_R7: return RegisterInfo(PPC_REG_R7, 0, addressSize);
- case PPC_REG_R8: return RegisterInfo(PPC_REG_R8, 0, addressSize);
- case PPC_REG_R9: return RegisterInfo(PPC_REG_R9, 0, addressSize);
- case PPC_REG_R10: return RegisterInfo(PPC_REG_R10, 0, addressSize);
- case PPC_REG_R11: return RegisterInfo(PPC_REG_R11, 0, addressSize);
- case PPC_REG_R12: return RegisterInfo(PPC_REG_R12, 0, addressSize);
- case PPC_REG_R13: return RegisterInfo(PPC_REG_R13, 0, addressSize);
- case PPC_REG_R14: return RegisterInfo(PPC_REG_R14, 0, addressSize);
- case PPC_REG_R15: return RegisterInfo(PPC_REG_R15, 0, addressSize);
- case PPC_REG_R16: return RegisterInfo(PPC_REG_R16, 0, addressSize);
- case PPC_REG_R17: return RegisterInfo(PPC_REG_R17, 0, addressSize);
- case PPC_REG_R18: return RegisterInfo(PPC_REG_R18, 0, addressSize);
- case PPC_REG_R19: return RegisterInfo(PPC_REG_R19, 0, addressSize);
- case PPC_REG_R20: return RegisterInfo(PPC_REG_R20, 0, addressSize);
- case PPC_REG_R21: return RegisterInfo(PPC_REG_R21, 0, addressSize);
- case PPC_REG_R22: return RegisterInfo(PPC_REG_R22, 0, addressSize);
- case PPC_REG_R23: return RegisterInfo(PPC_REG_R23, 0, addressSize);
- case PPC_REG_R24: return RegisterInfo(PPC_REG_R24, 0, addressSize);
- case PPC_REG_R25: return RegisterInfo(PPC_REG_R25, 0, addressSize);
- case PPC_REG_R26: return RegisterInfo(PPC_REG_R26, 0, addressSize);
- case PPC_REG_R27: return RegisterInfo(PPC_REG_R27, 0, addressSize);
- case PPC_REG_R28: return RegisterInfo(PPC_REG_R28, 0, addressSize);
- case PPC_REG_R29: return RegisterInfo(PPC_REG_R29, 0, addressSize);
- case PPC_REG_R30: return RegisterInfo(PPC_REG_R30, 0, addressSize);
- case PPC_REG_R31: return RegisterInfo(PPC_REG_R31, 0, addressSize);
- case PPC_REG_V0: return RegisterInfo(PPC_REG_V0, 0, 4);
- case PPC_REG_V1: return RegisterInfo(PPC_REG_V1, 0, 4);
- case PPC_REG_V2: return RegisterInfo(PPC_REG_V2, 0, 4);
- case PPC_REG_V3: return RegisterInfo(PPC_REG_V3, 0, 4);
- case PPC_REG_V4: return RegisterInfo(PPC_REG_V4, 0, 4);
- case PPC_REG_V5: return RegisterInfo(PPC_REG_V5, 0, 4);
- case PPC_REG_V6: return RegisterInfo(PPC_REG_V6, 0, 4);
- case PPC_REG_V7: return RegisterInfo(PPC_REG_V7, 0, 4);
- case PPC_REG_V8: return RegisterInfo(PPC_REG_V8, 0, 4);
- case PPC_REG_V9: return RegisterInfo(PPC_REG_V9, 0, 4);
- case PPC_REG_V10: return RegisterInfo(PPC_REG_V10, 0, 4);
- case PPC_REG_V11: return RegisterInfo(PPC_REG_V11, 0, 4);
- case PPC_REG_V12: return RegisterInfo(PPC_REG_V12, 0, 4);
- case PPC_REG_V13: return RegisterInfo(PPC_REG_V13, 0, 4);
- case PPC_REG_V14: return RegisterInfo(PPC_REG_V14, 0, 4);
- case PPC_REG_V15: return RegisterInfo(PPC_REG_V15, 0, 4);
- case PPC_REG_V16: return RegisterInfo(PPC_REG_V16, 0, 4);
- case PPC_REG_V17: return RegisterInfo(PPC_REG_V17, 0, 4);
- case PPC_REG_V18: return RegisterInfo(PPC_REG_V18, 0, 4);
- case PPC_REG_V19: return RegisterInfo(PPC_REG_V19, 0, 4);
- case PPC_REG_V20: return RegisterInfo(PPC_REG_V20, 0, 4);
- case PPC_REG_V21: return RegisterInfo(PPC_REG_V21, 0, 4);
- case PPC_REG_V22: return RegisterInfo(PPC_REG_V22, 0, 4);
- case PPC_REG_V23: return RegisterInfo(PPC_REG_V23, 0, 4);
- case PPC_REG_V24: return RegisterInfo(PPC_REG_V24, 0, 4);
- case PPC_REG_V25: return RegisterInfo(PPC_REG_V25, 0, 4);
- case PPC_REG_V26: return RegisterInfo(PPC_REG_V26, 0, 4);
- case PPC_REG_V27: return RegisterInfo(PPC_REG_V27, 0, 4);
- case PPC_REG_V28: return RegisterInfo(PPC_REG_V28, 0, 4);
- case PPC_REG_V29: return RegisterInfo(PPC_REG_V29, 0, 4);
- case PPC_REG_V30: return RegisterInfo(PPC_REG_V30, 0, 4);
- case PPC_REG_V31: return RegisterInfo(PPC_REG_V31, 0, 4);
- case PPC_REG_VRSAVE: return RegisterInfo(PPC_REG_VRSAVE, 0, 4);
- case PPC_REG_VS0: return RegisterInfo(PPC_REG_VS0, 0, 4);
- case PPC_REG_VS1: return RegisterInfo(PPC_REG_VS1, 0, 4);
- case PPC_REG_VS2: return RegisterInfo(PPC_REG_VS2, 0, 4);
- case PPC_REG_VS3: return RegisterInfo(PPC_REG_VS3, 0, 4);
- case PPC_REG_VS4: return RegisterInfo(PPC_REG_VS4, 0, 4);
- case PPC_REG_VS5: return RegisterInfo(PPC_REG_VS5, 0, 4);
- case PPC_REG_VS6: return RegisterInfo(PPC_REG_VS6, 0, 4);
- case PPC_REG_VS7: return RegisterInfo(PPC_REG_VS7, 0, 4);
- case PPC_REG_VS8: return RegisterInfo(PPC_REG_VS8, 0, 4);
- case PPC_REG_VS9: return RegisterInfo(PPC_REG_VS9, 0, 4);
- case PPC_REG_VS10: return RegisterInfo(PPC_REG_VS10, 0, 4);
- case PPC_REG_VS11: return RegisterInfo(PPC_REG_VS11, 0, 4);
- case PPC_REG_VS12: return RegisterInfo(PPC_REG_VS12, 0, 4);
- case PPC_REG_VS13: return RegisterInfo(PPC_REG_VS13, 0, 4);
- case PPC_REG_VS14: return RegisterInfo(PPC_REG_VS14, 0, 4);
- case PPC_REG_VS15: return RegisterInfo(PPC_REG_VS15, 0, 4);
- case PPC_REG_VS16: return RegisterInfo(PPC_REG_VS16, 0, 4);
- case PPC_REG_VS17: return RegisterInfo(PPC_REG_VS17, 0, 4);
- case PPC_REG_VS18: return RegisterInfo(PPC_REG_VS18, 0, 4);
- case PPC_REG_VS19: return RegisterInfo(PPC_REG_VS19, 0, 4);
- case PPC_REG_VS20: return RegisterInfo(PPC_REG_VS20, 0, 4);
- case PPC_REG_VS21: return RegisterInfo(PPC_REG_VS21, 0, 4);
- case PPC_REG_VS22: return RegisterInfo(PPC_REG_VS22, 0, 4);
- case PPC_REG_VS23: return RegisterInfo(PPC_REG_VS23, 0, 4);
- case PPC_REG_VS24: return RegisterInfo(PPC_REG_VS24, 0, 4);
- case PPC_REG_VS25: return RegisterInfo(PPC_REG_VS25, 0, 4);
- case PPC_REG_VS26: return RegisterInfo(PPC_REG_VS26, 0, 4);
- case PPC_REG_VS27: return RegisterInfo(PPC_REG_VS27, 0, 4);
- case PPC_REG_VS28: return RegisterInfo(PPC_REG_VS28, 0, 4);
- case PPC_REG_VS29: return RegisterInfo(PPC_REG_VS29, 0, 4);
- case PPC_REG_VS30: return RegisterInfo(PPC_REG_VS30, 0, 4);
- case PPC_REG_VS31: return RegisterInfo(PPC_REG_VS31, 0, 4);
- case PPC_REG_VS32: return RegisterInfo(PPC_REG_VS32, 0, 4);
- case PPC_REG_VS33: return RegisterInfo(PPC_REG_VS33, 0, 4);
- case PPC_REG_VS34: return RegisterInfo(PPC_REG_VS34, 0, 4);
- case PPC_REG_VS35: return RegisterInfo(PPC_REG_VS35, 0, 4);
- case PPC_REG_VS36: return RegisterInfo(PPC_REG_VS36, 0, 4);
- case PPC_REG_VS37: return RegisterInfo(PPC_REG_VS37, 0, 4);
- case PPC_REG_VS38: return RegisterInfo(PPC_REG_VS38, 0, 4);
- case PPC_REG_VS39: return RegisterInfo(PPC_REG_VS39, 0, 4);
- case PPC_REG_VS40: return RegisterInfo(PPC_REG_VS40, 0, 4);
- case PPC_REG_VS41: return RegisterInfo(PPC_REG_VS41, 0, 4);
- case PPC_REG_VS42: return RegisterInfo(PPC_REG_VS42, 0, 4);
- case PPC_REG_VS43: return RegisterInfo(PPC_REG_VS43, 0, 4);
- case PPC_REG_VS44: return RegisterInfo(PPC_REG_VS44, 0, 4);
- case PPC_REG_VS45: return RegisterInfo(PPC_REG_VS45, 0, 4);
- case PPC_REG_VS46: return RegisterInfo(PPC_REG_VS46, 0, 4);
- case PPC_REG_VS47: return RegisterInfo(PPC_REG_VS47, 0, 4);
- case PPC_REG_VS48: return RegisterInfo(PPC_REG_VS48, 0, 4);
- case PPC_REG_VS49: return RegisterInfo(PPC_REG_VS49, 0, 4);
- case PPC_REG_VS50: return RegisterInfo(PPC_REG_VS50, 0, 4);
- case PPC_REG_VS51: return RegisterInfo(PPC_REG_VS51, 0, 4);
- case PPC_REG_VS52: return RegisterInfo(PPC_REG_VS52, 0, 4);
- case PPC_REG_VS53: return RegisterInfo(PPC_REG_VS53, 0, 4);
- case PPC_REG_VS54: return RegisterInfo(PPC_REG_VS54, 0, 4);
- case PPC_REG_VS55: return RegisterInfo(PPC_REG_VS55, 0, 4);
- case PPC_REG_VS56: return RegisterInfo(PPC_REG_VS56, 0, 4);
- case PPC_REG_VS57: return RegisterInfo(PPC_REG_VS57, 0, 4);
- case PPC_REG_VS58: return RegisterInfo(PPC_REG_VS58, 0, 4);
- case PPC_REG_VS59: return RegisterInfo(PPC_REG_VS59, 0, 4);
- case PPC_REG_VS60: return RegisterInfo(PPC_REG_VS60, 0, 4);
- case PPC_REG_VS61: return RegisterInfo(PPC_REG_VS61, 0, 4);
- case PPC_REG_VS62: return RegisterInfo(PPC_REG_VS62, 0, 4);
- case PPC_REG_VS63: return RegisterInfo(PPC_REG_VS63, 0, 4);
- case PPC_REG_BN_GQR0: return RegisterInfo(PPC_REG_BN_GQR0, 0, 4);
- case PPC_REG_BN_GQR1: return RegisterInfo(PPC_REG_BN_GQR1, 0, 4);
- case PPC_REG_BN_GQR2: return RegisterInfo(PPC_REG_BN_GQR2, 0, 4);
- case PPC_REG_BN_GQR3: return RegisterInfo(PPC_REG_BN_GQR3, 0, 4);
- case PPC_REG_BN_GQR4: return RegisterInfo(PPC_REG_BN_GQR4, 0, 4);
- case PPC_REG_BN_GQR5: return RegisterInfo(PPC_REG_BN_GQR5, 0, 4);
- case PPC_REG_BN_GQR6: return RegisterInfo(PPC_REG_BN_GQR6, 0, 4);
- case PPC_REG_BN_GQR7: return RegisterInfo(PPC_REG_BN_GQR7, 0, 4);
+ case PPC_REG_CTR: return RegisterInfo(PPC_REG_CTR, 0, addressSize);
+ case PPC_REG_RM: return RegisterInfo(PPC_REG_RM, 0, addressSize);
+ case PPC_REG_VRSAVE: return RegisterInfo(PPC_REG_VRSAVE, 0, addressSize);
+ case PPC_REG_ZERO: return RegisterInfo(PPC_REG_ZERO, 0, addressSize);
+
+ case PPC_REG_FR0: return RegisterInfo(PPC_REG_FR0, 0, 8);
+ case PPC_REG_FR1: return RegisterInfo(PPC_REG_FR1, 0, 8);
+ case PPC_REG_FR2: return RegisterInfo(PPC_REG_FR2, 0, 8);
+ case PPC_REG_FR3: return RegisterInfo(PPC_REG_FR3, 0, 8);
+ case PPC_REG_FR4: return RegisterInfo(PPC_REG_FR4, 0, 8);
+ case PPC_REG_FR5: return RegisterInfo(PPC_REG_FR5, 0, 8);
+ case PPC_REG_FR6: return RegisterInfo(PPC_REG_FR6, 0, 8);
+ case PPC_REG_FR7: return RegisterInfo(PPC_REG_FR7, 0, 8);
+ case PPC_REG_FR8: return RegisterInfo(PPC_REG_FR8, 0, 8);
+ case PPC_REG_FR9: return RegisterInfo(PPC_REG_FR9, 0, 8);
+ case PPC_REG_FR10: return RegisterInfo(PPC_REG_FR10, 0, 8);
+ case PPC_REG_FR11: return RegisterInfo(PPC_REG_FR11, 0, 8);
+ case PPC_REG_FR12: return RegisterInfo(PPC_REG_FR12, 0, 8);
+ case PPC_REG_FR13: return RegisterInfo(PPC_REG_FR13, 0, 8);
+ case PPC_REG_FR14: return RegisterInfo(PPC_REG_FR14, 0, 8);
+ case PPC_REG_FR15: return RegisterInfo(PPC_REG_FR15, 0, 8);
+ case PPC_REG_FR16: return RegisterInfo(PPC_REG_FR16, 0, 8);
+ case PPC_REG_FR17: return RegisterInfo(PPC_REG_FR17, 0, 8);
+ case PPC_REG_FR18: return RegisterInfo(PPC_REG_FR18, 0, 8);
+ case PPC_REG_FR19: return RegisterInfo(PPC_REG_FR19, 0, 8);
+ case PPC_REG_FR20: return RegisterInfo(PPC_REG_FR20, 0, 8);
+ case PPC_REG_FR21: return RegisterInfo(PPC_REG_FR21, 0, 8);
+ case PPC_REG_FR22: return RegisterInfo(PPC_REG_FR22, 0, 8);
+ case PPC_REG_FR23: return RegisterInfo(PPC_REG_FR23, 0, 8);
+ case PPC_REG_FR24: return RegisterInfo(PPC_REG_FR24, 0, 8);
+ case PPC_REG_FR25: return RegisterInfo(PPC_REG_FR25, 0, 8);
+ case PPC_REG_FR26: return RegisterInfo(PPC_REG_FR26, 0, 8);
+ case PPC_REG_FR27: return RegisterInfo(PPC_REG_FR27, 0, 8);
+ case PPC_REG_FR28: return RegisterInfo(PPC_REG_FR28, 0, 8);
+ case PPC_REG_FR29: return RegisterInfo(PPC_REG_FR29, 0, 8);
+ case PPC_REG_FR30: return RegisterInfo(PPC_REG_FR30, 0, 8);
+ case PPC_REG_FR31: return RegisterInfo(PPC_REG_FR31, 0, 8);
+
+ case PPC_REG_CRF0: return RegisterInfo(PPC_REG_CRF0, 0, 4);
+ case PPC_REG_CRF1: return RegisterInfo(PPC_REG_CRF1, 0, 4);
+ case PPC_REG_CRF2: return RegisterInfo(PPC_REG_CRF2, 0, 4);
+ case PPC_REG_CRF3: return RegisterInfo(PPC_REG_CRF3, 0, 4);
+ case PPC_REG_CRF4: return RegisterInfo(PPC_REG_CRF4, 0, 4);
+ case PPC_REG_CRF5: return RegisterInfo(PPC_REG_CRF5, 0, 4);
+ case PPC_REG_CRF6: return RegisterInfo(PPC_REG_CRF6, 0, 4);
+ case PPC_REG_CRF7: return RegisterInfo(PPC_REG_CRF7, 0, 4);
+
+ // TODO: make these subregisters of VSX registers
+ case PPC_REG_AV_VR0: return RegisterInfo(PPC_REG_AV_VR0, 0, 4);
+ case PPC_REG_AV_VR1: return RegisterInfo(PPC_REG_AV_VR1, 0, 4);
+ case PPC_REG_AV_VR2: return RegisterInfo(PPC_REG_AV_VR2, 0, 4);
+ case PPC_REG_AV_VR3: return RegisterInfo(PPC_REG_AV_VR3, 0, 4);
+ case PPC_REG_AV_VR4: return RegisterInfo(PPC_REG_AV_VR4, 0, 4);
+ case PPC_REG_AV_VR5: return RegisterInfo(PPC_REG_AV_VR5, 0, 4);
+ case PPC_REG_AV_VR6: return RegisterInfo(PPC_REG_AV_VR6, 0, 4);
+ case PPC_REG_AV_VR7: return RegisterInfo(PPC_REG_AV_VR7, 0, 4);
+ case PPC_REG_AV_VR8: return RegisterInfo(PPC_REG_AV_VR8, 0, 4);
+ case PPC_REG_AV_VR9: return RegisterInfo(PPC_REG_AV_VR9, 0, 4);
+ case PPC_REG_AV_VR10: return RegisterInfo(PPC_REG_AV_VR10, 0, 4);
+ case PPC_REG_AV_VR11: return RegisterInfo(PPC_REG_AV_VR11, 0, 4);
+ case PPC_REG_AV_VR12: return RegisterInfo(PPC_REG_AV_VR12, 0, 4);
+ case PPC_REG_AV_VR13: return RegisterInfo(PPC_REG_AV_VR13, 0, 4);
+ case PPC_REG_AV_VR14: return RegisterInfo(PPC_REG_AV_VR14, 0, 4);
+ case PPC_REG_AV_VR15: return RegisterInfo(PPC_REG_AV_VR15, 0, 4);
+ case PPC_REG_AV_VR16: return RegisterInfo(PPC_REG_AV_VR16, 0, 4);
+ case PPC_REG_AV_VR17: return RegisterInfo(PPC_REG_AV_VR17, 0, 4);
+ case PPC_REG_AV_VR18: return RegisterInfo(PPC_REG_AV_VR18, 0, 4);
+ case PPC_REG_AV_VR19: return RegisterInfo(PPC_REG_AV_VR19, 0, 4);
+ case PPC_REG_AV_VR20: return RegisterInfo(PPC_REG_AV_VR20, 0, 4);
+ case PPC_REG_AV_VR21: return RegisterInfo(PPC_REG_AV_VR21, 0, 4);
+ case PPC_REG_AV_VR22: return RegisterInfo(PPC_REG_AV_VR22, 0, 4);
+ case PPC_REG_AV_VR23: return RegisterInfo(PPC_REG_AV_VR23, 0, 4);
+ case PPC_REG_AV_VR24: return RegisterInfo(PPC_REG_AV_VR24, 0, 4);
+ case PPC_REG_AV_VR25: return RegisterInfo(PPC_REG_AV_VR25, 0, 4);
+ case PPC_REG_AV_VR26: return RegisterInfo(PPC_REG_AV_VR26, 0, 4);
+ case PPC_REG_AV_VR27: return RegisterInfo(PPC_REG_AV_VR27, 0, 4);
+ case PPC_REG_AV_VR28: return RegisterInfo(PPC_REG_AV_VR28, 0, 4);
+ case PPC_REG_AV_VR29: return RegisterInfo(PPC_REG_AV_VR29, 0, 4);
+ case PPC_REG_AV_VR30: return RegisterInfo(PPC_REG_AV_VR30, 0, 4);
+ case PPC_REG_AV_VR31: return RegisterInfo(PPC_REG_AV_VR31, 0, 4);
+
+ case PPC_REG_VSX_VR0: return RegisterInfo(PPC_REG_VSX_VR0, 0, 8);
+ case PPC_REG_VSX_VR1: return RegisterInfo(PPC_REG_VSX_VR1, 0, 8);
+ case PPC_REG_VSX_VR2: return RegisterInfo(PPC_REG_VSX_VR2, 0, 8);
+ case PPC_REG_VSX_VR3: return RegisterInfo(PPC_REG_VSX_VR3, 0, 8);
+ case PPC_REG_VSX_VR4: return RegisterInfo(PPC_REG_VSX_VR4, 0, 8);
+ case PPC_REG_VSX_VR5: return RegisterInfo(PPC_REG_VSX_VR5, 0, 8);
+ case PPC_REG_VSX_VR6: return RegisterInfo(PPC_REG_VSX_VR6, 0, 8);
+ case PPC_REG_VSX_VR7: return RegisterInfo(PPC_REG_VSX_VR7, 0, 8);
+ case PPC_REG_VSX_VR8: return RegisterInfo(PPC_REG_VSX_VR8, 0, 8);
+ case PPC_REG_VSX_VR9: return RegisterInfo(PPC_REG_VSX_VR9, 0, 8);
+ case PPC_REG_VSX_VR10: return RegisterInfo(PPC_REG_VSX_VR10, 0, 8);
+ case PPC_REG_VSX_VR11: return RegisterInfo(PPC_REG_VSX_VR11, 0, 8);
+ case PPC_REG_VSX_VR12: return RegisterInfo(PPC_REG_VSX_VR12, 0, 8);
+ case PPC_REG_VSX_VR13: return RegisterInfo(PPC_REG_VSX_VR13, 0, 8);
+ case PPC_REG_VSX_VR14: return RegisterInfo(PPC_REG_VSX_VR14, 0, 8);
+ case PPC_REG_VSX_VR15: return RegisterInfo(PPC_REG_VSX_VR15, 0, 8);
+ case PPC_REG_VSX_VR16: return RegisterInfo(PPC_REG_VSX_VR16, 0, 8);
+ case PPC_REG_VSX_VR17: return RegisterInfo(PPC_REG_VSX_VR17, 0, 8);
+ case PPC_REG_VSX_VR18: return RegisterInfo(PPC_REG_VSX_VR18, 0, 8);
+ case PPC_REG_VSX_VR19: return RegisterInfo(PPC_REG_VSX_VR19, 0, 8);
+ case PPC_REG_VSX_VR20: return RegisterInfo(PPC_REG_VSX_VR20, 0, 8);
+ case PPC_REG_VSX_VR21: return RegisterInfo(PPC_REG_VSX_VR21, 0, 8);
+ case PPC_REG_VSX_VR22: return RegisterInfo(PPC_REG_VSX_VR22, 0, 8);
+ case PPC_REG_VSX_VR23: return RegisterInfo(PPC_REG_VSX_VR23, 0, 8);
+ case PPC_REG_VSX_VR24: return RegisterInfo(PPC_REG_VSX_VR24, 0, 8);
+ case PPC_REG_VSX_VR25: return RegisterInfo(PPC_REG_VSX_VR25, 0, 8);
+ case PPC_REG_VSX_VR26: return RegisterInfo(PPC_REG_VSX_VR26, 0, 8);
+ case PPC_REG_VSX_VR27: return RegisterInfo(PPC_REG_VSX_VR27, 0, 8);
+ case PPC_REG_VSX_VR28: return RegisterInfo(PPC_REG_VSX_VR28, 0, 8);
+ case PPC_REG_VSX_VR29: return RegisterInfo(PPC_REG_VSX_VR29, 0, 8);
+ case PPC_REG_VSX_VR30: return RegisterInfo(PPC_REG_VSX_VR30, 0, 8);
+ case PPC_REG_VSX_VR31: return RegisterInfo(PPC_REG_VSX_VR31, 0, 8);
+ case PPC_REG_VSX_VR32: return RegisterInfo(PPC_REG_VSX_VR32, 0, 8);
+ case PPC_REG_VSX_VR33: return RegisterInfo(PPC_REG_VSX_VR33, 0, 8);
+ case PPC_REG_VSX_VR34: return RegisterInfo(PPC_REG_VSX_VR34, 0, 8);
+ case PPC_REG_VSX_VR35: return RegisterInfo(PPC_REG_VSX_VR35, 0, 8);
+ case PPC_REG_VSX_VR36: return RegisterInfo(PPC_REG_VSX_VR36, 0, 8);
+ case PPC_REG_VSX_VR37: return RegisterInfo(PPC_REG_VSX_VR37, 0, 8);
+ case PPC_REG_VSX_VR38: return RegisterInfo(PPC_REG_VSX_VR38, 0, 8);
+ case PPC_REG_VSX_VR39: return RegisterInfo(PPC_REG_VSX_VR39, 0, 8);
+ case PPC_REG_VSX_VR40: return RegisterInfo(PPC_REG_VSX_VR40, 0, 8);
+ case PPC_REG_VSX_VR41: return RegisterInfo(PPC_REG_VSX_VR41, 0, 8);
+ case PPC_REG_VSX_VR42: return RegisterInfo(PPC_REG_VSX_VR42, 0, 8);
+ case PPC_REG_VSX_VR43: return RegisterInfo(PPC_REG_VSX_VR43, 0, 8);
+ case PPC_REG_VSX_VR44: return RegisterInfo(PPC_REG_VSX_VR44, 0, 8);
+ case PPC_REG_VSX_VR45: return RegisterInfo(PPC_REG_VSX_VR45, 0, 8);
+ case PPC_REG_VSX_VR46: return RegisterInfo(PPC_REG_VSX_VR46, 0, 8);
+ case PPC_REG_VSX_VR47: return RegisterInfo(PPC_REG_VSX_VR47, 0, 8);
+ case PPC_REG_VSX_VR48: return RegisterInfo(PPC_REG_VSX_VR48, 0, 8);
+ case PPC_REG_VSX_VR49: return RegisterInfo(PPC_REG_VSX_VR49, 0, 8);
+ case PPC_REG_VSX_VR50: return RegisterInfo(PPC_REG_VSX_VR50, 0, 8);
+ case PPC_REG_VSX_VR51: return RegisterInfo(PPC_REG_VSX_VR51, 0, 8);
+ case PPC_REG_VSX_VR52: return RegisterInfo(PPC_REG_VSX_VR52, 0, 8);
+ case PPC_REG_VSX_VR53: return RegisterInfo(PPC_REG_VSX_VR53, 0, 8);
+ case PPC_REG_VSX_VR54: return RegisterInfo(PPC_REG_VSX_VR54, 0, 8);
+ case PPC_REG_VSX_VR55: return RegisterInfo(PPC_REG_VSX_VR55, 0, 8);
+ case PPC_REG_VSX_VR56: return RegisterInfo(PPC_REG_VSX_VR56, 0, 8);
+ case PPC_REG_VSX_VR57: return RegisterInfo(PPC_REG_VSX_VR57, 0, 8);
+ case PPC_REG_VSX_VR58: return RegisterInfo(PPC_REG_VSX_VR58, 0, 8);
+ case PPC_REG_VSX_VR59: return RegisterInfo(PPC_REG_VSX_VR59, 0, 8);
+ case PPC_REG_VSX_VR60: return RegisterInfo(PPC_REG_VSX_VR60, 0, 8);
+ case PPC_REG_VSX_VR61: return RegisterInfo(PPC_REG_VSX_VR61, 0, 8);
+ case PPC_REG_VSX_VR62: return RegisterInfo(PPC_REG_VSX_VR62, 0, 8);
+ case PPC_REG_VSX_VR63: return RegisterInfo(PPC_REG_VSX_VR63, 0, 8);
+
+ case PPC_REG_GQR0: return RegisterInfo(PPC_REG_GQR0, 0, 4);
+ case PPC_REG_GQR1: return RegisterInfo(PPC_REG_GQR1, 0, 4);
+ case PPC_REG_GQR2: return RegisterInfo(PPC_REG_GQR2, 0, 4);
+ case PPC_REG_GQR3: return RegisterInfo(PPC_REG_GQR3, 0, 4);
+ case PPC_REG_GQR4: return RegisterInfo(PPC_REG_GQR4, 0, 4);
+ case PPC_REG_GQR5: return RegisterInfo(PPC_REG_GQR5, 0, 4);
+ case PPC_REG_GQR6: return RegisterInfo(PPC_REG_GQR6, 0, 4);
+ case PPC_REG_GQR7: return RegisterInfo(PPC_REG_GQR7, 0, 4);
+
default:
//LogError("%s(%d == \"%s\") invalid argument", __func__,
- // regId, powerpc_reg_to_str(regId));
+ // regId, PowerPCRegisterName(regId));
return RegisterInfo(0,0,0);
}
}
@@ -1814,7 +1854,7 @@ class PowerpcArchitecture: public Architecture
virtual uint32_t GetStackPointerRegister() override
{
//MYLOG("%s()\n", __func__);
- return PPC_REG_R1;
+ return PPC_REG_GPR1;
}
virtual uint32_t GetLinkRegister() override
@@ -2257,8 +2297,8 @@ public:
virtual vector<uint32_t> GetIntegerArgumentRegisters() override
{
return vector<uint32_t>{
- PPC_REG_R3, PPC_REG_R4, PPC_REG_R5, PPC_REG_R6,
- PPC_REG_R7, PPC_REG_R8, PPC_REG_R9, PPC_REG_R10
+ PPC_REG_GPR3, PPC_REG_GPR4, PPC_REG_GPR5, PPC_REG_GPR6,
+ PPC_REG_GPR7, PPC_REG_GPR8, PPC_REG_GPR9, PPC_REG_GPR10
/* remaining arguments onto stack */
};
}
@@ -2267,10 +2307,10 @@ public:
virtual vector<uint32_t> GetFloatArgumentRegisters() override
{
return vector<uint32_t>{
- PPC_REG_F1, PPC_REG_F2, PPC_REG_F3, PPC_REG_F4,
- PPC_REG_F5, PPC_REG_F6, PPC_REG_F7, PPC_REG_F8,
- PPC_REG_F9, PPC_REG_F10, PPC_REG_F11, PPC_REG_F12,
- PPC_REG_F13
+ PPC_REG_FR1, PPC_REG_FR2, PPC_REG_FR3, PPC_REG_FR4,
+ PPC_REG_FR5, PPC_REG_FR6, PPC_REG_FR7, PPC_REG_FR8,
+ PPC_REG_FR9, PPC_REG_FR10, PPC_REG_FR11, PPC_REG_FR12,
+ PPC_REG_FR13
};
}
@@ -2278,14 +2318,14 @@ public:
virtual vector<uint32_t> GetCallerSavedRegisters() override
{
return vector<uint32_t>{
- PPC_REG_R0, PPC_REG_R2, PPC_REG_R3, PPC_REG_R4,
- PPC_REG_R5, PPC_REG_R6, PPC_REG_R7, PPC_REG_R8,
- PPC_REG_R9, PPC_REG_R10, PPC_REG_R12,
+ PPC_REG_GPR0, PPC_REG_GPR2, PPC_REG_GPR3, PPC_REG_GPR4,
+ PPC_REG_GPR5, PPC_REG_GPR6, PPC_REG_GPR7, PPC_REG_GPR8,
+ PPC_REG_GPR9, PPC_REG_GPR10, PPC_REG_GPR12,
- PPC_REG_F0, PPC_REG_F1, PPC_REG_F2, PPC_REG_F3,
- PPC_REG_F4, PPC_REG_F5, PPC_REG_F6, PPC_REG_F7,
- PPC_REG_F8, PPC_REG_F9, PPC_REG_F10, PPC_REG_F11,
- PPC_REG_F12, PPC_REG_F13,
+ PPC_REG_FR0, PPC_REG_FR1, PPC_REG_FR2, PPC_REG_FR3,
+ PPC_REG_FR4, PPC_REG_FR5, PPC_REG_FR6, PPC_REG_FR7,
+ PPC_REG_FR8, PPC_REG_FR9, PPC_REG_FR10, PPC_REG_FR11,
+ PPC_REG_FR12, PPC_REG_FR13,
PPC_REG_LR, PPC_REG_CTR,
};
@@ -2295,30 +2335,30 @@ public:
virtual vector<uint32_t> GetCalleeSavedRegisters() override
{
return vector<uint32_t>{
- PPC_REG_R14, PPC_REG_R15, PPC_REG_R16, PPC_REG_R17,
- PPC_REG_R18, PPC_REG_R19, PPC_REG_R20, PPC_REG_R21,
- PPC_REG_R22, PPC_REG_R23, PPC_REG_R24, PPC_REG_R25,
- PPC_REG_R26, PPC_REG_R27, PPC_REG_R28, PPC_REG_R29,
- PPC_REG_R30, PPC_REG_R31
+ PPC_REG_GPR14, PPC_REG_GPR15, PPC_REG_GPR16, PPC_REG_GPR17,
+ PPC_REG_GPR18, PPC_REG_GPR19, PPC_REG_GPR20, PPC_REG_GPR21,
+ PPC_REG_GPR22, PPC_REG_GPR23, PPC_REG_GPR24, PPC_REG_GPR25,
+ PPC_REG_GPR26, PPC_REG_GPR27, PPC_REG_GPR28, PPC_REG_GPR29,
+ PPC_REG_GPR30, PPC_REG_GPR31
};
}
virtual uint32_t GetGlobalPointerRegister() override
{
- return PPC_REG_R13;
+ return PPC_REG_GPR13;
}
virtual uint32_t GetIntegerReturnValueRegister() override
{
- return PPC_REG_R3;
+ return PPC_REG_GPR3;
}
virtual uint32_t GetFloatReturnValueRegister() override
{
- return PPC_REG_F1;
+ return PPC_REG_FR1;
}
};
@@ -2332,33 +2372,33 @@ public:
virtual vector<uint32_t> GetIntegerArgumentRegisters() override
{
return vector<uint32_t>{
- PPC_REG_R0,
- PPC_REG_R3, PPC_REG_R4, PPC_REG_R5, PPC_REG_R6,
- PPC_REG_R7, PPC_REG_R8, PPC_REG_R9, PPC_REG_R10
+ PPC_REG_GPR0,
+ PPC_REG_GPR3, PPC_REG_GPR4, PPC_REG_GPR5, PPC_REG_GPR6,
+ PPC_REG_GPR7, PPC_REG_GPR8, PPC_REG_GPR9, PPC_REG_GPR10
};
}
virtual vector<uint32_t> GetCallerSavedRegisters() override
{
return vector<uint32_t>{
- PPC_REG_R3
+ PPC_REG_GPR3
};
}
virtual vector<uint32_t> GetCalleeSavedRegisters() override
{
- return vector<uint32_t>{
- PPC_REG_R14, PPC_REG_R15, PPC_REG_R16, PPC_REG_R17,
- PPC_REG_R18, PPC_REG_R19, PPC_REG_R20, PPC_REG_R21,
- PPC_REG_R22, PPC_REG_R23, PPC_REG_R24, PPC_REG_R25,
- PPC_REG_R26, PPC_REG_R27, PPC_REG_R28, PPC_REG_R29,
- PPC_REG_R30, PPC_REG_R31
+ return vector<uint32_t> {
+ PPC_REG_GPR14, PPC_REG_GPR15, PPC_REG_GPR16, PPC_REG_GPR17,
+ PPC_REG_GPR18, PPC_REG_GPR19, PPC_REG_GPR20, PPC_REG_GPR21,
+ PPC_REG_GPR22, PPC_REG_GPR23, PPC_REG_GPR24, PPC_REG_GPR25,
+ PPC_REG_GPR26, PPC_REG_GPR27, PPC_REG_GPR28, PPC_REG_GPR29,
+ PPC_REG_GPR30, PPC_REG_GPR31
};
}
virtual uint32_t GetIntegerReturnValueRegister() override
{
- return PPC_REG_R3;
+ return PPC_REG_GPR3;
}
virtual bool IsEligibleForHeuristics() override
@@ -2367,11 +2407,6 @@ public:
}
};
-uint16_t bswap16(uint16_t x)
-{
- return (x >> 8) | (x << 8);
-}
-
class PpcElfRelocationHandler: public RelocationHandler
{
public:
@@ -2533,6 +2568,93 @@ public:
}
};
+#define SECTION_FLAG_EXECUTABLE 0x00000004
+#define SECTION_FLAG_VLE 0x10000000
+
+static Ref<Platform> ElfSpecialRecognize(BinaryView* view, Metadata* metadata)
+{
+ Ref<Metadata> eiClassMetadata = metadata->Get("EI_CLASS");
+ if (!eiClassMetadata || !eiClassMetadata->IsUnsignedInteger())
+ return nullptr;
+
+ uint64_t eiClass = eiClassMetadata->GetUnsignedInteger();
+
+ bool is32bit;
+ if (eiClass == 1)
+ is32bit = true;
+ else if (eiClass == 2)
+ is32bit = false;
+ else
+ return nullptr;
+
+ // TODO: Issue #6290, look for .ppc.EMB.apuinfo to figure out which
+ // APU to use (Altivec vs. SPE vs. etc.)
+
+ // TODO: This only handles the cases when all executable sections share
+ // the same VLE-ness; currently elf views don't support
+ // granularity at the section level for different architectures
+ Ref<Metadata> numSectionsMetadata = metadata->Get("numSections");
+ if (!numSectionsMetadata || !numSectionsMetadata->IsUnsignedInteger())
+ return nullptr;
+
+ uint64_t numSections = numSectionsMetadata->GetUnsignedInteger();
+ bool foundFirst = false;
+ bool allVle = false;
+ for (unsigned i = 0; i < numSections; ++i)
+ {
+ char metaname[0x20];
+ snprintf(metaname, sizeof metaname, "sectionFlags[%d]", i);
+
+ Ref<Metadata> sectionFlagsMetadata = metadata->Get(metaname);
+ if (!sectionFlagsMetadata || !sectionFlagsMetadata->IsUnsignedInteger())
+ {
+ LogError("Internal error: there are %" PRId64 " sections in ELF metadata, but we're missing sectionFlags[%d]", numSections, i);
+
+ return nullptr;
+ }
+
+ uint64_t sectionFlags = sectionFlagsMetadata->GetUnsignedInteger();
+ LogDebug("sectionFlags[%d] = %" PRIx64, i, sectionFlags);
+
+ if ((sectionFlags & SECTION_FLAG_EXECUTABLE) == 0)
+ {
+ LogDebug("Skipping non-executable section");
+ continue;
+ }
+
+ bool isVle = (sectionFlags & SECTION_FLAG_VLE) != 0;
+ if (!foundFirst)
+ {
+ LogDebug("first code sectionFlags[%d] VLE=%d", i, isVle);
+ allVle = isVle;
+ foundFirst = true;
+ }
+ else if (isVle != allVle)
+ {
+ LogWarn("Executable section %d doesn't have same VLE flag as previously encountered ones: previous sections %s but this one %s", i,
+ allVle ? "have VLE" : "have no VLE",
+ isVle ? "has VLE" : "has no VLE");
+ return nullptr;
+ }
+ else
+ {
+ LogDebug("sectionFlags[%d] VLE=%d (same as others)", i, isVle);
+ }
+ }
+
+ if (allVle)
+ {
+ MYLOG("OVERRIDING WITH VLE: %p\n", (void *)Platform::GetByName("linux-ppcvle"));
+ if (is32bit)
+ return Platform::GetByName("linux-ppcvle32");
+ else
+ return Platform::GetByName("linux-ppcvle64");
+ }
+
+ // No need to override, let the ELF view figure it out
+ return nullptr;
+}
+
extern "C"
{
BN_DECLARE_CORE_ABI_VERSION
@@ -2554,13 +2676,16 @@ extern "C"
Architecture* ppc = new PowerpcArchitecture("ppc", BigEndian);
Architecture::Register(ppc);
- Architecture* ppc_qpx = new PowerpcArchitecture("ppc_qpx", BigEndian, 4, CS_MODE_QPX);
+ Architecture* ppcvle = new PowerpcArchitecture("ppcvle", BigEndian, 4, DECODE_FLAGS_VLE);
+ Architecture::Register(ppcvle);
+
+ Architecture* ppc_qpx = new PowerpcArchitecture("ppc_qpx", BigEndian, 4, DECODE_FLAGS_QPX);
Architecture::Register(ppc_qpx);
- Architecture* ppc_spe = new PowerpcArchitecture("ppc_spe", BigEndian, 4, CS_MODE_SPE);
+ Architecture* ppc_spe = new PowerpcArchitecture("ppc_spe", BigEndian, 4, DECODE_FLAGS_SPE);
Architecture::Register(ppc_spe);
- Architecture* ppc_ps = new PowerpcArchitecture("ppc_ps", BigEndian, 4, CS_MODE_PS);
+ Architecture* ppc_ps = new PowerpcArchitecture("ppc_ps", BigEndian, 4, DECODE_FLAGS_PS);
Architecture::Register(ppc_ps);
Architecture* ppc64 = new PowerpcArchitecture("ppc64", BigEndian, 8);
@@ -2577,6 +2702,8 @@ extern "C"
conv = new PpcSvr4CallingConvention(ppc);
ppc->RegisterCallingConvention(conv);
ppc->SetDefaultCallingConvention(conv);
+ ppcvle->RegisterCallingConvention(conv);
+ ppcvle->SetDefaultCallingConvention(conv);
ppc_qpx->RegisterCallingConvention(conv);
ppc_qpx->SetDefaultCallingConvention(conv);
ppc_spe->RegisterCallingConvention(conv);
@@ -2585,8 +2712,10 @@ extern "C"
ppc_ps->SetDefaultCallingConvention(conv);
ppc64->RegisterCallingConvention(conv);
ppc64->SetDefaultCallingConvention(conv);
+
conv = new PpcLinuxSyscallCallingConvention(ppc);
ppc->RegisterCallingConvention(conv);
+ ppcvle->RegisterCallingConvention(conv);
ppc_qpx->RegisterCallingConvention(conv);
ppc_spe->RegisterCallingConvention(conv);
ppc_ps->RegisterCallingConvention(conv);
@@ -2609,6 +2738,7 @@ extern "C"
ppc_le->RegisterFunctionRecognizer(new PpcImportedFunctionRecognizer());
ppc->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler());
+ ppcvle->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler());
ppc_qpx->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler());
ppc_spe->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler());
ppc_ps->RegisterRelocationHandler("ELF", new PpcElfRelocationHandler());
@@ -2666,6 +2796,15 @@ extern "C"
ppc64_le /* the architecture */
);
+ Ref<BinaryViewType> elf = BinaryViewType::GetByName("ELF");
+ if (elf)
+ {
+ elf->RegisterPlatformRecognizer(EM_PPC, BigEndian, ElfSpecialRecognize);
+ elf->RegisterPlatformRecognizer(EM_PPC, LittleEndian, ElfSpecialRecognize);
+ elf->RegisterPlatformRecognizer(EM_PPC64, BigEndian, ElfSpecialRecognize);
+ elf->RegisterPlatformRecognizer(EM_PPC64, LittleEndian, ElfSpecialRecognize);
+ }
+
return true;
}
}
diff --git a/arch/powerpc/assembler.cpp b/arch/powerpc/assembler.cpp
index bafc0686..845b1ecb 100644
--- a/arch/powerpc/assembler.cpp
+++ b/arch/powerpc/assembler.cpp
@@ -20,9 +20,17 @@ using namespace std;
/* capstone stuff */
#include "capstone/capstone.h"
+#include "disassembler.h"
-//#define MYLOG printf
+#define DEBUG 0
+#if DEBUG
+#define MYLOG printf
+#else
#define MYLOG(...) while(0);
+#endif
+
+
+// #define ENABLE_CAPSTONE
#include "assembler.h"
@@ -1252,10 +1260,14 @@ map<string, info> lookup = {
{"rlwinm GPR , GPR , NUM , NUM , NUM",{0x54000000,0x03FFFFFE}}, // 010101xxxxxxxxxxxxxxxxxxxxxxxxx0 rlwinm r0, r0, 0, 0, 0
{"rlwinm . GPR , GPR , NUM , NUM , NUM",{0x54000001,0x03FFFFFE}}, // 010101xxxxxxxxxxxxxxxxxxxxxxxxx1 rlwinm. r0, r0, 0, 0, 0
{ "slwi GPR , GPR , NUM",{0x5400003E,0x03FFF83E}}, // 010101xxxxxxxxxxxxxxx00000xxxxx0 slwi r0, r0, 0
-{ "rotlwi . GPR , GPR , NUM",{0x5400003F,0x03FFF800}}, // 010101xxxxxxxxxxxxxxx00000111111 rotlwi. r0, r0, 0
+{ "clrrwi GPR , GPR , NUM",{0x54000000,0x03FF003E}}, // 010101xxxxxxxxxx0000000000xxxxx0 clrrwi r0, r0, 1
+{ "clrrwi . GPR , GPR , NUM",{0x54000001,0x03FF003F}}, // 010101xxxxxxxxxx0000000000xxxxx0 clrrwi. r0, r0, 1
{ "clrlwi GPR , GPR , NUM",{0x5400007E,0x03FF07C0}}, // 010101xxxxxxxxxx00000xxxxx111110 clrlwi r0, r0, 1
{ "clrlwi . GPR , GPR , NUM",{0x5400007F,0x03FF07C0}}, // 010101xxxxxxxxxx00000xxxxx111111 clrlwi. r0, r0, 1
{ "rotlwi GPR , GPR , NUM",{0x5400083E,0x03FFF800}}, // 010101xxxxxxxxxxxxxxx00000111110 rotlwi r0, r0, 1
+{ "rotlwi . GPR , GPR , NUM",{0x5400083F,0x03FFF800}}, // 010101xxxxxxxxxxxxxxx00000111111 rotlwi. r0, r0, 1
+{ "rotrwi GPR , GPR , NUM",{0x5400083E,0x03FFF800}}, // 010101xxxxxxxxxxxxxxx00000111110 rotrwi r0, r0, 1
+{ "rotrwi . GPR , GPR , NUM",{0x5400003F,0x03FFF800}}, // 010101xxxxxxxxxxxxxxx00000111111 rotrwi. r0, r0, 0
{ "srwi GPR , GPR , NUM",{0x54000FFE,0x03FFFFC0}}, // 010101xxxxxxxxxxxxxxxxxxxx111110 srwi r0, r0, 0x1f
{ "rlwnm GPR , GPR , GPR , NUM , NUM",{0x5C000000,0x03FFFFFE}}, // 010111xxxxxxxxxxxxxxxxxxxxxxxxx0 rlwnm r0, r0, r0, 0, 0
{"rlwnm . GPR , GPR , GPR , NUM , NUM",{0x5C000001,0x03FFFFFE}}, // 010111xxxxxxxxxxxxxxxxxxxxxxxxx1 rlwnm. r0, r0, r0, 0, 0
@@ -1271,8 +1283,20 @@ map<string, info> lookup = {
{ "andis . GPR , GPR , NUM",{0x74000000,0x03FFFFFF}}, // 011101xxxxxxxxxxxxxxxxxxxxxxxxxx andis. r0, r0, 0
{ "rotldi GPR , GPR , NUM",{0x78000000,0x03FFF802}}, // 011110xxxxxxxxxxxxxxx000000000x0 rotldi r0, r0, 0
{ "rotldi . GPR , GPR , NUM",{0x78000001,0x03FFF802}}, // 011110xxxxxxxxxxxxxxx000000000x1 rotldi. r0, r0, 0
+{ "rotrdi GPR , GPR , NUM",{0x78000000,0x03FFF802}}, // 011110xxxxxxxxxxxxxxx000000000x0 rotrdi r0, r0, 0
+{ "rotrdi . GPR , GPR , NUM",{0x78000001,0x03FFF802}}, // 011110xxxxxxxxxxxxxxx000000000x1 rotrdi. r0, r0, 0
+
+{ "extrdi . GPR , GPR , NUM , NUM",{0x78000023,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx000x1 rldicl. r0, r0, 0x20, 0x20
+
+// clrrdi r1, r1, 0x5 782106a4 // 011110'00001'00001'00000'110101'00100
+// // 000000'11111'11111'00000'111111'00000
+{ "clrrdi GPR , GPR , NUM",{0x78000004,0x03FF07E0}}, // 011110'xxxxx'xxxxx'00000'xxxxxx'00100 clrrdi r0, r0, 0x20
+{ "clrrdi . GPR , GPR , NUM",{0x78000005,0x03FF07E0}}, // 011110xxxxxxxxxx00000xxxxxx00101 clrrdi. r0, r0, 0x20
+{ "extldi GPR , GPR , NUM , NUM",{0x78000004,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx001x0 extldi r0, r0, 1, 0
+{ "extldi . GPR , GPR , NUM , NUM",{0x78000005,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx001x1 extldi. r0, r0, 1, 0
{ "rldicr GPR , GPR , NUM , NUM",{0x78000004,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx001x0 rldicr r0, r0, 0, 0
{ "rldicr . GPR , GPR , NUM , NUM",{0x78000005,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx001x1 rldicr. r0, r0, 0, 0
+
{ "rldic GPR , GPR , NUM , NUM",{0x78000008,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx010x0 rldic r0, r0, 0, 0
{ "rldic . GPR , GPR , NUM , NUM",{0x78000009,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx010x1 rldic. r0, r0, 0, 0
{ "rldimi GPR , GPR , NUM , NUM",{0x7800000C,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx011x0 rldimi r0, r0, 0, 0
@@ -1281,13 +1305,20 @@ map<string, info> lookup = {
{ "rotld . GPR , GPR , GPR",{0x78000011,0x03FFF800}}, // 011110xxxxxxxxxxxxxxx00000010001 rotld. r0, r0, r0
{ "rldcr GPR , GPR , GPR , NUM",{0x78000012,0x03FFFFE0}}, // 011110xxxxxxxxxxxxxxxxxxxxx10010 rldcr r0, r0, r0, 0
{ "rldcr . GPR , GPR , GPR , NUM",{0x78000013,0x03FFFFE0}}, // 011110xxxxxxxxxxxxxxxxxxxxx10011 rldcr. r0, r0, r0, 0
+
{ "clrldi GPR , GPR , NUM",{0x78000020,0x03FF07E0}}, // 011110xxxxxxxxxx00000xxxxxx00000 clrldi r0, r0, 0x20
{ "clrldi . GPR , GPR , NUM",{0x78000021,0x03FF07E0}}, // 011110xxxxxxxxxx00000xxxxxx00001 clrldi. r0, r0, 0x20
+{ "extrdi GPR , GPR , NUM , NUM",{0x78000022,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx000x0 extrdi r0, r0, 1, 0x20
+{ "extrdi . GPR , GPR , NUM , NUM",{0x78000023,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx000x1 extrdi. r0, r0, 1, 0x20
{ "rldicl GPR , GPR , NUM , NUM",{0x78000022,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx000x0 rldicl r0, r0, 0x20, 0x20
{ "rldicl . GPR , GPR , NUM , NUM",{0x78000023,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx000x1 rldicl. r0, r0, 0x20, 0x20
+
{ "rldcl GPR , GPR , GPR , NUM",{0x78000030,0x03FFFFE0}}, // 011110xxxxxxxxxxxxxxxxxxxxx10000 rldcl r0, r0, r0, 0x20
{ "rldcl . GPR , GPR , GPR , NUM",{0x78000031,0x03FFFFE0}}, // 011110xxxxxxxxxxxxxxxxxxxxx10001 rldcl. r0, r0, r0, 0x20
{ "sldi GPR , GPR , NUM",{0x780007C6,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx001x0 sldi r0, r0, 0x20
+{ "srdi GPR , GPR , NUM",{0x780007C4,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx000x0 srdi r0, r0, 0x20
+{ "sldi . GPR , GPR , NUM",{0x780007C7,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx001x0 sldi. r0, r0, 0x20
+{ "srdi . GPR , GPR , NUM",{0x780007C5,0x03FFFFE2}}, // 011110xxxxxxxxxxxxxxxxxxxxx000x0 srdi. r0, r0, 0x20
{ "cmpw GPR , GPR",{0x7C000000,0x001FF800}}, // 01111100000xxxxxxxxxx00000000000 cmpw r0, r0
{ "tw NUM , GPR , GPR",{0x7C000008,0x03FFF800}}, // 011111xxxxxxxxxxxxxxx00000001000 tw 0, r0, r0
{ "lvsl VREG , NUM , GPR",{0x7C00000C,0x03E0F800}}, // 011111xxxxx00000xxxxx00000001100 lvsl v0, 0, r0
@@ -2160,8 +2191,16 @@ const char *cs_err_to_string(cs_err e)
}
}
+int disasm_binja(uint8_t *data, uint32_t addr, string& result, string& err)
+{
+ return disassemble(data, addr, result);
+}
+
int disasm_capstone(uint8_t *data, uint32_t addr, string& result, string& err)
{
+#ifndef ENABLE_CAPSTONE
+ return -1;
+#endif
int rc = -1;
static bool init = false;
@@ -2218,18 +2257,20 @@ int disasm_capstone(uint8_t *data, uint32_t addr, string& result, string& err)
/* instruction tokenizing */
/*****************************************************************************/
-#define TT_GPR 1
-#define TT_VREG 2
-#define TT_FLAG 3
-#define TT_CREG 4
-#define TT_VSREG 5
-#define TT_FREG 6
-#define TT_NUM 7
-#define TT_PUNC 8
-#define TT_OPC 9
-
+enum t_type
+{
+ TT_GPR = 1,
+ TT_VREG = 2,
+ TT_FLAG = 3,
+ TT_CREG = 4,
+ TT_VSREG = 5,
+ TT_FREG = 6,
+ TT_NUM = 7,
+ TT_PUNC = 8,
+ TT_OPC = 9,
+};
struct token {
- int type;
+ t_type type;
uint32_t ival;
string sval;
};
@@ -2380,6 +2421,7 @@ void tokens_print(vector<token>& tokens)
case TT_FREG:
case TT_VSREG:
case TT_NUM:
+ case TT_FLAG:
printf("%s: %d\n", token_type_tostr(t.type), t.ival);
break;
case TT_PUNC:
@@ -2449,6 +2491,7 @@ float fitness(vector<token> dst, vector<token> src) {
float score(vector<token> baseline, uint32_t newcomer, uint32_t addr)
{
+ // return 0;
vector<token> toks_child;
string err;
string src;
@@ -2471,6 +2514,86 @@ float score(vector<token> baseline, uint32_t newcomer, uint32_t addr)
return fitness(baseline, toks_child);
}
+float score_binja(vector<token> baseline, uint32_t newcomer, uint32_t addr)
+{
+ vector<token> toks_child;
+ string err;
+ string src;
+
+ if(disasm_binja((uint8_t *)&newcomer, addr, src, err))
+ return -1;
+
+ /* compare mnemonics before doing more work */
+ string mnem = baseline[0].sval;
+ if(src.compare(0, mnem.size(), mnem) != 0) {
+ // A few special case equivalences that it can't figure out on its own
+ if (mnem == "rotrdi" && src.compare(0, 6, "rotldi") == 0)
+ {
+ if (tokenize("rotrdi" + src.substr(6), toks_child, err))
+ return 0;
+ toks_child.back().ival = 64 - toks_child.back().ival;
+ }
+ else if (mnem == "rldicl" && src.compare(0, 6, "rotldi") == 0)
+ {
+ if (tokenize("rldicl" + src.substr(6), toks_child, err))
+ return 0;
+ toks_child.push_back({TT_PUNC, 0, ","});
+ toks_child.push_back({TT_NUM, 0, ""});
+ }
+ else if (mnem == "rldcl" && src.compare(0, 5, "rotld") == 0)
+ {
+ if (tokenize("rldcl" + src.substr(5), toks_child, err))
+ return 0;
+ toks_child.push_back({TT_PUNC, 0, ","});
+ toks_child.push_back({TT_NUM, 0, ""});
+ }
+ else if (mnem == "rlwinm")
+ {
+ if (src.compare(0, 6, "clrrwi") == 0)
+ {
+ if (tokenize("rlwinm" + src.substr(6), toks_child, err))
+ return 0;
+ uint32_t me = toks_child.back().ival;
+ toks_child.back().ival = 0;
+ toks_child.push_back({TT_PUNC, 0, ","});
+ toks_child.push_back({TT_NUM, 0, ""});
+ toks_child.push_back({TT_PUNC, 0, ","});
+ toks_child.push_back({TT_NUM, 31 - me, ""});
+ }
+ else if (src.compare(0, 6, "clrlwi") == 0)
+ {
+ if (tokenize("rlwinm" + src.substr(6), toks_child, err))
+ return 0;
+ uint32_t mb = toks_child.back().ival;
+ toks_child.back().ival = 0;
+ toks_child.push_back({TT_PUNC, 0, ","});
+ toks_child.push_back({TT_NUM, mb, ""});
+ toks_child.push_back({TT_PUNC, 0, ","});
+ toks_child.push_back({TT_NUM, 31, ""});
+ }
+ else if (src.compare(0, 6, "rotlwi") == 0)
+ {
+ if (tokenize("rlwinm" + src.substr(6), toks_child, err))
+ return 0;
+ toks_child.push_back({TT_PUNC, 0, ","});
+ toks_child.push_back({TT_NUM, 0, ""});
+ toks_child.push_back({TT_PUNC, 0, ","});
+ toks_child.push_back({TT_NUM, 31, ""});
+ }
+ }
+ else
+ return 0;
+ }
+
+ /* mnemonics are the same, tokenize now... */
+ if(toks_child.size() == 0 && tokenize(src, toks_child, err)) {
+ printf("ERROR: %s\n", err.c_str());
+ return 0;
+ }
+
+ return fitness(baseline, toks_child);
+}
+
struct match {
uint32_t src_hi, src_lo; // source bit range
uint32_t dst_hi, dst_lo; // destination bit range
@@ -2512,12 +2635,15 @@ uint32_t enforce_bit_match(uint32_t inp, unsigned bit, vector<match> matches)
// seed: the seed value that may need the special case
// insword: instruction word
// bit: last bit changed
-uint32_t special_handling(uint32_t seed, uint32_t insword, int bit)
+uint32_t special_handling(uint32_t seed, uint32_t insword, int bit, vector<token> baseline)
{
switch(seed) {
/* sldi is extended mnemonic for rldicr (when mask = 63-shift) and hops
to it or other extended mnemonics easily */
case 0x780007C6:
+ // case 0x780007C4:
+ case 0x780007C7:
+ // case 0x780007C5:
/* if shift field changed, update mask */
if(bit==1 || (bit>=11 && bit<=15)) {
uint32_t shift = ((insword>>1)&1) | ((insword>>10)&0x3E);
@@ -2532,6 +2658,24 @@ uint32_t special_handling(uint32_t seed, uint32_t insword, int bit)
}
/* neither field updated */
return insword;
+ // case 0x780007C6:
+ case 0x780007C4:
+ // case 0x780007C7:
+ case 0x780007C5:
+ /* if shift field changed, update mask */
+ if(bit==1 || (bit>=11 && bit<=15)) {
+ uint32_t shift = ((insword>>1)&1) | ((insword>>10)&0x3E);
+ uint32_t mask = 64-shift;
+ return (insword&0xFFFFF81F) | (mask<<5);
+ }
+ /* if mask field changed, update shift */
+ if(bit>=5 && bit<=10) {
+ uint32_t mask = (insword>>5)&0x3F;
+ uint32_t shift = 64-mask;
+ return (insword&0xFFFF07FD) | ((shift&0x3E)<<11) | ((shift&0x1)<<1);
+ }
+ /* neither field updated */
+ return insword;
case 0x54000FFE: // srwi
if(bit>=6 && bit<=10) {
@@ -2767,6 +2911,8 @@ bool fmt_match(string fmt, string str, vector<string>& result)
/*****************************************************************************/
#define FAILURES_LIMIT 10000
+
+
int assemble_single(string src, uint32_t addr, uint8_t *result, string& err,
int& failures)
{
@@ -2805,11 +2951,17 @@ int assemble_single(string src, uint32_t addr, uint8_t *result, string& err,
toks_src.back().ival = -toks_src.back().ival;
toks_src[0].sval = "addis";
}
+ else if(!strncmp("rotrwi", toks_src[0].sval.c_str(), 6) &&
+ toks_src.back().type == TT_NUM) {
+ toks_src.back().ival = 32-toks_src.back().ival;
+ toks_src[0].sval = "rotlwi";
+ }
/* start with the parent */
uint32_t parent = info.seed;
float init_score, top_score;
- init_score = top_score = score(toks_src, parent, addr);
+ init_score = top_score = max(score(toks_src, parent, addr),
+ score_binja(toks_src, parent, addr));
/* cache the xor masks */
int n_flips = 0;
@@ -2839,9 +2991,10 @@ int assemble_single(string src, uint32_t addr, uint8_t *result, string& err,
for(; b1i<n_flips; b1i = (b1i+1) % n_flips) {
uint32_t child = parent ^ flipper[b1i];
- child = special_handling(info.seed, child, flipper_idx[b1i]);
+ child = special_handling(info.seed, child, flipper_idx[b1i], toks_src);
- float s = score(toks_src, child, addr);
+ float s = max(score(toks_src, child, addr),
+ score_binja(toks_src, child, addr));
if(s > top_score) {
parent = child;
top_score = s;
@@ -2864,20 +3017,22 @@ int assemble_single(string src, uint32_t addr, uint8_t *result, string& err,
for(int i=0; i<n_flips; ++i) {
if(rand()%2) {
parent ^= flipper[i];
- parent = special_handling(info.seed, parent, flipper_idx[i]);
+ parent = special_handling(info.seed, parent, flipper_idx[i], toks_src);
}
}
-
- top_score = score(toks_src, parent, addr);
+ top_score = max(score(toks_src, parent, addr),
+ score_binja(toks_src, parent, addr));
if(top_score >= init_score) {
MYLOG("perturbing the parent to: %08X (score:%f) (vs:%f)\n", parent, top_score, init_score);
break;
}
else {
+#if DEBUG
string tmp;
disasm_capstone((uint8_t *)&parent, addr, tmp, err);
MYLOG("%08X: %s perturb fail %f\n", parent, tmp.c_str(), top_score);
+#endif
failures++;
}
diff --git a/arch/powerpc/build_capstone_compare.sh b/arch/powerpc/build_capstone_compare.sh
new file mode 100755
index 00000000..ed806267
--- /dev/null
+++ b/arch/powerpc/build_capstone_compare.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+gcc -I decode decode/decode.c decode/mnemonic.c decode/names.c decode/operands.c decode/priv.c capstone_compare_test.c -l capstone -g -Wall -O3 -o capstone_compare.bin
diff --git a/arch/powerpc/capstone_compare_test.c b/arch/powerpc/capstone_compare_test.c
new file mode 100644
index 00000000..0c64c0eb
--- /dev/null
+++ b/arch/powerpc/capstone_compare_test.c
@@ -0,0 +1,1875 @@
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "capstone/capstone.h"
+
+#include "decode/decode.h"
+
+bool crbit_equal(ppc_reg cs_reg, uint32_t crbit)
+{
+ if (crbit >= 32)
+ {
+ printf("invalid new crbit %d\n", crbit);
+ return false;
+ }
+
+ if (cs_reg < PPC_REG_CR0EQ || cs_reg > PPC_REG_CR7UN)
+ {
+ printf("invalid cs crbit cs reg %d\n", cs_reg);
+ return false;
+ }
+
+ uint32_t crn = 0;
+ uint32_t bit = 0;
+ if (PPC_REG_CR0EQ <= cs_reg && cs_reg <= PPC_REG_CR7EQ)
+ {
+ crn = cs_reg - PPC_REG_CR0EQ;
+ bit = 2;
+ }
+ else if (PPC_REG_CR0GT <= cs_reg && cs_reg <= PPC_REG_CR7GT)
+ {
+ crn = cs_reg - PPC_REG_CR0GT;
+ bit = 1;
+ }
+ else if (PPC_REG_CR0LT <= cs_reg && cs_reg <= PPC_REG_CR7LT)
+ {
+ crn = cs_reg - PPC_REG_CR0LT;
+ bit = 0;
+ } else {
+ // PPC_REG_CR0UN <= cs_reg && cs_reg <= PPC_REG_CR7UN
+ crn = cs_reg - PPC_REG_CR0UN;
+ bit = 3;
+ }
+
+ uint32_t cs_equivalent = 4*crn + bit;
+ return crbit == cs_equivalent;
+}
+
+bool ops_equal(csh handle, const cs_ppc_op* capstone_op, const Operand* new_op)
+{
+ switch (new_op->cls)
+ {
+ case PPC_OP_NONE: return capstone_op->type == PPC_OP_INVALID;
+
+ case PPC_OP_UIMM:
+ {
+ // handle RA|0
+ if (capstone_op->type == PPC_OP_REG)
+ {
+ if (capstone_op->reg == PPC_REG_INVALID)
+ {
+ if (new_op->uimm != 0)
+ {
+ printf("new operand is UIMM %ld != 0, when capstone is PPC_REG_INVALID\n",
+ new_op->uimm);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ printf("new operand is UIMM %ld, capstone is REG %d != PPC_REG_INVALID\n",
+ new_op->uimm, capstone_op->reg);
+ return false;
+ }
+
+ if (capstone_op->type != PPC_OP_IMM)
+ {
+ printf("new operand is UIMM, but capstone is %d\n", capstone_op->type);
+ return false;
+ }
+
+ int64_t capstone_imm = capstone_op->imm;
+ int64_t new_imm = new_op->uimm;
+
+ if (capstone_imm != new_imm)
+ {
+ printf("new operand UIMM is %#lx, capstone imm is %#lx\n",
+ new_imm, capstone_imm);
+ return false;
+ }
+
+ return true;
+ }
+
+ case PPC_OP_SIMM:
+ {
+ if (capstone_op->type != PPC_OP_IMM)
+ {
+ printf("new operand is SIMM, but capstone is %d\n", capstone_op->type);
+ return false;
+ }
+
+ int64_t capstone_imm = capstone_op->imm;
+ int64_t new_imm = new_op->simm;
+
+ if (capstone_imm != new_imm)
+ {
+ printf("new operand SIMM is %#lx, capstone imm is %#lx\n",
+ new_imm, capstone_imm);
+ return false;
+ }
+
+ return true;
+ }
+
+ case PPC_OP_REG_RA:
+ case PPC_OP_REG_RB:
+ case PPC_OP_REG_RC:
+ case PPC_OP_REG_RD:
+ case PPC_OP_REG_RS:
+ {
+ if (capstone_op->type != PPC_OP_REG)
+ {
+ printf("new operand is register, but capstone is %d\n", capstone_op->type);
+ return false;
+ }
+
+ int capstone_reg = capstone_op->reg - PPC_REG_R0;
+ int new_reg = new_op->reg - NUPPC_REG_GPR0;
+
+ if (capstone_reg != new_reg)
+ {
+ printf("new operand register %d, capstone register %d\n",
+ new_reg, capstone_reg);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ case PPC_OP_REG_FRA:
+ case PPC_OP_REG_FRB:
+ case PPC_OP_REG_FRC:
+ case PPC_OP_REG_FRD:
+ case PPC_OP_REG_FRS:
+ {
+ if (capstone_op->type != PPC_OP_REG)
+ {
+ printf("new operand is register, but capstone is %d\n", capstone_op->type);
+ return false;
+ }
+
+ int capstone_reg = capstone_op->reg - PPC_REG_F0;
+ int new_reg = new_op->reg - NUPPC_REG_FR0;
+
+ if (capstone_reg != new_reg)
+ {
+ printf("new operand register %d, capstone register %d\n",
+ new_reg, capstone_reg);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ case PPC_OP_REG_CRFD:
+ case PPC_OP_REG_CRFD_IMPLY0:
+ case PPC_OP_REG_CRFS:
+ {
+ if (capstone_op->type != PPC_OP_REG)
+ {
+ printf("new operand is CR, but capstone is %d\n", capstone_op->type);
+ return false;
+ }
+
+ int capstone_reg = capstone_op->reg - PPC_REG_CR0;
+ int new_reg = new_op->reg - NUPPC_REG_CRF0;
+
+ if (capstone_reg != new_reg)
+ {
+ printf("new operand CR %d, capstone CR register %d\n",
+ new_reg, capstone_reg);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ case PPC_OP_CRBIT_A:
+ case PPC_OP_CRBIT_B:
+ case PPC_OP_CRBIT_D:
+ {
+ if (capstone_op->type != PPC_OP_REG)
+ {
+ printf("new operand is CRbit, but capstone is %d\n", capstone_op->type);
+ return false;
+ }
+
+ const char* capstone_name = cs_reg_name(handle, capstone_op->reg);
+
+ if (!crbit_equal(capstone_op->reg, new_op->crbit))
+ {
+ printf("new operand CR %d, capstone CR register %d (%s)\n",
+ new_op->crbit, capstone_op->reg, capstone_name);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ case PPC_OP_REG_AV_VA:
+ case PPC_OP_REG_AV_VB:
+ case PPC_OP_REG_AV_VC:
+ case PPC_OP_REG_AV_VD:
+ case PPC_OP_REG_AV_VS:
+ {
+ if (capstone_op->type != PPC_OP_REG)
+ {
+ printf("new operand is altivec register, but capstone is %d\n", capstone_op->type);
+ return false;
+ }
+
+ int capstone_reg = capstone_op->reg - PPC_REG_V0;
+ int new_reg = new_op->reg - NUPPC_REG_AV_VR0;
+
+ if (capstone_reg != new_reg)
+ {
+ printf("new operand altivec register %d, capstone altivec register %d\n",
+ new_reg, capstone_reg);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ case PPC_OP_REG_VSX_RA:
+ case PPC_OP_REG_VSX_RB:
+ case PPC_OP_REG_VSX_RC:
+ case PPC_OP_REG_VSX_RD:
+ case PPC_OP_REG_VSX_RS:
+ {
+ if (capstone_op->type != PPC_OP_REG)
+ {
+ printf("new operand is vsx (full) register, but capstone is %d\n", capstone_op->type);
+ return false;
+ }
+
+ const char* capstone_name = cs_reg_name(handle, capstone_op->reg);
+ int new_reg = new_op->reg - NUPPC_REG_VSX_VR0;
+ int capstone_reg;
+ if (PPC_REG_VS0 <= capstone_op->reg && capstone_op->reg <= PPC_REG_VS63)
+ capstone_reg = capstone_op->reg - PPC_REG_VS0;
+ else if (PPC_REG_V0 <= capstone_op->reg && capstone_op->reg <= PPC_REG_V31)
+ capstone_reg = capstone_op->reg - PPC_REG_V0 + 32;
+ else
+ {
+ printf("new operand vsx (full) register %d, capstone register %d (%s) isn't any kind of vector\n", new_reg, capstone_op->reg, capstone_name);
+
+ return false;
+ }
+
+ if (capstone_reg != new_reg)
+ {
+ printf("new operand vsx (full) register %d, capstone vsx register %d (%s)\n",
+ new_reg, capstone_reg, capstone_name);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ case PPC_OP_REG_VSX_RA_DWORD0:
+ case PPC_OP_REG_VSX_RB_DWORD0:
+ case PPC_OP_REG_VSX_RC_DWORD0:
+ case PPC_OP_REG_VSX_RD_DWORD0:
+ case PPC_OP_REG_VSX_RS_DWORD0:
+ {
+ if (capstone_op->type != PPC_OP_REG)
+ {
+ printf("new operand is vsx (dword0) register, but capstone is %d\n", capstone_op->type);
+ return false;
+ }
+
+ const char* capstone_name = cs_reg_name(handle, capstone_op->reg);
+ int new_reg = new_op->reg - NUPPC_REG_VSX_VR0;
+ int capstone_reg;
+ if (PPC_REG_VS0 <= capstone_op->reg && capstone_op->reg <= PPC_REG_VS63)
+ capstone_reg = capstone_op->reg - PPC_REG_VS0;
+ else if (PPC_REG_V0 <= capstone_op->reg && capstone_op->reg <= PPC_REG_V31)
+ capstone_reg = capstone_op->reg - PPC_REG_V0 + 32;
+ else if (PPC_REG_F0 <= capstone_op->reg && capstone_op->reg <= PPC_REG_F31)
+ capstone_reg = capstone_op->reg - PPC_REG_F0;
+ else
+ {
+ printf("new operand vsx (dword0) register %d, capstone register %d (%s) isn't any kind of vector\n", new_reg, capstone_op->reg, capstone_name);
+
+ return false;
+ }
+
+
+ if (capstone_reg != new_reg)
+ {
+ printf("new operand vsx (dword0) register %d, capstone vsx register %d (%s)\n",
+ new_reg, capstone_reg, capstone_name);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ case PPC_OP_MEM_RA:
+ {
+ if (capstone_op->type != PPC_OP_MEM)
+ {
+ printf("new operand is memory, but capstone is %d\n", capstone_op->type);
+ return false;
+ }
+
+ // memory are of the form RA|0
+ int new_reg = new_op->mem.reg - NUPPC_REG_GPR0;
+ if (new_reg == 0)
+ {
+ if (capstone_op->mem.base != PPC_REG_INVALID)
+ {
+ printf("new operand mem reg is r0, capstone mem reg is %d != invalid\n",
+ capstone_op->mem.base);
+ return false;
+ }
+ }
+ else
+ {
+ int capstone_reg = capstone_op->mem.base - PPC_REG_R0;
+ if (capstone_reg != new_reg)
+ {
+ printf("new operand mem reg is %d, capstone mem reg is %d\n",
+ new_reg, capstone_reg);
+ return false;
+ }
+ }
+
+ int capstone_offset = capstone_op->mem.disp;
+ int new_offset = new_op->mem.offset;
+
+ if (capstone_offset != new_offset)
+ {
+ printf("new operand mem offset is %d, capstone mem offset is %d\n",
+ new_offset, capstone_offset);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ default:
+ printf("unhandled class %d\n", new_op->cls);
+ return false;
+ }
+
+}
+
+uint32_t bc_to_bi(ppc_bc bc)
+{
+ switch (bc)
+ {
+ case PPC_BC_LT: return 0;
+ case PPC_BC_GT: return 1;
+ case PPC_BC_EQ: return 2;
+ case PPC_BC_SO: return 3;
+ default: return 0xffffffff;
+ }
+}
+
+uint32_t crx_to_bi(const ppc_op_crx* crx)
+{
+ uint32_t crn = (crx->reg - PPC_REG_CR0);
+ uint32_t extra = 0;
+ switch (crx->cond)
+ {
+ case PPC_BC_LT: extra = 0; break;
+ case PPC_BC_GT: extra = 1; break;
+ case PPC_BC_EQ: extra = 2; break;
+ case PPC_BC_SO: extra = 3; break;
+
+ default:
+ printf("bcx capstone op 0 cond is weird %d\n",
+ crx->cond);
+ return 0xffffffff;
+ }
+
+ return crx->scale*crn + extra;
+}
+
+// compare bcx <bit> <label> (for decrementing CTR and checking if bit is true)
+bool bcx_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction, const OperandsList* bcx, uint64_t address)
+{
+ if (bcx->operands[0].cls != PPC_OP_UIMM || bcx->operands[1].cls != PPC_OP_LABEL)
+ {
+ printf("bcx new ops 0/1 are %d/%d not UIMM/LABEL\n",
+ bcx->operands[0].cls,
+ bcx->operands[1].cls);
+ return false;
+ }
+
+ if (capstone_instruction->op_count == 0)
+ {
+ // I don't know if it's idiomatic to be able to exclude the
+ // address for branch instructions, but when BD is 0 (whether
+ // the 'aa' bit is set or not), capstone omits the address
+ // token?
+ if (new_instruction->flags.aa && bcx->operands[1].label == 0)
+ return true;
+
+ if (!new_instruction->flags.aa && bcx->operands[1].label == address)
+ return true;
+
+ printf("bcx capstone 0 operands but new target %" PRIx64 " isn't address %" PRIx64" \n",
+ bcx->operands[1].label, address);
+
+ return false;
+ }
+
+ switch (capstone_instruction->operands[0].type)
+ {
+ case PPC_OP_IMM:
+ {
+ if (bcx->operands[1].label != capstone_instruction->operands[0].imm)
+ {
+ printf("bcx new op1 %08lx != capstone bc %08lx\n",
+ bcx->operands[1].uimm, capstone_instruction->operands[0].imm);
+
+ return false;
+ }
+
+ return true;
+ }
+ case PPC_OP_CRX:
+ {
+ printf("capstone op 0 is crx");
+ return false;
+ }
+
+ case PPC_OP_REG:
+ {
+ if (capstone_instruction->op_count >= 3) {
+ printf("bcx (crbit) capstone has too many (%d) args\n",
+ capstone_instruction->op_count);
+
+ return false;
+ }
+
+ if (!crbit_equal(capstone_instruction->operands[0].reg, bcx->operands[0].uimm))
+ {
+ printf("bcx (crbit) crbit not equivalent: new uimm %ld, cs reg %d\n",
+ bcx->operands[0].uimm, capstone_instruction->operands[0].reg);
+ return false;
+ }
+
+ if (capstone_instruction->op_count == 2 && (capstone_instruction->operands[1].imm != bcx->operands[1].label))
+ {
+ printf("bcx (crbit) labels not equivalent: new label %lx, cs imm %lx\n",
+ bcx->operands[1].label, capstone_instruction->operands[1].imm);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ default:
+ printf("bcx capstone op 0 is %d not PPC_OP_IMM\n",
+ capstone_instruction->operands[0].type);
+ return false;
+ }
+
+ return true;
+}
+
+bool bcx_2op_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction, const OperandsList* bcx, uint64_t address)
+{
+ if (bcx->numOperands != 2)
+ {
+ printf("bcx 2op equal unknown number of arguments for new %ld\n",
+ bcx->numOperands);
+
+ return false;
+ }
+
+ if (bcx->operands[0].cls != PPC_OP_REG_CRFS && bcx->operands[1].cls != PPC_OP_LABEL)
+ {
+ printf("bcx 2op equal unexpected op classes %d/%d (new)\n",
+ bcx->operands[0].cls, bcx->operands[1].cls);
+
+ return false;
+ }
+
+ if (capstone_instruction->op_count == 0)
+ {
+ if (bcx->operands[0].reg != NUPPC_REG_CRF0)
+ {
+ printf("bcx 2op equal capstone 0 operands but new reg %d isn't CRF0 %d\n",
+ bcx->operands[0].reg, NUPPC_REG_CRF0);
+
+ return false;
+ }
+
+ // I don't know if it's idiomatic to be able to exclude the
+ // address for branch instructions, but when BD is 0 (whether
+ // the 'aa' bit is set or not), capstone omits the address
+ // token?
+ if (new_instruction->flags.aa && bcx->operands[1].label == 0)
+ return true;
+
+ if (!new_instruction->flags.aa && bcx->operands[1].label == address)
+ return true;
+
+ printf("bcx 2op equal capstone 0 operand but new target %lx isn't address %lx\n",
+ bcx->operands[1].label, address);
+
+ return false;
+ }
+
+ if (capstone_instruction->op_count == 1)
+ {
+ if (capstone_instruction->operands[0].type == PPC_OP_REG)
+ {
+ // I don't know if it's idiomatic to be able to exclude the
+ // address for branch instructions, but when BD is 0 (whether
+ // the 'aa' bit is set or not), capstone omits the address
+ // token?
+ if (new_instruction->flags.aa && bcx->operands[1].label == 0)
+ return true;
+
+ if (!new_instruction->flags.aa && bcx->operands[1].label == address)
+ return true;
+
+ printf("bcx 2op equal capstone 1 operand but new target %lx isn't address %lx\n",
+ bcx->operands[1].label, address);
+
+ return false;
+ }
+ else if (capstone_instruction->operands[0].type == PPC_OP_IMM)
+ {
+ if (bcx->operands[0].reg != NUPPC_REG_CRF0)
+ {
+ printf("bcx 2op equal capstone 1 operand but new reg %d isn't CRF0 %d\n",
+ bcx->operands[0].reg, NUPPC_REG_CRF0);
+
+ return false;
+ }
+
+ if (bcx->operands[1].label != capstone_instruction->operands[0].imm)
+ {
+ printf("bcx 2op equal capstone 1 operand but new target %lx isn't capstone target %lx\n",
+ bcx->operands[1].label, capstone_instruction->operands[0].imm);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ printf("bcx 2op equal unexpected op type %d (capstone)\n",
+ capstone_instruction->operands[0].type);
+
+ return false;
+ }
+
+ if (capstone_instruction->operands[0].type != PPC_OP_REG || capstone_instruction->operands[1].type != PPC_OP_IMM)
+ {
+ printf("bcx 2op equal unexpected op type %d/%d (capstone)\n",
+ capstone_instruction->operands[0].type, capstone_instruction->operands[1].type);
+
+ return false;
+ }
+
+ uint32_t new_crn = bcx->operands[0].reg - NUPPC_REG_CRF0;
+ uint32_t cs_crn = capstone_instruction->operands[0].reg - PPC_REG_CR0;
+
+ if (new_crn != cs_crn)
+ {
+ printf("bcx 2op equal regs are different cs %d != new %d\n",
+ cs_crn, new_crn);
+
+ return false;
+ }
+
+ if (capstone_instruction->operands[1].imm != bcx->operands[1].label)
+ {
+ printf("bcx 2op equal targets are different cs %#lx != new %#lx\n",
+ capstone_instruction->operands[1].imm, new_instruction->operands[1].label);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool bcx_1op_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction, const OperandsList* bcx, uint64_t address)
+{
+ if (bcx->numOperands != 1)
+ {
+ printf("bcx 1op equal unknown number of arguments for new %ld\n",
+ bcx->numOperands);
+
+ return false;
+ }
+
+ if (bcx->operands[0].cls != PPC_OP_LABEL)
+ {
+ printf("bcx 1op equal unexpected op class %d (new)\n",
+ bcx->operands[0].cls);
+
+ return false;
+ }
+
+ if (capstone_instruction->op_count == 0)
+ {
+ if (new_instruction->flags.aa && bcx->operands[0].label == 0)
+ return true;
+
+ if (!new_instruction->flags.aa && bcx->operands[0].label == address)
+ return true;
+
+ printf("bcx 1op equal address mismatch; capstone no operands, aa %d new label %lx address %lx\n",
+ new_instruction->flags.aa, bcx->operands[0].label, address);
+
+ return false;
+ }
+
+ if (capstone_instruction->op_count != 1)
+ {
+ printf("bcx 1op equal unexpected count %d (capstone)\n",
+ capstone_instruction->op_count);
+
+ return false;
+ }
+
+ if (capstone_instruction->operands[0].imm != bcx->operands[0].label)
+ {
+ printf("bcx 1op equal labels not equal cs %lx != new %lx\n",
+ capstone_instruction->operands[0].imm,
+ bcx->operands[0].label);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool bcregx_noargs_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction)
+{
+ if (new_instruction->numOperands != 0)
+ {
+ printf("bcregx_noargs unknown number of arguments for new %ld\n",
+ new_instruction->numOperands);
+
+ return false;
+ }
+
+ if (capstone_instruction->op_count == 0)
+ return true;
+
+ // <op> <unnecessary target>
+ if (capstone_instruction->op_count == 1 && capstone_instruction->operands[0].type == PPC_OP_IMM)
+ return true;
+
+ printf("bcregx_noargs unexpected capstone structure: op count %d/op0 type %d\n",
+ capstone_instruction->op_count, capstone_instruction->operands[0].type);
+ return false;
+}
+
+// for BCCTRx and BCLRx variants when just "<op> BI"
+bool bcregx_bi_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction)
+{
+ if (new_instruction->numOperands != 1)
+ {
+ printf("bcregx_bi unknown number of arguments for new %ld\n",
+ new_instruction->numOperands);
+
+ return false;
+ }
+
+ if (new_instruction->operands[0].cls != PPC_OP_UIMM)
+ {
+ printf("bcregx_bi unknown new op0 class %d\n",
+ new_instruction->operands[0].cls);
+
+ return false;
+ }
+
+ // capstone uses just condition codes when CRn = 0; condition codes
+ // aren't treated as operands, so this happens when op_count == 0 and
+ // when capstone (unnecessarily?) adds a branch target
+ if (capstone_instruction->op_count == 0 || (capstone_instruction->op_count == 1 && capstone_instruction->operands[0].type == PPC_OP_IMM))
+ {
+ uint32_t cs_bi = bc_to_bi(capstone_instruction->bc);
+ if (new_instruction->operands[0].uimm != cs_bi)
+ {
+ printf("bcregx_bi cs_bi %d != new bi %ld\n",
+ cs_bi, new_instruction->operands[0].uimm);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ if (capstone_instruction->operands[0].type != PPC_OP_CRX)
+ {
+ printf("bcregx_bi unknown capstone op0 type %d\n",
+ capstone_instruction->operands[0].type);
+
+ return false;
+ }
+
+ uint32_t cs_bi = crx_to_bi(&capstone_instruction->operands[0].crx);
+ if (cs_bi != new_instruction->operands[0].uimm)
+ {
+ printf("bcregx_bi capstone BI %d != new BI %ld\n",
+ cs_bi, new_instruction->operands[0].uimm);
+
+ return false;
+ }
+
+ return true;
+}
+
+// bclrx/bcctrx
+bool bcregx1_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction, const OperandsList* bcregx)
+{
+ if (bcregx->numOperands != 1)
+ {
+ printf("bcregx1_equal unexpected num operands %ld (new)\n",
+ bcregx->numOperands);
+
+ return false;
+ }
+
+ if (bcregx->operands[0].cls != PPC_OP_CRBIT)
+ {
+ printf("bcregx1_equal unexpected op0 type %d isn't %d (new)\n",
+ bcregx->operands[0].cls, PPC_OP_CRBIT);
+
+ return false;
+ }
+
+ if (capstone_instruction->op_count == 0)
+ {
+ uint32_t cs_bi = bc_to_bi(capstone_instruction->bc);
+ if (bcregx->operands[0].crbit != cs_bi)
+ {
+ printf("bcregx1_equal capstone 1op op0 imm unexpected value %#x (new) != %#x (cs)\n",
+ bcregx->operands[0].crbit, cs_bi);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ else if (capstone_instruction->op_count == 1)
+ {
+ if (capstone_instruction->operands[0].type == PPC_OP_REG)
+ {
+ if (!crbit_equal(capstone_instruction->operands[0].reg, bcregx->operands[0].crbit))
+ {
+ printf("bcregx1_equal capstone 1op op0 reg %d != crbit %d\n",
+ capstone_instruction->operands[0].reg, bcregx->operands[0].crbit);
+ return false;
+ }
+
+ return true;
+ }
+
+ printf("bcregx1_equal capstone 1op op0 unexpected type %d",
+ capstone_instruction->operands[0].type);
+
+ return false;
+ }
+ else if (capstone_instruction->op_count == 2)
+ {
+ // <op> <BI> [unnecessary target]
+ if (capstone_instruction->operands[0].type == PPC_OP_CRX)
+ {
+ printf("bcregx1_equal 2op crx\n");
+ return false;
+ }
+ else if (capstone_instruction->operands[0].type == PPC_OP_REG)
+ {
+ if (!crbit_equal(capstone_instruction->operands[0].reg, bcregx->operands[0].crbit))
+ {
+ printf("bcregx1_equal capstone 2op op0 reg %d != crbit %d\n",
+ capstone_instruction->operands[0].reg, bcregx->operands[0].crbit);
+ return false;
+ }
+ return true;
+ }
+ else
+ {
+ printf("bcregx1_equal capstone 2op op0 unexpected type %d != PPC_OP_CRX %d\n",
+ capstone_instruction->operands[0].type, PPC_OP_CRX);
+
+ return false;
+ }
+ }
+
+ printf("bcregx1_equal unknown number of capstone operands %d\n",
+ capstone_instruction->op_count);
+
+ return false;
+}
+
+bool bcregx2_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction, const OperandsList* bcregx)
+{
+ if (bcregx->numOperands != 1)
+ {
+ printf("bcregx2_equal unexpected num operands %ld (new)\n",
+ bcregx->numOperands);
+
+ return false;
+ }
+
+ if (bcregx->operands[0].cls != PPC_OP_REG_CRFS_IMPLY0)
+ {
+ printf("bcregx2_equal unexpected op0 type %d isn't %d (new)\n",
+ bcregx->operands[0].cls, PPC_OP_REG_CRFS);
+
+ return false;
+ }
+
+ if (capstone_instruction->op_count == 0)
+ {
+ if (bcregx->operands[0].reg != NUPPC_REG_CRF0)
+ {
+ printf("bcregx2_equal capstone no ops but crn is %d != %d\n",
+ bcregx->operands[0].reg, NUPPC_REG_CRF0);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ if (capstone_instruction->op_count == 1)
+ {
+ if (capstone_instruction->operands[0].type == PPC_OP_REG)
+ {
+ uint32_t new_reg = bcregx->operands[0].reg - NUPPC_REG_CRF0;
+ uint32_t cs_reg = capstone_instruction->operands[0].reg - PPC_REG_CR0;
+
+ if (new_reg != cs_reg)
+ {
+ printf("bcregx2_equal capstone 1 op REG, new reg is %d != cs reg %d\n",
+ new_reg, cs_reg);
+
+ return false;
+ }
+
+ return true;
+ }
+ else if (capstone_instruction->operands[0].type == PPC_OP_IMM)
+ {
+ if (bcregx->operands[0].reg != NUPPC_REG_CRF0)
+ {
+ printf("bcregx2_equal capstone 1 op UIMM, new reg is %d != %d\n",
+ bcregx->operands[0].reg, NUPPC_REG_CRF0);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ printf("bcregx2_equal unexpected op0 %d (capstone)\n",
+ capstone_instruction->operands[0].type);
+
+ return false;
+ }
+
+ if (capstone_instruction->op_count == 2)
+ {
+ if (capstone_instruction->operands[0].type != PPC_OP_REG)
+ {
+ printf("bcregx2_equal capstone op0 type %d != %d\n",
+ capstone_instruction->operands[0].type, PPC_OP_REG);
+
+ return false;
+ }
+
+ uint32_t new_reg = bcregx->operands[0].reg - NUPPC_REG_CRF0;
+ uint32_t cs_reg = capstone_instruction->operands[0].reg - PPC_REG_CR0;
+
+ if (new_reg != cs_reg)
+ {
+ printf("bcregx2_equal capstone 2 op REG/UIMM, new reg is %d != cs reg %d\n",
+ new_reg, cs_reg);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ printf("bcregx2_equal unexpected num ops %d (capstone)\n",
+ capstone_instruction->op_count);
+
+ return false;
+}
+
+bool bcregx3_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction, const OperandsList* bcregx)
+{
+ if (bcregx->numOperands != 0)
+ {
+ printf("bcregx3_equal unexpected num operands %ld != 0 (new)\n",
+ bcregx->numOperands);
+
+ return false;
+ }
+
+ if (capstone_instruction->op_count == 0)
+ {
+ return true;
+ }
+ else if (capstone_instruction->op_count == 1)
+ {
+ if (capstone_instruction->operands[0].type != PPC_OP_IMM)
+ {
+ printf("bcregx3_equal cs 1-op unexpected op0 type %d != %d\n",
+ capstone_instruction->operands[0].type, PPC_OP_IMM);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ printf("bcregx3_equal unexpected num operands %d (cs)\n",
+ capstone_instruction->op_count);
+
+ return false;
+}
+
+bool bcregx_crn_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction)
+{
+ if (new_instruction->numOperands == 0)
+ {
+ if (capstone_instruction->op_count == 0)
+ {
+ return true;
+ }
+
+ if (capstone_instruction->op_count == 1 && capstone_instruction->operands[0].type == PPC_OP_IMM)
+ {
+ return true;
+ }
+
+ printf("bcregx_crn new has no ops but capstone has %d ops and op0 is type %d != %d\n",
+ capstone_instruction->op_count, capstone_instruction->operands[0].type, PPC_OP_IMM);
+ return false;
+ }
+
+ if (new_instruction->numOperands != 1)
+ {
+ printf("bcregx_crn unknown number of arguments for new %ld\n",
+ new_instruction->numOperands);
+
+ return false;
+ }
+
+ if (new_instruction->operands[0].cls != PPC_OP_REG_CRFS)
+ {
+ printf("bcregx_crn unknown new op0 class %d\n",
+ new_instruction->operands[0].cls);
+
+ return false;
+ }
+
+ uint32_t new_reg = new_instruction->operands[0].reg - NUPPC_REG_CRF0;
+
+ if (capstone_instruction->op_count == 0)
+ {
+ if (new_reg != 0)
+ {
+ printf("bcregx_crn capstone no ops, new reg %d != 0\n",
+ new_reg);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ // capstone: <op> [cr0] <unnecessary target address> or <op> <crX>
+ if (capstone_instruction->op_count == 1)
+ {
+ if (capstone_instruction->operands[0].type == PPC_OP_REG)
+ {
+ // capstone: <op> <crX>
+ uint32_t cs_reg = capstone_instruction->operands[0].reg - PPC_REG_CR0;
+ if (cs_reg != new_reg)
+ {
+ printf("bcregx_crn capstone 1 reg %d != new reg %d\n",
+ cs_reg, new_reg);
+
+ return false;
+
+ }
+
+ return true;
+ }
+ else if (capstone_instruction->operands[0].type == PPC_OP_IMM)
+ {
+ // capstone: <op> <target>
+ if (new_reg != 0)
+ {
+ printf("bcregx_crn capstone just target, new reg %d != 0\n",
+ new_reg);
+
+ return false;
+ }
+
+ return true;
+ }
+ else
+ {
+ printf("bcregx_crn capstone 1-op unknown type %d\n",
+ capstone_instruction->operands[0].type);
+
+ return false;
+ }
+ }
+
+ if (capstone_instruction->op_count == 2)
+ {
+ if (capstone_instruction->operands[0].type != PPC_OP_REG || capstone_instruction->operands[1].type != PPC_OP_IMM)
+ {
+ printf("bcregx_crn capstone 2-op types %d/%d != %d/%d\n",
+ capstone_instruction->operands[0].type,
+ capstone_instruction->operands[1].type,
+ PPC_OP_REG, PPC_OP_IMM);
+
+ return false;
+ }
+
+ uint32_t cs_reg = capstone_instruction->operands[0].reg - PPC_REG_CR0;
+ if (cs_reg != new_reg)
+ {
+ printf("bcregx_crn capstone 2-op new reg %d != cs reg %d\n",
+ new_reg, cs_reg);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ printf("bcregx_crn unknown number of operands in capstone %d\n",
+ capstone_instruction->op_count);
+
+ return false;
+}
+
+#define ADDRESS 0x1000
+
+int main(int argc, char* argv[])
+{
+ csh handle;
+ cs_insn *cs_instruction;
+ Instruction new_instruction;
+
+ int err = cs_open(CS_ARCH_PPC, CS_MODE_32 | CS_MODE_BIG_ENDIAN, &handle);
+ if (err != CS_ERR_OK)
+ {
+ printf("failed to open capstone: err %d\n", err);
+ return -1;
+ }
+
+ err = cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
+ if (err != CS_ERR_OK)
+ {
+ printf("failed to set detail on: err %d\n", err);
+ return -1;
+ }
+
+ uint32_t i;
+
+ for (i = 0x7c000000; i < 0x80000000; ++i)
+ {
+ uint32_t op = ((i << 24) & 0xff000000) | ((i << 8) & 0x00ff0000) | ((i >> 8) & 0x0000ff00) | ((i >> 24) & 0x000000ff);
+
+ bool cs_error = cs_disasm(handle, (uint8_t*)&op, sizeof op, ADDRESS, 1, &cs_instruction) != 1;
+ bool new_error = !Decompose32(&new_instruction, i, ADDRESS, DECODE_FLAGS_ALTIVEC | DECODE_FLAGS_PPC64 | DECODE_FLAGS_VSX);
+
+ if (cs_error != new_error)
+ {
+ if (new_error)
+ {
+ // capstone disassembled something that we don't
+ bool complain = true;
+
+ switch (cs_instruction->id)
+ {
+ // capstone is too eager to decode some instructions
+ case PPC_INS_MFSR:
+ case PPC_INS_MTSR:
+ if ((i & 0x0010f801) != 0)
+ complain = false;
+ break;
+ case PPC_INS_MFSRIN:
+ case PPC_INS_MTSRIN:
+ if ((i & 0x001f0001) != 0)
+ complain = false;
+ break;
+ case PPC_INS_WRTEE:
+ if ((i & 0x001ff801) != 0)
+ complain = false;
+ break;
+ case PPC_INS_WRTEEI:
+ if ((i & 0x03ff7801) != 0)
+ complain = false;
+ break;
+ case PPC_INS_MBAR:
+ case PPC_INS_MTMSR:
+ case PPC_INS_MTMSRD:
+ if ((i & 0x001ff801) != 0)
+ complain = false;
+ break;
+ case PPC_INS_DCCCI:
+ case PPC_INS_ICCCI:
+ if ((i & 0x021ff801) != 0)
+ complain = false;
+ break;
+
+ case PPC_INS_TLBSX:
+ // capstone thinks this has an "RC" bits
+ if ((i & 0x1) != 0)
+ complain = false;
+
+ // capstone is too eager to decode
+ if ((i & 0x03e00000) != 0)
+ complain = false;
+
+ break;
+
+ case PPC_INS_SC:
+ // capstone is too eager for sc
+ if ((i & 0x03fff01d) != 0)
+ complain = false;
+
+ break;
+
+ // capstone treats UIM as 5 bits when it's 4,
+ // with a reserved bit that should be clear
+ case PPC_INS_VEXTRACTD:
+ case PPC_INS_VEXTRACTUB:
+ case PPC_INS_VEXTRACTUH:
+ case PPC_INS_VEXTRACTUW:
+ case PPC_INS_VINSERTB:
+ case PPC_INS_VINSERTD:
+ case PPC_INS_VINSERTH:
+ case PPC_INS_VINSERTW:
+ case PPC_INS_XXEXTRACTUW:
+ case PPC_INS_XXINSERTW:
+ if ((i & 0x00100000) != 0)
+ complain = false;
+
+ break;
+
+ // capstone has the wrong opcode for this (it's 0x18c, not 0x18d)
+ case PPC_INS_ICBLQ:
+ if ((i & 0x1) == 0)
+ complain = false;
+
+ break;
+
+ case PPC_INS_COPY:
+ // capstone doesn't check that bit 10 == 1
+ if (((i >> 21) & 0x1f) != 1)
+ complain = false;
+
+ break;
+
+ case PPC_INS_PASTE:
+ // capstone doesn't check that bit 10 == 1 or that bit 31 == 1
+ if ((((i >> 21) & 0x1f) != 1) || ((i & 0x1) != 1))
+ complain = false;
+
+ break;
+
+ case PPC_INS_LDMX:
+ // this instruction never made it into POWER9:
+ // https://inbox.sourceware.org/binutils/c3a53df0-cdf4-de7b-0e50-75150f2fa456@linux.ibm.com/T/
+ // I guess we could add support, but it's something that would
+ // only apply to like pre-release binaries
+ complain = false;
+ break;
+
+ case PPC_INS_DCBZLEP:
+ // I can't find any official docs about this
+ complain = false;
+ break;
+
+ case PPC_INS_DCBF:
+ // L is only 2 bits, capstone recognizes more
+ if (((i >> 21) & 0x1f) > 3)
+ complain = false;
+
+ break;
+
+ default:
+ ;
+ }
+
+ if (complain)
+ printf("capstone succeeded but new failed for %08x: %s %s [id %d]\n",
+ i, cs_instruction->mnemonic, cs_instruction->op_str, cs_instruction->id);
+
+ cs_free(cs_instruction, 1);
+ }
+ else
+ {
+ // we disassembled something that capstone doesn't
+ bool complain = true;
+
+ switch (new_instruction.id)
+ {
+ // capstone doesn't seem to handle these
+ case PPC_ID_ECIWX:
+ case PPC_ID_ECOWX:
+ case PPC_ID_FCMPO:
+ case PPC_ID_LSWX:
+ case PPC_ID_STSWX:
+ case PPC_ID_TLBIA:
+ case PPC_ID_STDEPX:
+ complain = false;
+ break;
+
+ // capstone doesn't seem to handle "o" suffix
+ case PPC_ID_ADDx:
+ case PPC_ID_ADDCx:
+ case PPC_ID_ADDEx:
+ case PPC_ID_ADDMEx:
+ case PPC_ID_ADDZEx:
+ case PPC_ID_DIVDx:
+ case PPC_ID_DIVDEx:
+ case PPC_ID_DIVDEUx:
+ case PPC_ID_DIVDUx:
+ case PPC_ID_DIVWx:
+ case PPC_ID_DIVWEx:
+ case PPC_ID_DIVWEUx:
+ case PPC_ID_DIVWUx:
+ case PPC_ID_MULLDx:
+ case PPC_ID_MULLWx:
+ case PPC_ID_NEGx:
+ case PPC_ID_SUBFx:
+ case PPC_ID_SUBFCx:
+ case PPC_ID_SUBFEx:
+ case PPC_ID_SUBFMEx:
+ case PPC_ID_SUBFZEx:
+ if (new_instruction.flags.oe)
+ complain = false;
+ break;
+
+ // capstone doesn't realize these have rc
+ case PPC_ID_MTFSB0x:
+ case PPC_ID_MTFSB1x:
+ if (new_instruction.flags.rc)
+ complain = false;
+ break;
+
+ // capstone doesn't recognize op in DCI, ICI
+ case PPC_ID_DCI:
+ case PPC_ID_ICI:
+ if ((i & 0x01e00000) != 0)
+ complain = false;
+ break;
+
+ // capstone doesn't recognize these
+ case PPC_ID_AV_BCDADD:
+ case PPC_ID_AV_BCDSUB:
+ complain = false;
+ break;
+
+ // capstone has the wrong opcode: 0x18c instead of 0x18d
+ case PPC_ID_ICBLQ:
+ if ((i & 0x1) != 0)
+ complain = false;
+ break;
+
+ case PPC_ID_SLBMFEV:
+ // v3.0B includes L bit, capstone still using V2.07 form
+ // which doesn't have it
+ if (((i >> 16) & 0x1) == 1)
+ complain = false;
+ break;
+
+ case PPC_ID_DCBFEP:
+ // capstone doesn't recognize L!=0
+ if (((i >> 21) & 0x3) != 0)
+ complain = false;
+
+ break;
+
+ default:
+ ;
+ }
+
+ if (complain)
+ printf("new succeeded but capstone failed for %08x (%s)\n", i, GetMnemonic(&new_instruction));
+
+
+ }
+
+ continue;
+ }
+
+ if (cs_error)
+ {
+ continue;
+ }
+
+ const char* new_mnem = GetMnemonic(&new_instruction);
+ if (!new_mnem)
+ {
+ printf("no mnem for %08x (capstone %s)\n", i, cs_instruction->mnemonic);
+ cs_free(cs_instruction, 1);
+ continue;
+ }
+
+ if (strcmp(cs_instruction->mnemonic, new_mnem))
+ {
+ bool complain = true;
+
+ switch (new_instruction.id)
+ {
+ case PPC_ID_BCCTRx:
+ {
+ uint32_t bo = new_instruction.operands[0].uimm;
+ if ((bo & 0x4) == 0)
+ complain = false;
+
+ // "always branch" is 1z1zz, but
+ // capstone disassembles it as "bdnzctr"?
+ if ((bo & 0x14) == 0x14)
+ complain = false;
+
+ break;
+ }
+
+ case PPC_ID_BCLRx:
+ {
+ uint32_t bo = new_instruction.operands[0].uimm;
+
+ // "always branch" is 1z1zz, but
+ // capstone disassembles it as "bdnzlr"?
+ if ((bo & 0x14) == 0x14)
+ complain = false;
+
+ break;
+ }
+
+ // capstone disassembles this as just "cntlz"
+ case PPC_ID_CNTLZWx:
+ complain = false;
+ break;
+
+ // capstone disassembles pseudo-ops for RLWINM
+ // differently from RLWINM. for some reason
+ case PPC_ID_SLWIx:
+ if (new_instruction.flags.rc && !strcmp(cs_instruction->mnemonic, "rotlwi."))
+ complain = false;
+
+ // intentional fallthrough
+ case PPC_ID_SRWIx:
+ if (new_instruction.flags.rc && !strcmp(cs_instruction->mnemonic, "rlwinm."))
+ complain = false;
+
+ break;
+
+ // likewise for RLDICR vs RLDICR.
+ case PPC_ID_SLDIx:
+ if (new_instruction.flags.rc && !strcmp(cs_instruction->mnemonic, "rldicr."))
+ complain = false;
+
+ break;
+
+ // capstone doesn't seem to recognize CLRRWI
+ case PPC_ID_CLRRWIx:
+ complain = false;
+ break;
+
+ case PPC_ID_MFSPR:
+ complain = !strncmp(cs_instruction->mnemonic, "mf", 3);
+ break;
+
+ case PPC_ID_MTSPR:
+ complain = !strncmp(cs_instruction->mnemonic, "mt", 3);
+ break;
+
+ default:
+ ;
+ }
+
+ if (complain)
+ {
+ printf("different mnemonics for %08x! CS: %s NEW: %s\n",
+ i, cs_instruction->mnemonic, new_mnem);
+
+ cs_free(cs_instruction, 1);
+ continue;
+ }
+ }
+
+ cs_ppc* capstone_ppc = &cs_instruction->detail->ppc;
+ switch (new_instruction.id)
+ {
+ case PPC_ID_BCx:
+ {
+ OperandsList bcx;
+ FillBcxOperands(&bcx, &new_instruction);
+
+ uint32_t bo = new_instruction.operands[0].uimm;
+
+ switch (bo & 0x1e)
+ {
+ case 0:
+ case 2:
+ case 8:
+ case 10:
+ if (!(bcx_equal(handle, capstone_ppc, &new_instruction, &bcx, ADDRESS)))
+ {
+ printf("bcx different for %08x (new %s/cs %s %s)!\n",
+ i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str);
+ }
+ break;
+
+ case 4:
+ case 6:
+ case 12:
+ case 14:
+ if (!(bcx_2op_equal(handle, capstone_ppc, &new_instruction, &bcx, ADDRESS)))
+ {
+ printf("bcx 2op different for %08x (new %s/cs %s %s)!\n",
+ i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str);
+ }
+ break;
+
+ case 16:
+ case 18:
+ case 20:
+ case 22:
+ case 24:
+ case 26:
+ case 28:
+ case 30:
+ if (!(bcx_1op_equal(handle, capstone_ppc, &new_instruction, &bcx, ADDRESS)))
+ {
+ printf("bcx simple different for %08x (new %s/cs %s %s)!\n",
+ i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str);
+ }
+ break;
+
+ default:
+ {
+ if (capstone_ppc->op_count != new_instruction.numOperands)
+ {
+ printf("bcx raw num ops different for %08x (new/cs %ld/%d)\n",
+ i, new_instruction.numOperands, capstone_ppc->op_count);
+ }
+
+ unsigned int j;
+ for (j = 0; j < new_instruction.numOperands; ++j)
+ {
+ cs_ppc_op* capstone_op = &(capstone_ppc->operands[j]);
+ Operand* new_op = &(new_instruction.operands[j]);
+
+ if (!ops_equal(handle, capstone_op, new_op))
+ {
+ printf("bcx raw op%d for %08x (new %s/cs %s %s)!\n",
+ j, i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str);
+ }
+
+ }
+
+ break;
+ }
+ }
+
+ cs_free(cs_instruction, 1);
+ continue;
+ }
+
+ case PPC_ID_BCCTRx:
+ {
+ OperandsList bcctrx;
+ FillBcctrxOperands(&bcctrx, &new_instruction);
+
+ uint32_t bo = new_instruction.operands[0].uimm;
+
+ switch (bo & 0x1e)
+ {
+ case 4:
+ case 6:
+ case 12:
+ case 14:
+ if (!(bcregx2_equal(handle, capstone_ppc, &new_instruction, &bcctrx)))
+ {
+ printf("bcctrx not equal for %08x (new/cs %s/%s %s)\n",
+ i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str);
+ }
+
+ break;
+
+
+ default:
+ {
+ // invalid for BCCTRx
+ if ((bo & 0x4) == 0)
+ break;
+
+ // capstone's "branch always" (BO: 1z1zz) is just
+ // flat out wrong?
+ if ((bo & 0x14) == 0x14)
+ break;
+
+ if (capstone_ppc->op_count != new_instruction.numOperands)
+ {
+ printf("bcctrx raw num ops different for %08x (new/cs %ld/%d)\n",
+ i, new_instruction.numOperands, capstone_ppc->op_count);
+ }
+
+ unsigned int j;
+ for (j = 0; j < new_instruction.numOperands; ++j)
+ {
+ cs_ppc_op* capstone_op = &(capstone_ppc->operands[j]);
+ Operand* new_op = &(new_instruction.operands[j]);
+
+ if (!ops_equal(handle, capstone_op, new_op))
+ {
+ printf("bcctrx raw op%d for %08x (new %s/cs %s %s)!\n",
+ j, i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str);
+ }
+
+ }
+ }
+ }
+
+ cs_free(cs_instruction, 1);
+ continue;
+ }
+
+ case PPC_ID_BCLRx:
+ {
+ OperandsList bclrx;
+ FillBclrxOperands(&bclrx, &new_instruction);
+
+ uint32_t bo = new_instruction.operands[0].uimm;
+
+ switch (bo & 0x1e)
+ {
+ case 0:
+ case 2:
+ case 8:
+ case 10:
+ if (!(bcregx1_equal(handle, capstone_ppc, &new_instruction, &bclrx)))
+ {
+ printf("bcx different for %08x (new %s/cs %s %s)!\n",
+ i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str);
+ }
+ break;
+
+ case 4:
+ case 6:
+ case 12:
+ case 14:
+ if (!(bcregx2_equal(handle, capstone_ppc, &new_instruction, &bclrx)))
+ {
+ printf("bclrx not equal for %08x (new/cs %s/%s %s)\n",
+ i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str);
+ }
+
+ break;
+
+ case 16:
+ case 18:
+ case 24:
+ case 26:
+ if (!(bcregx3_equal(handle, capstone_ppc, &new_instruction, &bclrx)))
+ {
+ printf("bclrx not equal for %08x (new/cs %s/%s %s)\n",
+ i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str);
+ }
+
+ break;
+
+ default:
+ // capstone's "branch always" is just flat out wrong?
+ if ((bo & 0x14) == 0x14)
+ break;
+
+ if (capstone_ppc->op_count != new_instruction.numOperands)
+ {
+ printf("bclrx raw num ops different for %08x (new/cs %ld/%d)\n",
+ i, new_instruction.numOperands, capstone_ppc->op_count);
+ }
+
+ unsigned int j;
+ for (j = 0; j < new_instruction.numOperands; ++j)
+ {
+ cs_ppc_op* capstone_op = &(capstone_ppc->operands[j]);
+ Operand* new_op = &(new_instruction.operands[j]);
+
+ if (!ops_equal(handle, capstone_op, new_op))
+ {
+ printf("bclrx raw op%d for %08x (new %s/cs %s %s)!\n",
+ j, i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str);
+ }
+
+ }
+ }
+
+ cs_free(cs_instruction, 1);
+ continue;
+ }
+
+ default:
+ ;
+ }
+
+ if (capstone_ppc->op_count != new_instruction.numOperands)
+ {
+ bool complain = true;
+
+ switch (new_instruction.id)
+ {
+ // capstone seems to think it only has one
+ // operand (despite printing 2?)
+ case PPC_ID_MFOCRF:
+ case PPC_ID_MTOCRF:
+ complain = false;
+ break;
+
+ // capstone doesn't recognize the 0/1 operand it seems
+ case PPC_ID_VSX_XXSPLTD:
+ complain = false;
+ break;
+
+ case PPC_ID_SLWIx:
+ case PPC_ID_SRWIx:
+ if (new_instruction.id == PPC_ID_SLWIx && new_instruction.flags.rc && !strcmp(cs_instruction->mnemonic, "rotlwi."))
+ complain = false;
+
+ if (new_instruction.flags.rc && !strcmp(cs_instruction->mnemonic, "rlwinm."))
+ complain = false;
+
+ break;
+
+ case PPC_ID_CLRRWIx:
+ complain = false;
+ break;
+
+ // despite printing 3 operands, capstone only thinks there
+ // are 2?
+ case PPC_ID_SLDIx:
+ complain = false;
+ break;
+
+ // capstone doesn't recognize rS?
+ case PPC_ID_TLBIE:
+ complain = false;
+ break;
+
+ // we treat "MFSPR" and "MF<some register>" the same,
+ // which have different number of arguments
+ // (MFSPR rD, UIMM vs. MFxxx rD)
+ case PPC_ID_MFSPR:
+ complain = false;
+ break;
+
+ // we treat "MTSPR" and "MT<some register>" the same,
+ // which have different number of arguments
+ // (MTSPR UIMM, rS vs. MTxxx rS)
+ case PPC_ID_MTSPR:
+ complain = false;
+ break;
+
+ // capstone treats DCCCI/ICCCI as <op> r0, r0?
+ case PPC_ID_DCCCI:
+ case PPC_ID_ICCCI:
+ complain = false;
+ break;
+
+ // we unconditionally use cr0 and only omit it
+ // in disassembly
+ case PPC_ID_CMPD:
+ case PPC_ID_CMPDI:
+ case PPC_ID_CMPLD:
+ case PPC_ID_CMPLDI:
+ case PPC_ID_CMPLW:
+ case PPC_ID_CMPLWI:
+ case PPC_ID_CMPW:
+ case PPC_ID_CMPWI:
+ complain = false;
+ break;
+
+ // these seem to treat bit 10 as an operand, when
+ // v3.0B requires it as a constant 1 in decoding
+ case PPC_ID_COPY:
+ case PPC_ID_PASTE:
+ complain = false;
+ break;
+
+ default:
+ complain = true;
+ }
+
+ if (complain)
+ {
+ printf("different number of operands for %08x (%s)! CS %d NEW %ld [%s] \n",
+ i, new_mnem, capstone_ppc->op_count, new_instruction.numOperands,
+ cs_instruction->op_str);
+ }
+
+ // we unconditionally finish here since it's not super
+ // clear which operands we should compare to which
+ cs_free(cs_instruction, 1);
+ continue;
+ }
+
+ unsigned int j;
+ for (j = 0; j < new_instruction.numOperands; ++j)
+ {
+ cs_ppc_op* capstone_op = &(capstone_ppc->operands[j]);
+ Operand* new_op = &(new_instruction.operands[j]);
+
+ switch (new_instruction.id)
+ {
+ // things we sign extend to 64-bit but capstone
+ // doesn't
+ case PPC_ID_TDEQI:
+ case PPC_ID_TDGTI:
+ case PPC_ID_TDLGTI:
+ case PPC_ID_TDLLTI:
+ case PPC_ID_TDLTI:
+ case PPC_ID_TDNEI:
+ case PPC_ID_TDUI:
+ case PPC_ID_TWEQI:
+ case PPC_ID_TWGTI:
+ case PPC_ID_TWGEI:
+ case PPC_ID_TWLEI:
+ case PPC_ID_TWLLEI:
+ case PPC_ID_TWLGTI:
+ case PPC_ID_TWLLTI:
+ case PPC_ID_TWLTI:
+ case PPC_ID_TWNEI:
+ case PPC_ID_TWUI:
+ case PPC_ID_LI:
+ case PPC_ID_LIS:
+ if (j == 1) continue;
+ break;
+
+ // things we sign extend to 64-bit but capstone
+ // doesn't
+ case PPC_ID_TDI:
+ case PPC_ID_TWI:
+ case PPC_ID_MULLI:
+ case PPC_ID_SUBFIC:
+ case PPC_ID_ADDI:
+ case PPC_ID_ADDICx:
+ case PPC_ID_ADDIS:
+ case PPC_ID_TABORTDCI:
+ case PPC_ID_TABORTWCI:
+ if (j == 2) continue;
+ break;
+
+ // capstone sign extends the immediate for some
+ // reason
+ case PPC_ID_Bx:
+ continue;
+
+ // capstone doesn't sign-extend these imms when
+ // it should; we also unconditionally decode cr0
+ case PPC_ID_CMPDI:
+ case PPC_ID_CMPWI:
+ if (new_op->cls == PPC_OP_SIMM) continue;
+ if (new_op->cls == PPC_OP_REG_CRFD_IMPLY0 && new_op->reg == NUPPC_REG_CRF0) continue;
+ break;
+
+ // we unconditionally decode cr0
+ case PPC_ID_CMPLDI:
+ case PPC_ID_CMPLWI:
+ if (new_op->cls == PPC_OP_REG_CRFD_IMPLY0 && new_op->reg == NUPPC_REG_CRF0) continue;
+ break;
+
+ // capstone makes operand 3 a register for some
+ // reason
+ case PPC_ID_ISEL:
+ if (j == 3) continue;
+ break;
+
+ // capstone doesn't add 0/1 operand
+ case PPC_ID_VSX_XXSPLTD:
+ if (j == 2) continue;
+ break;
+
+ // capstone sometimes uses RA instead of RA|0
+ case PPC_ID_LBZCIX:
+ case PPC_ID_LDCIX:
+ case PPC_ID_LHZCIX:
+ case PPC_ID_LWZCIX:
+ case PPC_ID_STBCIX:
+ case PPC_ID_STDCIX:
+ case PPC_ID_STHCIX:
+ case PPC_ID_STWCIX:
+ if (j == 1)
+ {
+ if (new_op->cls == PPC_OP_UIMM && new_op->uimm == 0 && capstone_op->type == PPC_OP_REG && capstone_op->reg == PPC_REG_R0)
+ continue;
+ }
+ break;
+
+ // capstone treats these as setting a CR bit (ie cr4+eq), but
+ // these instructions clear the rest of the CR field, so it
+ // should really be a CR register (ie cr4)
+ case PPC_ID_CMPEQB:
+ case PPC_ID_CMPRB:
+ if (j == 0)
+ continue;
+
+ break;
+
+ // capstone seems to swap the "dc" and "dm" bits
+ case PPC_ID_VSX_XVTSTDCDP:
+ case PPC_ID_VSX_XVTSTDCSP:
+ if (j == 2)
+ continue;
+
+ break;
+
+ // capstone thinks this is a floating point register
+ // (but it could be the weird "altivec/floating point
+ // registers and vsx registers are 2 sides of the same
+ // coin" thing)
+ case PPC_ID_VSX_XSIEXPQP:
+ if (j == 2)
+ continue;
+ break;
+
+ default: ;
+ }
+
+ if (!ops_equal(handle, capstone_op, new_op))
+ {
+ printf("operand %d differs for %08x (%s)!\n",
+ j, i, new_mnem);
+
+ break;
+ }
+ }
+
+ cs_free(cs_instruction, 1);
+ }
+
+ return 0;
+}
diff --git a/arch/powerpc/decode/decode.c b/arch/powerpc/decode/decode.c
new file mode 100644
index 00000000..fc5dc9d5
--- /dev/null
+++ b/arch/powerpc/decode/decode.c
@@ -0,0 +1,6110 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "decode.h"
+#include "priv.h"
+
+// Documentation:
+// * [ProgrammingEnvironments32]: "Programming Environments Manual for 32-bit
+// Implementations of the PowerPC^TM Architecture" by Freescale/NXP
+//
+
+size_t
+GetInstructionLength(const uint8_t* data, size_t data_length, uint32_t decodeFlags)
+{
+ size_t instruction_length = 0;
+ if ((decodeFlags & DECODE_FLAGS_VLE) != 0)
+ {
+ instruction_length = VleGetInstructionLength(data, data_length, decodeFlags);
+ }
+ else
+ {
+ // All other powerpc flavors have fixed 32-bit instructions
+ instruction_length = 4;
+ }
+
+ if (data_length < instruction_length)
+ return 0;
+
+ return instruction_length;
+}
+
+static InstructionId DecodeAltivec0x04(uint32_t word32, uint32_t decodeFlags)
+{
+ uint32_t subop = word32 & 0x3f;
+
+ uint32_t a = GetA(word32);
+ uint32_t b = GetB(word32);
+ uint32_t d = GetD(word32);
+
+ switch (subop)
+ {
+ case 0x20:
+ return PPC_ID_AV_VMHADDSHS;
+
+ case 0x21:
+ return PPC_ID_AV_VMHRADDSHS;
+
+ case 0x22:
+ return PPC_ID_AV_VMLADDUHM;
+
+ case 0x24:
+ return PPC_ID_AV_VMSUMUBM;
+
+ case 0x25:
+ return PPC_ID_AV_VMSUMMBM;
+
+ case 0x26:
+ return PPC_ID_AV_VMSUMUHM;
+
+ case 0x27:
+ return PPC_ID_AV_VMSUMUHS;
+
+ case 0x28:
+ return PPC_ID_AV_VMSUMSHM;
+
+ case 0x29:
+ return PPC_ID_AV_VMSUMSHS;
+
+ case 0x2a:
+ return PPC_ID_AV_VSEL;
+
+ case 0x2b:
+ return PPC_ID_AV_VPERM;
+
+ case 0x2c:
+ if ((word32 & 0x400) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VSLDOI;
+
+ case 0x2d:
+ return PPC_ID_AV_VPERMXOR;
+
+ case 0x2e:
+ return PPC_ID_AV_VMADDFP;
+
+ case 0x2f:
+ return PPC_ID_AV_VNMSUBFP;
+
+ case 0x30:
+ return PPC_ID_AV_MADDHD;
+
+ case 0x31:
+ return PPC_ID_AV_MADDHDU;
+
+ case 0x33:
+ return PPC_ID_AV_MADDLD;
+
+ case 0x3b:
+ return PPC_ID_AV_VPERMR;
+
+ case 0x3c:
+ return PPC_ID_AV_VADDEUQM;
+
+ case 0x3d:
+ return PPC_ID_AV_VADDECUQ;
+
+ case 0x3e:
+ return PPC_ID_AV_VSUBEUQM;
+
+ case 0x3f:
+ return PPC_ID_AV_VSUBECUQ;
+
+ default:
+ ;
+ }
+
+ subop = word32 & 0x7ff;
+ switch (subop)
+ {
+ case 0x000:
+ return PPC_ID_AV_VADDUBM;
+
+ case 0x001:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VMUL10CUQ;
+
+ case 0x002:
+ return PPC_ID_AV_VMAXUB;
+
+ case 0x004:
+ return PPC_ID_AV_VRLB;
+
+
+ case 0x006:
+ case 0x406:
+ return PPC_ID_AV_VCMPEQUBx;
+
+ case 0x007:
+ case 0x407:
+ return PPC_ID_AV_VCMPNEBx;
+
+ case 0x008:
+ return PPC_ID_AV_VMULOUB;
+
+ case 0x00a:
+ return PPC_ID_AV_VADDFP;
+
+ case 0x00c:
+ return PPC_ID_AV_VMRGHB;
+
+ case 0x00e:
+ return PPC_ID_AV_VPKUHUM;
+
+ case 0x040:
+ return PPC_ID_AV_VADDUHM;
+
+ case 0x041:
+ return PPC_ID_AV_VMUL10ECUQ;
+
+ case 0x042:
+ return PPC_ID_AV_VMAXUH;
+
+ case 0x044:
+ return PPC_ID_AV_VRLH;
+
+
+ case 0x046:
+ case 0x446:
+ return PPC_ID_AV_VCMPEQUHx;
+
+ case 0x047:
+ case 0x447:
+ return PPC_ID_AV_VCMPNEHx;
+
+ case 0x048:
+ return PPC_ID_AV_VMULOUH;
+
+ case 0x04a:
+ return PPC_ID_AV_VSUBFP;
+
+ case 0x04c:
+ return PPC_ID_AV_VMRGHH;
+
+ case 0x04e:
+ return PPC_ID_AV_VPKUWUM;
+
+ case 0x080:
+ return PPC_ID_AV_VADDUWM;
+
+ case 0x082:
+ return PPC_ID_AV_VMAXUW;
+
+ case 0x084:
+ return PPC_ID_AV_VRLW;
+
+ case 0x085:
+ return PPC_ID_AV_VRLWMI;
+
+ case 0x086:
+ case 0x486:
+ return PPC_ID_AV_VCMPEQUWx;
+
+ case 0x087:
+ case 0x487:
+ return PPC_ID_AV_VCMPNEWx;
+
+ case 0x88:
+ return PPC_ID_AV_VMULOUW;
+
+ case 0x89:
+ return PPC_ID_AV_VMULUWM;
+
+ case 0x08c:
+ return PPC_ID_AV_VMRGHW;
+
+ case 0x08e:
+ return PPC_ID_AV_VPKUHUS;
+
+ case 0x0c0:
+ return PPC_ID_AV_VADDUDM;
+
+ case 0x0c2:
+ return PPC_ID_AV_VMAXUD;
+
+ case 0x0c4:
+ return PPC_ID_AV_VRLD;
+
+ case 0x0c5:
+ return PPC_ID_AV_VRLDMI;
+
+ case 0x0c6:
+ case 0x4c6:
+ return PPC_ID_AV_VCMPEQFPx;
+
+ case 0x0c7:
+ case 0x4c7:
+ return PPC_ID_AV_VCMPEQUDx;
+
+ case 0x0ce:
+ return PPC_ID_AV_VPKUWUS;
+
+ case 0x100:
+ return PPC_ID_AV_VADDUQM;
+
+ case 0x102:
+ return PPC_ID_AV_VMAXSB;
+
+ case 0x104:
+ return PPC_ID_AV_VSLB;
+
+ case 0x107:
+ case 0x507:
+ return PPC_ID_AV_VCMPNEZBx;
+
+ case 0x108:
+ return PPC_ID_AV_VMULOSB;
+
+ case 0x10a:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VREFP;
+
+ case 0x10c:
+ return PPC_ID_AV_VMRGLB;
+
+ case 0x10e:
+ return PPC_ID_AV_VPKSHUS;
+
+ case 0x140:
+ return PPC_ID_AV_VADDCUQ;
+
+ case 0x142:
+ return PPC_ID_AV_VMAXSH;
+
+ case 0x144:
+ return PPC_ID_AV_VSLH;
+
+ case 0x147:
+ case 0x547:
+ return PPC_ID_AV_VCMPNEZHx;
+
+ case 0x148:
+ return PPC_ID_AV_VMULOSH;
+
+ case 0x14a:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VRSQRTEFP;
+
+ case 0x14c:
+ return PPC_ID_AV_VMRGLH;
+
+ case 0x14e:
+ return PPC_ID_AV_VPKSWUS;
+
+ case 0x180:
+ return PPC_ID_AV_VADDCUW;
+
+ case 0x182:
+ return PPC_ID_AV_VMAXSW;
+
+ case 0x184:
+ return PPC_ID_AV_VSLW;
+
+ case 0x185:
+ return PPC_ID_AV_VRLWNM;
+
+ case 0x187:
+ case 0x587:
+ return PPC_ID_AV_VCMPNEZWx;
+
+ case 0x188:
+ return PPC_ID_AV_VMULOSW;
+
+ case 0x18a:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VEXPTEFP;
+
+ case 0x18c:
+ return PPC_ID_AV_VMRGLW;
+
+ case 0x18e:
+ return PPC_ID_AV_VPKSHSS;
+
+ case 0x1c2:
+ return PPC_ID_AV_VMAXSD;
+
+ case 0x1c4:
+ return PPC_ID_AV_VSL;
+
+ case 0x1c5:
+ return PPC_ID_AV_VRLDNM;
+
+ case 0x1c6:
+ case 0x5c6:
+ return PPC_ID_AV_VCMPGEFPx;
+
+ case 0x1ca:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VLOGEFP;
+
+ case 0x1ce:
+ return PPC_ID_AV_VPKSWSS;
+
+ case 0x200:
+ return PPC_ID_AV_VADDUBS;
+
+ case 0x201:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VMUL10UQ;
+
+ case 0x202:
+ return PPC_ID_AV_VMINUB;
+
+ case 0x204:
+ return PPC_ID_AV_VSRB;
+
+
+ case 0x206:
+ case 0x606:
+ return PPC_ID_AV_VCMPGTUBx;
+
+ case 0x208:
+ return PPC_ID_AV_VMULEUB;
+
+ case 0x20a:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VRFIN;
+
+ case 0x20c:
+ return PPC_ID_AV_VSPLTB;
+
+ case 0x20d:
+ if ((word32 & 0x00100000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VEXTRACTUB;
+
+ case 0x20e:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VUPKHSB;
+
+ case 0x240:
+ return PPC_ID_AV_VADDUHS;
+
+ case 0x241:
+ return PPC_ID_AV_VMUL10EUQ;
+
+ case 0x242:
+ return PPC_ID_AV_VMINUH;
+
+ case 0x244:
+ return PPC_ID_AV_VSRH;
+
+ case 0x246:
+ case 0x646:
+ return PPC_ID_AV_VCMPGTUHx;
+
+ case 0x248:
+ return PPC_ID_AV_VMULEUH;
+
+ case 0x24a:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VRFIZ;
+
+ case 0x24c:
+ return PPC_ID_AV_VSPLTH;
+
+ case 0x24d:
+ if ((word32 & 0x00100000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VEXTRACTUH;
+
+ case 0x24e:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VUPKHSH;
+
+ case 0x280:
+ return PPC_ID_AV_VADDUWS;
+
+ case 0x282:
+ return PPC_ID_AV_VMINUW;
+
+ case 0x284:
+ return PPC_ID_AV_VSRW;
+
+ case 0x286:
+ case 0x686:
+ return PPC_ID_AV_VCMPGTUWx;
+
+ case 0x288:
+ return PPC_ID_AV_VMULEUW;
+
+ case 0x28a:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VRFIP;
+
+ case 0x28c:
+ return PPC_ID_AV_VSPLTW;
+
+ case 0x28d:
+ if ((word32 & 0x00100000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VEXTRACTUW;
+
+ case 0x28e:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VUPKLSB;
+
+ case 0x2c2:
+ return PPC_ID_AV_VMINUD;
+
+ case 0x2c4:
+ return PPC_ID_AV_VSR;
+
+ case 0x2c6:
+ case 0x6c6:
+ return PPC_ID_AV_VCMPGTFPx;
+
+ case 0x2c7:
+ case 0x6c7:
+ return PPC_ID_AV_VCMPGTUDx;
+
+ case 0x2ca:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VRFIM;
+
+ case 0x2cd:
+ if ((word32 & 0x00100000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VEXTRACTD;
+
+ case 0x2ce:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VUPKLSH;
+
+ case 0x300:
+ return PPC_ID_AV_VADDSBS;
+
+ case 0x302:
+ return PPC_ID_AV_VMINSB;
+
+ case 0x304:
+ return PPC_ID_AV_VSRAB;
+
+ case 0x306:
+ case 0x706:
+ return PPC_ID_AV_VCMPGTSBx;
+
+ case 0x308:
+ return PPC_ID_AV_VMULESB;
+
+ case 0x30a:
+ return PPC_ID_AV_VCFUX;
+
+ case 0x30c:
+ if ((b) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VSPLTISB;
+
+ case 0x30d:
+ if ((word32 & 0x00100000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VINSERTB;
+
+ case 0x30e:
+ return PPC_ID_AV_VPKPX;
+
+ case 0x340:
+ return PPC_ID_AV_VADDSHS;
+
+ case 0x341:
+ return PPC_ID_AV_BCDCPSGN;
+
+ case 0x342:
+ return PPC_ID_AV_VMINSH;
+
+ case 0x344:
+ return PPC_ID_AV_VSRAH;
+
+ case 0x346:
+ case 0x746:
+ return PPC_ID_AV_VCMPGTSHx;
+
+ case 0x348:
+ return PPC_ID_AV_VMULESH;
+
+ case 0x34a:
+ return PPC_ID_AV_VCFSX;
+
+ case 0x34c:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VSPLTISH;
+
+ case 0x34d:
+ if ((word32 & 0x00100000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VINSERTH;
+
+ case 0x34e:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VUPKHPX;
+
+ case 0x380:
+ return PPC_ID_AV_VADDSWS;
+
+ case 0x382:
+ return PPC_ID_AV_VMINSW;
+
+ case 0x384:
+ return PPC_ID_AV_VSRAW;
+
+ case 0x386:
+ case 0x786:
+ return PPC_ID_AV_VCMPGTSWx;
+
+ case 0x388:
+ return PPC_ID_AV_VMULESW;
+
+ case 0x38a:
+ return PPC_ID_AV_VCTUXS;
+
+ case 0x38c:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VSPLTISW;
+
+ case 0x38d:
+ if ((word32 & 0x00100000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VINSERTW;
+
+ case 0x3c2:
+ return PPC_ID_AV_VMINSD;
+
+ case 0x3c4:
+ return PPC_ID_AV_VSRAD;
+
+ case 0x3c6:
+ case 0x7c6:
+ return PPC_ID_AV_VCMPBFPx;
+
+ case 0x3c7:
+ case 0x7c7:
+ return PPC_ID_AV_VCMPGTSDx;
+
+ case 0x3ca:
+ return PPC_ID_AV_VCTSXS;
+
+ case 0x3cd:
+ if ((word32 & 0x00100000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VINSERTD;
+
+ case 0x3ce:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VUPKLPX;
+
+ case 0x400:
+ return PPC_ID_AV_VSUBUBM;
+
+ case 0x401:
+ case 0x601:
+ return PPC_ID_AV_BCDADD;
+
+ case 0x402:
+ return PPC_ID_AV_VAVGUB;
+
+ case 0x403:
+ return PPC_ID_AV_VABSDUB;
+
+ case 0x404:
+ return PPC_ID_AV_VAND;
+
+ case 0x408:
+ return PPC_ID_AV_VPMSUMB;
+
+ case 0x40a:
+ return PPC_ID_AV_VMAXFP;
+
+ case 0x40c:
+ return PPC_ID_AV_VSLO;
+
+ case 0x440:
+ return PPC_ID_AV_VSUBUHM;
+
+ case 0x441:
+ case 0x641:
+ return PPC_ID_AV_BCDSUB;
+
+ case 0x442:
+ return PPC_ID_AV_VAVGUH;
+
+ case 0x443:
+ return PPC_ID_AV_VABSDUH;
+
+ case 0x444:
+ return PPC_ID_AV_VANDC;
+
+ case 0x448:
+ return PPC_ID_AV_VPMSUMH;
+
+ case 0x44a:
+ return PPC_ID_AV_VMINFP;
+
+ case 0x44c:
+ return PPC_ID_AV_VSRO;
+
+ case 0x44e:
+ return PPC_ID_AV_VPKUDUM;
+
+ case 0x480:
+ return PPC_ID_AV_VSUBUWM;
+
+ case 0x481:
+ return PPC_ID_AV_BCDUS;
+
+ case 0x482:
+ return PPC_ID_AV_VAVGUW;
+
+ case 0x483:
+ return PPC_ID_AV_VABSDUW;
+
+ case 0x484:
+ if (a == b)
+ return PPC_ID_AV_VMR;
+ else
+ return PPC_ID_AV_VOR;
+
+ case 0x488:
+ return PPC_ID_AV_VPMSUMW;
+
+ case 0x4c0:
+ return PPC_ID_AV_VSUBUDM;
+
+ case 0x4c1:
+ case 0x6c1:
+ return PPC_ID_AV_BCDS;
+
+ case 0x4c4:
+ return PPC_ID_AV_VXOR;
+
+ case 0x4c8:
+ return PPC_ID_AV_VPMSUMD;
+
+ case 0x4ce:
+ return PPC_ID_AV_VPKUDUS;
+
+ case 0x500:
+ return PPC_ID_AV_VSUBUQM;
+
+ case 0x501:
+ case 0x701:
+ return PPC_ID_AV_BCDTRUNC;
+
+ case 0x502:
+ return PPC_ID_AV_VAVGSB;
+
+ case 0x504:
+ if (a == b)
+ return PPC_ID_AV_VNOT;
+ else
+ return PPC_ID_AV_VNOR;
+
+ case 0x508:
+ return PPC_ID_AV_VCIPHER;
+
+ case 0x509:
+ return PPC_ID_AV_VCIPHERLAST;
+
+ case 0x50c:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VGBBD;
+
+ case 0x540:
+ return PPC_ID_AV_VSUBCUQ;
+
+ case 0x541:
+ return PPC_ID_AV_BCDUTRUNC;
+
+ case 0x542:
+ return PPC_ID_AV_VAVGSH;
+
+ case 0x544:
+ return PPC_ID_AV_VORC;
+
+ case 0x548:
+ return PPC_ID_AV_VNCIPHER;
+
+ case 0x549:
+ return PPC_ID_AV_VNCIPHERLAST;
+
+ case 0x54c:
+ return PPC_ID_AV_VBPERMQ;
+
+ case 0x54e:
+ return PPC_ID_AV_VPKSDUS;
+
+ case 0x580:
+ return PPC_ID_AV_VSUBCUW;
+
+ case 0x581:
+ case 0x781:
+ switch (a)
+ {
+ case 0x00:
+ if (subop == 0x581)
+ return PPC_ID_AV_BCDCTSQ;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x02:
+ return PPC_ID_AV_BCDCFSQ;
+
+ case 0x04:
+ return PPC_ID_AV_BCDCTZ;
+
+ case 0x05:
+ if (subop == 0x581)
+ return PPC_ID_AV_BCDCTN;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x06:
+ return PPC_ID_AV_BCDCFZ;
+
+ case 0x07:
+ return PPC_ID_AV_BCDCFN;
+
+ case 0x1f:
+ return PPC_ID_AV_BCDSETSGN;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+
+ case 0x582:
+ return PPC_ID_AV_VAVGSW;
+
+ case 0x584:
+ return PPC_ID_AV_VNAND;
+
+ case 0x5c1:
+ case 0x7c1:
+ return PPC_ID_AV_BCDSR;
+
+ case 0x5c4:
+ return PPC_ID_AV_VSLD;
+
+ case 0x5c8:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VSBOX;
+
+ case 0x5cc:
+ return PPC_ID_AV_VBPERMD;
+
+ case 0x5ce:
+ return PPC_ID_AV_VPKSDSS;
+
+ case 0x600:
+ return PPC_ID_AV_VSUBUBS;
+
+ case 0x602:
+ switch (a)
+ {
+ case 0x00:
+ return PPC_ID_AV_VCLZLSBB;
+
+ case 0x01:
+ return PPC_ID_AV_VCTZLSBB;
+
+ case 0x06:
+ return PPC_ID_AV_VNEGW;
+
+ case 0x07:
+ return PPC_ID_AV_VNEGD;
+
+ case 0x08:
+ return PPC_ID_AV_VPRTYBW;
+
+ case 0x09:
+ return PPC_ID_AV_VPRTYBD;
+
+ case 0x0a:
+ return PPC_ID_AV_VPRTYBQ;
+
+ case 0x10:
+ return PPC_ID_AV_VEXTSB2W;
+
+ case 0x11:
+ return PPC_ID_AV_VEXTSH2W;
+
+ case 0x18:
+ return PPC_ID_AV_VEXTSB2D;
+
+ case 0x19:
+ return PPC_ID_AV_VEXTSH2D;
+
+ case 0x1a:
+ return PPC_ID_AV_VEXTSW2D;
+
+ case 0x1c:
+ return PPC_ID_AV_VCTZB;
+
+ case 0x1d:
+ return PPC_ID_AV_VCTZH;
+
+ case 0x1e:
+ return PPC_ID_AV_VCTZW;
+
+ case 0x1f:
+ return PPC_ID_AV_VCTZD;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+
+ case 0x604:
+ if ((a != 0) || (b != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_MFVSCR;
+
+ case 0x60d:
+ return PPC_ID_AV_VEXTUBLX;
+
+ case 0x608:
+ return PPC_ID_AV_VSUM4UBS;
+
+ case 0x640:
+ return PPC_ID_AV_VSUBUHS;
+
+ case 0x644:
+ if ((d != 0) || (a != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_MTVSCR;
+
+ case 0x648:
+ return PPC_ID_AV_VSUM4SHS;
+
+ case 0x64d:
+ return PPC_ID_AV_VEXTUHLX;
+
+ case 0x64e:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VUPKHSW;
+
+ case 0x680:
+ return PPC_ID_AV_VSUBUWS;
+
+ case 0x682:
+ return PPC_ID_AV_VSHASIGMAW;
+
+ case 0x684:
+ return PPC_ID_AV_VEQV;
+
+ case 0x688:
+ return PPC_ID_AV_VSUM2SWS;
+
+ case 0x68c:
+ return PPC_ID_AV_VMRGOW;
+
+ case 0x68d:
+ return PPC_ID_AV_VEXTUWLX;
+
+ case 0x6c2:
+ return PPC_ID_AV_VSHASIGMAD;
+
+ case 0x6c4:
+ return PPC_ID_AV_VSRD;
+
+ case 0x6ce:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VUPKLSW;
+
+ case 0x700:
+ return PPC_ID_AV_VSUBSBS;
+
+ case 0x702:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VCLZB;
+
+ case 0x703:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VPOPCNTB;
+
+ case 0x704:
+ return PPC_ID_AV_VSRV;
+
+ case 0x708:
+ return PPC_ID_AV_VSUM4SBS;
+
+ case 0x70d:
+ return PPC_ID_AV_VEXTUBRX;
+
+ case 0x740:
+ return PPC_ID_AV_VSUBSHS;
+
+ case 0x742:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VCLZH;
+
+ case 0x743:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VPOPCNTH;
+
+ case 0x744:
+ return PPC_ID_AV_VSLV;
+
+ case 0x74d:
+ return PPC_ID_AV_VEXTUHRX;
+
+ case 0x780:
+ return PPC_ID_AV_VSUBSWS;
+
+ case 0x782:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VCLZW;
+
+ case 0x783:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VPOPCNTW;
+
+ case 0x788:
+ return PPC_ID_AV_VSUMSWS;
+
+ case 0x78c:
+ return PPC_ID_AV_VMRGEW;
+
+ case 0x78d:
+ return PPC_ID_AV_VEXTUWRX;
+
+ case 0x7c2:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VCLZD;
+
+ case 0x7c3:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_AV_VPOPCNTD;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+}
+
+static InstructionId DecodeSpe0x04(uint32_t word32, uint32_t decodeFlags)
+{
+ uint32_t a = GetA(word32);
+ uint32_t b = GetB(word32);
+ uint32_t subop = word32 & 0x7ff;
+
+ switch (subop)
+ {
+ case 512:
+ return PPC_ID_SPE_EVADDW;
+
+ case 514:
+ return PPC_ID_SPE_EVADDIW;
+
+ case 516:
+ return PPC_ID_SPE_EVSUBFW;
+
+ case 518:
+ return PPC_ID_SPE_EVSUBIFW;
+
+ case 520:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVABS;
+
+ case 521:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVNEG;
+
+ case 522:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVEXTSB;
+
+ case 523:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVEXTSH;
+
+ case 524:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVRNDW;
+
+ case 525:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVCNTLZW;
+
+ case 526:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVCNTLSW;
+
+ case 527:
+ return PPC_ID_SPE_BRINC;
+
+ case 529:
+ return PPC_ID_SPE_EVAND;
+
+ case 530:
+ return PPC_ID_SPE_EVANDC;
+
+ case 534:
+ return PPC_ID_SPE_EVXOR;
+
+ case 535:
+ if (a == b)
+ return PPC_ID_SPE_EVMR;
+ else
+ return PPC_ID_SPE_EVOR;
+
+ case 536:
+ if (a == b)
+ return PPC_ID_SPE_EVNOT;
+ else
+ return PPC_ID_SPE_EVNOR;
+
+ case 537:
+ return PPC_ID_SPE_EVEQV;
+
+ case 539:
+ return PPC_ID_SPE_EVORC;
+
+ case 542:
+ return PPC_ID_SPE_EVNAND;
+
+ case 544:
+ return PPC_ID_SPE_EVSRWU;
+
+ case 545:
+ return PPC_ID_SPE_EVSRWS;
+
+ case 546:
+ return PPC_ID_SPE_EVSRWIU;
+
+ case 547:
+ return PPC_ID_SPE_EVSRWIS;
+
+ case 548:
+ return PPC_ID_SPE_EVSLW;
+
+ case 550:
+ return PPC_ID_SPE_EVSLWI;
+
+ case 552:
+ return PPC_ID_SPE_EVRLW;
+
+ case 553:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVSPLATI;
+
+ case 554:
+ return PPC_ID_SPE_EVRLWI;
+
+ case 555:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVSPLATFI;
+
+ case 556:
+ return PPC_ID_SPE_EVMERGEHI;
+
+ case 557:
+ return PPC_ID_SPE_EVMERGELO;
+
+ case 558:
+ return PPC_ID_SPE_EVMERGEHILO;
+
+ case 559:
+ return PPC_ID_SPE_EVMERGELOHI;
+
+ case 560:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVCMPGTU;
+
+ case 561:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVCMPGTS;
+
+ case 562:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVCMPLTU;
+
+ case 563:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVCMPLTS;
+
+ case 564:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVCMPEQ;
+
+ case 632:
+ return PPC_ID_SPE_EVSEL;
+
+ case 633:
+ return PPC_ID_SPE_EVSEL;
+
+ case 634:
+ return PPC_ID_SPE_EVSEL;
+
+ case 635:
+ return PPC_ID_SPE_EVSEL;
+
+ case 636:
+ return PPC_ID_SPE_EVSEL;
+
+ case 637:
+ return PPC_ID_SPE_EVSEL;
+
+ case 638:
+ return PPC_ID_SPE_EVSEL;
+
+ case 639:
+ return PPC_ID_SPE_EVSEL;
+
+ case 640:
+ return PPC_ID_SPE_EVFSADD;
+
+ case 641:
+ return PPC_ID_SPE_EVFSSUB;
+
+ case 644:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSABS;
+
+ case 645:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSNABS;
+
+ case 646:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSNEG;
+
+ case 648:
+ return PPC_ID_SPE_EVFSMUL;
+
+ case 649:
+ return PPC_ID_SPE_EVFSDIV;
+
+ case 652:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSCMPGT;
+
+ case 653:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSCMPLT;
+
+ case 654:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSCMPEQ;
+
+ case 656:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSCFUI;
+
+ case 657:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSCFSI;
+
+ case 658:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSCFUF;
+
+ case 659:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSCFSF;
+
+ case 660:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSCTUI;
+
+ case 661:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSCTSI;
+
+ case 662:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSCTUF;
+
+ case 663:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSCTSF;
+
+ case 664:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSCTUIZ;
+
+ case 666:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSCTSIZ;
+
+ case 668:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSTSTGT;
+
+ case 669:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSTSTLT;
+
+ case 670:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVFSTSTEQ;
+
+ case 704:
+ return PPC_ID_SPE_EFSADD;
+
+ case 705:
+ return PPC_ID_SPE_EFSSUB;
+
+ case 708:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSABS;
+
+ case 709:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSNABS;
+
+ case 710:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSNEG;
+
+ case 712:
+ return PPC_ID_SPE_EFSMUL;
+
+ case 713:
+ return PPC_ID_SPE_EFSDIV;
+
+ case 716:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSCMPGT;
+
+ case 717:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSCMPLT;
+
+ case 718:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSCMPEQ;
+
+ case 719:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSCFD;
+
+ case 720:
+ return PPC_ID_SPE_EFSCFUI;
+
+ case 721:
+ return PPC_ID_SPE_EFSCFSI;
+
+ case 722:
+ return PPC_ID_SPE_EFSCFUF;
+
+ case 723:
+ return PPC_ID_SPE_EFSCFSF;
+
+ case 724:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSCTUI;
+
+ case 725:
+ return PPC_ID_SPE_EFSCTSI;
+
+ case 726:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSCTUF;
+
+ case 727:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSCTSF;
+
+ case 728:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSCTUIZ;
+
+ case 730:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSCTSIZ;
+
+ case 732:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSTSTGT;
+
+ case 733:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSTSTLT;
+
+ case 734:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFSTSTEQ;
+
+ case 736:
+ return PPC_ID_SPE_EFDADD;
+
+ case 737:
+ return PPC_ID_SPE_EFDSUB;
+
+ case 738:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCFUID;
+
+ case 739:
+ return PPC_ID_SPE_EFDCFSID;
+
+ case 740:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDABS;
+
+ case 741:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDNABS;
+
+ case 742:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDNEG;
+
+ case 744:
+ return PPC_ID_SPE_EFDMUL;
+
+ case 745:
+ return PPC_ID_SPE_EFDDIV;
+
+ case 746:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCTUIDZ;
+
+ case 747:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCTSIDZ;
+
+ case 748:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCMPGT;
+
+ case 749:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCMPLT;
+
+ case 750:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCMPEQ;
+
+ case 751:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCFS;
+
+ case 752:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCFUI;
+
+ case 753:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCFSI;
+
+ case 754:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCFUF;
+
+ case 755:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCFSF;
+
+ case 756:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCTUI;
+
+ case 757:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCTSI;
+
+ case 758:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCTUF;
+
+ case 759:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCTSF;
+
+ case 760:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCTUIZ;
+
+ case 762:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDCTSIZ;
+
+ case 764:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDTSTGT;
+
+ case 765:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDTSTLT;
+
+ case 766:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EFDTSTEQ;
+
+ case 768:
+ return PPC_ID_SPE_EVLDDX;
+
+ case 769:
+ return PPC_ID_SPE_EVLDD;
+
+ case 770:
+ return PPC_ID_SPE_EVLDWX;
+
+ case 771:
+ return PPC_ID_SPE_EVLDW;
+
+ case 772:
+ return PPC_ID_SPE_EVLDHX;
+
+ case 773:
+ return PPC_ID_SPE_EVLDH;
+
+ case 776:
+ return PPC_ID_SPE_EVLHHESPLATX;
+
+ case 777:
+ return PPC_ID_SPE_EVLHHESPLAT;
+
+ case 780:
+ return PPC_ID_SPE_EVLHHOUSPLATX;
+
+ case 781:
+ return PPC_ID_SPE_EVLHHOUSPLAT;
+
+ case 782:
+ return PPC_ID_SPE_EVLHHOSSPLATX;
+
+ case 783:
+ return PPC_ID_SPE_EVLHHOSSPLAT;
+
+ case 784:
+ return PPC_ID_SPE_EVLWHEX;
+
+ case 785:
+ return PPC_ID_SPE_EVLWHE;
+
+ case 788:
+ return PPC_ID_SPE_EVLWHOUX;
+
+ case 789:
+ return PPC_ID_SPE_EVLWHOU;
+
+ case 790:
+ return PPC_ID_SPE_EVLWHOSX;
+
+ case 791:
+ return PPC_ID_SPE_EVLWHOS;
+
+ case 792:
+ return PPC_ID_SPE_EVLWWSPLATX;
+
+ case 793:
+ return PPC_ID_SPE_EVLWWSPLAT;
+
+ case 796:
+ return PPC_ID_SPE_EVLWHSPLATX;
+
+ case 797:
+ return PPC_ID_SPE_EVLWHSPLAT;
+
+ case 800:
+ return PPC_ID_SPE_EVSTDDX;
+
+ case 801:
+ return PPC_ID_SPE_EVSTDD;
+
+ case 802:
+ return PPC_ID_SPE_EVSTDWX;
+
+ case 803:
+ return PPC_ID_SPE_EVSTDW;
+
+ case 804:
+ return PPC_ID_SPE_EVSTDHX;
+
+ case 805:
+ return PPC_ID_SPE_EVSTDH;
+
+ case 816:
+ return PPC_ID_SPE_EVSTWHEX;
+
+ case 817:
+ return PPC_ID_SPE_EVSTWHE;
+
+ case 820:
+ return PPC_ID_SPE_EVSTWHOX;
+
+ case 821:
+ return PPC_ID_SPE_EVSTWHO;
+
+ case 824:
+ return PPC_ID_SPE_EVSTWWEX;
+
+ case 825:
+ return PPC_ID_SPE_EVSTWWE;
+
+ case 828:
+ return PPC_ID_SPE_EVSTWWOX;
+
+ case 829:
+ return PPC_ID_SPE_EVSTWWO;
+
+ case 1027:
+ return PPC_ID_SPE_EVMHESSF;
+
+ case 1031:
+ return PPC_ID_SPE_EVMHOSSF;
+
+ case 1032:
+ return PPC_ID_SPE_EVMHEUMI;
+
+ case 1033:
+ return PPC_ID_SPE_EVMHESMI;
+
+ case 1035:
+ return PPC_ID_SPE_EVMHESMF;
+
+ case 1036:
+ return PPC_ID_SPE_EVMHOUMI;
+
+ case 1037:
+ return PPC_ID_SPE_EVMHOSMI;
+
+ case 1039:
+ return PPC_ID_SPE_EVMHOSMF;
+
+ case 1059:
+ return PPC_ID_SPE_EVMHESSFA;
+
+ case 1063:
+ return PPC_ID_SPE_EVMHOSSFA;
+
+ case 1064:
+ return PPC_ID_SPE_EVMHEUMIA;
+
+ case 1065:
+ return PPC_ID_SPE_EVMHESMIA;
+
+ case 1067:
+ return PPC_ID_SPE_EVMHESMFA;
+
+ case 1068:
+ return PPC_ID_SPE_EVMHOUMIA;
+
+ case 1069:
+ return PPC_ID_SPE_EVMHOSMIA;
+
+ case 1071:
+ return PPC_ID_SPE_EVMHOSMFA;
+
+ case 1095:
+ return PPC_ID_SPE_EVMWHSSF;
+
+ case 1096:
+ return PPC_ID_SPE_EVMWLUMI;
+
+ case 1100:
+ return PPC_ID_SPE_EVMWHUMI;
+
+ case 1101:
+ return PPC_ID_SPE_EVMWHSMI;
+
+ case 1103:
+ return PPC_ID_SPE_EVMWHSMF;
+
+ case 1107:
+ return PPC_ID_SPE_EVMWSSF;
+
+ case 1112:
+ return PPC_ID_SPE_EVMWUMI;
+
+ case 1113:
+ return PPC_ID_SPE_EVMWSMI;
+
+ case 1115:
+ return PPC_ID_SPE_EVMWSMF;
+
+ case 1127:
+ return PPC_ID_SPE_EVMWHSSFA;
+
+ case 1128:
+ return PPC_ID_SPE_EVMWLUMIA;
+
+ case 1132:
+ return PPC_ID_SPE_EVMWHUMIA;
+
+ case 1133:
+ return PPC_ID_SPE_EVMWHSMIA;
+
+ case 1135:
+ return PPC_ID_SPE_EVMWHSMFA;
+
+ case 1139:
+ return PPC_ID_SPE_EVMWSSFA;
+
+ case 1144:
+ return PPC_ID_SPE_EVMWUMIA;
+
+ case 1145:
+ return PPC_ID_SPE_EVMWSMIA;
+
+ case 1147:
+ return PPC_ID_SPE_EVMWSMFA;
+
+ case 1216:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVADDUSIAAW;
+
+ case 1217:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVADDSSIAAW;
+
+ case 1218:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVSUBFUSIAAW;
+
+ case 1219:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVSUBFSSIAAW;
+
+ case 1220:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVMRA;
+
+ case 1222:
+ return PPC_ID_SPE_EVDIVWS;
+
+ case 1223:
+ return PPC_ID_SPE_EVDIVWU;
+
+ case 1224:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVADDUMIAAW;
+
+ case 1225:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVADDSMIAAW;
+
+ case 1226:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVSUBFUMIAAW;
+
+ case 1227:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SPE_EVSUBFSMIAAW;
+
+ case 1280:
+ return PPC_ID_SPE_EVMHEUSIAAW;
+
+ case 1281:
+ return PPC_ID_SPE_EVMHESSIAAW;
+
+ case 1283:
+ return PPC_ID_SPE_EVMHESSFAAW;
+
+ case 1284:
+ return PPC_ID_SPE_EVMHOUSIAAW;
+
+ case 1285:
+ return PPC_ID_SPE_EVMHOSSIAAW;
+
+ case 1287:
+ return PPC_ID_SPE_EVMHOSSFAAW;
+
+ case 1288:
+ return PPC_ID_SPE_EVMHEUMIAAW;
+
+ case 1289:
+ return PPC_ID_SPE_EVMHESMIAAW;
+
+ case 1291:
+ return PPC_ID_SPE_EVMHESMFAAW;
+
+ case 1292:
+ return PPC_ID_SPE_EVMHOUMIAAW;
+
+ case 1293:
+ return PPC_ID_SPE_EVMHOSMIAAW;
+
+ case 1295:
+ return PPC_ID_SPE_EVMHOSMFAAW;
+
+ case 1320:
+ return PPC_ID_SPE_EVMHEGUMIAA;
+
+ case 1321:
+ return PPC_ID_SPE_EVMHEGSMIAA;
+
+ case 1323:
+ return PPC_ID_SPE_EVMHEGSMFAA;
+
+ case 1324:
+ return PPC_ID_SPE_EVMHOGUMIAA;
+
+ case 1325:
+ return PPC_ID_SPE_EVMHOGSMIAA;
+
+ case 1327:
+ return PPC_ID_SPE_EVMHOGSMFAA;
+
+ case 1344:
+ return PPC_ID_SPE_EVMWLUSIAAW;
+
+ case 1345:
+ return PPC_ID_SPE_EVMWLSSIAAW;
+
+ case 1352:
+ return PPC_ID_SPE_EVMWLUMIAAW;
+
+ case 1353:
+ return PPC_ID_SPE_EVMWLSMIAAW;
+
+ case 1363:
+ return PPC_ID_SPE_EVMWSSFAA;
+
+ case 1368:
+ return PPC_ID_SPE_EVMWUMIAA;
+
+ case 1369:
+ return PPC_ID_SPE_EVMWSMIAA;
+
+ case 1371:
+ return PPC_ID_SPE_EVMWSMFAA;
+
+ case 1408:
+ return PPC_ID_SPE_EVMHEUSIANW;
+
+ case 1409:
+ return PPC_ID_SPE_EVMHESSIANW;
+
+ case 1411:
+ return PPC_ID_SPE_EVMHESSFANW;
+
+ case 1412:
+ return PPC_ID_SPE_EVMHOUSIANW;
+
+ case 1413:
+ return PPC_ID_SPE_EVMHOSSIANW;
+
+ case 1415:
+ return PPC_ID_SPE_EVMHOSSFANW;
+
+ case 1416:
+ return PPC_ID_SPE_EVMHEUMIANW;
+
+ case 1417:
+ return PPC_ID_SPE_EVMHESMIANW;
+
+ case 1419:
+ return PPC_ID_SPE_EVMHESMFANW;
+
+ case 1420:
+ return PPC_ID_SPE_EVMHOUMIANW;
+
+ case 1421:
+ return PPC_ID_SPE_EVMHOSMIANW;
+
+ case 1423:
+ return PPC_ID_SPE_EVMHOSMFANW;
+
+ case 1448:
+ return PPC_ID_SPE_EVMHEGUMIAN;
+
+ case 1449:
+ return PPC_ID_SPE_EVMHEGSMIAN;
+
+ case 1451:
+ return PPC_ID_SPE_EVMHEGSMFAN;
+
+ case 1452:
+ return PPC_ID_SPE_EVMHOGUMIAN;
+
+ case 1453:
+ return PPC_ID_SPE_EVMHOGSMIAN;
+
+ case 1455:
+ return PPC_ID_SPE_EVMHOGSMFAN;
+
+ case 1472:
+ return PPC_ID_SPE_EVMWLUSIANW;
+
+ case 1473:
+ return PPC_ID_SPE_EVMWLSSIANW;
+
+ case 1480:
+ return PPC_ID_SPE_EVMWLUMIANW;
+
+ case 1481:
+ return PPC_ID_SPE_EVMWLSMIANW;
+
+ case 1491:
+ return PPC_ID_SPE_EVMWSSFAN;
+
+ case 1496:
+ return PPC_ID_SPE_EVMWUMIAN;
+
+ case 1497:
+ return PPC_ID_SPE_EVMWSMIAN;
+
+ case 1499:
+ return PPC_ID_SPE_EVMWSMFAN;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+}
+
+static InstructionId DecodePairedSingle0x04(uint32_t word32, uint32_t decodeFlags)
+{
+ uint32_t a = GetA(word32);
+ uint32_t b = GetB(word32);
+ uint32_t c = GetC(word32);
+ uint32_t d = GetD(word32);
+
+ // see IBM Broadway RISC Microprocessor User's Manual,
+ // Tables A-30, A-31, and A-32
+ uint32_t subop = (word32 >> 1) & 0x1f;
+ switch (subop)
+ {
+ case 10:
+ return PPC_ID_PAIREDSINGLE_PS_SUM0x;
+
+ case 11:
+ return PPC_ID_PAIREDSINGLE_PS_SUM1x;
+
+ case 12:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_MULS0x;
+
+ case 13:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_MULS1x;
+
+ case 14:
+ return PPC_ID_PAIREDSINGLE_PS_MADDS0x;
+
+ case 15:
+ return PPC_ID_PAIREDSINGLE_PS_MADDS1x;
+
+ case 18:
+ if (c != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_DIVx;
+
+ case 20:
+ if (c != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_SUBx;
+
+ case 21:
+ if (c != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_ADDx;
+
+ case 23:
+ return PPC_ID_PAIREDSINGLE_PS_SELx;
+
+ case 24:
+ if ((a != 0) || (c != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_RESx;
+
+ case 25:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_MULx;
+
+ case 26:
+ if ((a != 0) || (c != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_RSQRTEx;
+
+ case 28:
+ return PPC_ID_PAIREDSINGLE_PS_MSUBx;
+
+ case 29:
+ return PPC_ID_PAIREDSINGLE_PS_MADDx;
+
+ case 30:
+ return PPC_ID_PAIREDSINGLE_PS_NMSUBx;
+
+ case 31:
+ return PPC_ID_PAIREDSINGLE_PS_NMADDx;
+
+ default:
+ ;
+ }
+
+ subop = (word32 >> 1) & 0x3f;
+ switch (subop)
+ {
+ case 6:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PSQ_LX;
+
+ case 7:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PSQ_STX;
+
+ case 38:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PSQ_LUX;
+
+ case 39:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PSQ_STUX;
+
+ default:
+ ;
+ }
+
+ subop = (word32 >> 1) & 0x3ff;
+ switch (subop)
+ {
+ case 0:
+ if ((word32 & 0x00600001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_CMPU0;
+
+ case 32:
+ if ((word32 & 0x00600001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_CMPO0;
+
+ case 40:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_NEGx;
+
+ case 64:
+ if ((word32 & 0x00600001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_CMPU1;
+
+ case 72:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_MRx;
+
+ case 96:
+ if ((word32 & 0x00600001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_CMPO1;
+
+ case 136:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_NABSx;
+
+ case 264:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_PS_ABSx;
+
+ case 528:
+ return PPC_ID_PAIREDSINGLE_PS_MERGE00x;
+
+ case 560:
+ return PPC_ID_PAIREDSINGLE_PS_MERGE01x;
+
+ case 592:
+ return PPC_ID_PAIREDSINGLE_PS_MERGE10x;
+
+ case 624:
+ return PPC_ID_PAIREDSINGLE_PS_MERGE11x;
+
+ case 1014:
+ if ((d != 0) || ((word32 & 0x1) != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PAIREDSINGLE_DCBZ_L;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+
+}
+
+static InstructionId Decode0x13(uint32_t word32, uint32_t decodeFlags)
+{
+ uint32_t a = GetA(word32);
+ uint32_t b = GetB(word32);
+ uint32_t d = GetD(word32);
+
+ uint32_t subop = (word32 >> 1) & 0x1f;
+ switch (subop)
+ {
+ case 0x2:
+ if ((word32 & 0x001fffff) == 4)
+ return PPC_ID_LNIA;
+
+ return PPC_ID_ADDPCIS;
+
+ default:
+ ;
+ }
+
+ subop = word32 & 0x7ff;
+ switch (subop)
+ {
+ case 0x000:
+ if ((word32 & 0x0063f800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MCRF;
+
+ case 0x020:
+ case 0x021:
+ // for PowerPC, this is 0x0000f800, but POWER
+ // introduces BH bits
+ if ((word32 & 0x0000e000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_BCLRx;
+
+ case 0x024:
+ if ((word32 & 0x03fff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_RFID;
+
+ case 0x042:
+ if (a == b)
+ return PPC_ID_CRNOT;
+ else
+ return PPC_ID_CRNOR;
+
+ case 0x04c:
+ if ((word32 & 0x03fff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_RFMCI;
+
+ case 0x04e:
+ if ((word32 & 0x03fff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_RFDI;
+
+ case 0x064:
+ if ((word32 & 0x03fff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_RFI;
+
+ case 0x066:
+ if ((word32 & 0x03fff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_RFCI;
+
+ case 0x102:
+ return PPC_ID_CRANDC;
+
+ case 0x124:
+ if ((word32 & 0x03fff000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_RFEBB;
+
+ case 0x12c:
+ if ((word32 & 0x03fff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_ISYNC;
+
+ case 0x182:
+ if (d == a && d == b)
+ return PPC_ID_CRCLR;
+ else
+ return PPC_ID_CRXOR;
+
+ case 0x1c2:
+ return PPC_ID_CRNAND;
+
+ case 0x202:
+ return PPC_ID_CRAND;
+
+ case 0x224:
+ if ((word32 & 0x03fff801) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_HRFID;
+
+ case 0x242:
+ if (d == a && d == b)
+ return PPC_ID_CRSET;
+ else
+ return PPC_ID_CREQV;
+
+ case 0x2e4:
+ if ((word32 & 0x03fff801) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_STOP;
+
+ case 0x342:
+ return PPC_ID_CRORC;
+
+ case 0x364:
+ if ((word32 & 0x03fff801) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_NAP;
+
+ case 0x382:
+ if (a == b)
+ return PPC_ID_CRMOVE;
+ else
+ return PPC_ID_CROR;
+
+ case 0x420:
+ case 0x421:
+ // TODO: return invalid when BO[2] == 0 (ie when & 0x00800000 == 0)
+ // keeping it in makes it easier to compare against capstone
+ // for now
+
+ // for PowerPC, this is 0x0000f800, but POWER
+ // introduces BH bits
+ if ((word32 & 0x0000e000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_BCCTRx;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+}
+
+static InstructionId Decode0x1E(uint32_t word32, uint32_t decodeFlags)
+{
+ uint32_t sh = GetSH64(word32);
+ uint32_t mx = GetMX64(word32);
+
+ uint32_t subop = (word32 >> 1) & 0xf;
+ switch (subop)
+ {
+ // PPC_ID_RLDICLx
+ case 0x0:
+ case 0x1:
+ // EXTRDIx: n = sh > 0
+ if (mx == 0)
+ return PPC_ID_ROTLDIx;
+ // Encoding of ROTRDIx is impossible to distinguish from ROTLDIx:
+ // return PPC_ID_ROTRDIx;
+ else if (sh + mx == 64)
+ return PPC_ID_SRDIx;
+ else if (sh == 0)
+ return PPC_ID_CLRLDIx;
+ // else if (sh > 0)
+ // return PPC_ID_EXTRDIx;
+ else
+ return PPC_ID_RLDICLx;
+
+ // PPC_ID_RLDICRx
+ case 0x2:
+ case 0x3:
+ // EXTLDIx: n = sh > 0
+ if (sh + mx == 63)
+ return PPC_ID_SLDIx;
+ else if (sh == 0)
+ return PPC_ID_CLRRDIx;
+ // else if (sh > 0)
+ // return PPC_ID_EXTLDIx;
+ // else
+ else
+ return PPC_ID_RLDICRx;
+
+ case 0x4:
+ case 0x5:
+ return PPC_ID_RLDICx;
+
+ case 0x6:
+ case 0x7:
+ return PPC_ID_RLDIMIx;
+
+ case 0x8:
+ if (mx == 0)
+ return PPC_ID_ROTLDx;
+ else
+ return PPC_ID_RLDCLx;
+
+ case 0x9:
+ return PPC_ID_RLDCRx;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+}
+
+InstructionId Decode0x1F(uint32_t word32, uint32_t decodeFlags)
+{
+ uint32_t a = GetA(word32);
+ uint32_t b = GetB(word32);
+ uint32_t d = GetD(word32);
+ uint32_t s = GetS(word32);
+
+ uint32_t subop = word32 & 0x3f;
+ switch (subop)
+ {
+ case 0x1e:
+ return PPC_ID_ISEL;
+
+ default: break;
+ }
+
+ subop = word32 & 0x7ff;
+ switch (subop)
+ {
+ case 0x000:
+ if ((word32 & 0x00400000) == 0)
+ {
+ if ((word32 & 0x00200000) != 0)
+ {
+ if ((decodeFlags & DECODE_FLAGS_PPC64) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_CMPD;
+ }
+ else
+ {
+ return PPC_ID_CMPW;
+ }
+ }
+
+ return PPC_ID_INVALID;
+
+ case 0x008:
+ {
+ uint32_t to = (word32 >> 21) & 0x1f;
+
+ switch (to)
+ {
+ case 1: return PPC_ID_TWLGT;
+ case 2: return PPC_ID_TWLLT;
+ case 4: return PPC_ID_TWEQ;
+ case 8: return PPC_ID_TWGT;
+ case 16: return PPC_ID_TWLT;
+ case 24: return PPC_ID_TWNE;
+ case 31:
+ {
+ if ((GetA(word32) == 0) && (GetB(word32) == 0))
+ return PPC_ID_TRAP;
+
+ return PPC_ID_TWU;
+ }
+ default: return PPC_ID_TW;
+ }
+ }
+
+ case 0x00c:
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC) != 0)
+ return PPC_ID_AV_LVSL;
+
+ return PPC_ID_INVALID;
+
+ case 0x00e:
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC) != 0)
+ return PPC_ID_AV_LVEBX;
+
+ return PPC_ID_INVALID;
+
+ case 0x010:
+ case 0x011:
+ case 0x410:
+ case 0x411:
+ return PPC_ID_SUBFCx;
+
+ case 0x012:
+ case 0x013:
+ if ((decodeFlags & DECODE_FLAGS_PPC64) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MULHDUx;
+
+ case 0x014:
+ case 0x015:
+ case 0x414:
+ case 0x415:
+ return PPC_ID_ADDCx;
+
+ case 0x016:
+ case 0x017:
+ return PPC_ID_MULHWUx;
+
+ case 0x018:
+ case 0x019:
+ return PPC_ID_VSX_LXSIWZX;
+
+ case 0x026:
+ if ((word32 & 0x00100000) != 0)
+ {
+ if ((word32 & 0x800) != 0)
+ return PPC_ID_INVALID;
+
+ uint32_t fxm = (word32 >> 12) & 0xff;
+ if (fxm == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MFOCRF;
+ }
+
+ if ((word32 & 0x000ff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MFCR;
+
+ case 0x028:
+ case 0x029:
+ return PPC_ID_LWARX;
+
+ case 0x02a:
+ return PPC_ID_LDX;
+
+ case 0x02c:
+ if ((word32 & 0x02000000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_ICBT;
+
+ case 0x02e:
+ return PPC_ID_LWZX;
+
+ case 0x030:
+ case 0x031:
+ return PPC_ID_SLWx;
+
+ case 0x034:
+ case 0x035:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_CNTLZWx;
+
+ case 0x036:
+ case 0x037:
+ return PPC_ID_SLDx;
+
+ case 0x038:
+ case 0x039:
+ return PPC_ID_ANDx;
+
+ case 0x03e:
+ return PPC_ID_LWEPX;
+
+ case 0x040:
+ if ((word32 & 0x00400000) == 0)
+ {
+ if ((word32 & 0x00200000) != 0)
+ {
+ if ((decodeFlags & DECODE_FLAGS_PPC64) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_CMPLD;
+ }
+ else
+ {
+ return PPC_ID_CMPLW;
+ }
+
+ break;
+ }
+
+ return PPC_ID_INVALID;
+
+ case 0x04c:
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC) != 0)
+ return PPC_ID_AV_LVSR;
+
+ return PPC_ID_INVALID;
+
+ case 0x04e:
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC) != 0)
+ return PPC_ID_AV_LVEHX;
+
+ return PPC_ID_INVALID;
+
+ case 0x050:
+ case 0x051:
+ case 0x450:
+ case 0x451:
+ return PPC_ID_SUBFx;
+
+ case 0x066:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_MFFPRD;
+
+ case 0x067:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ // either MFVSRD or MFVRD; we use MFVRD for backwards
+ // compatibility with capstone
+ return PPC_ID_VSX_MFVSRD;
+
+ case 0x068:
+ case 0x069:
+ return PPC_ID_LBARX;
+
+ case 0x06a:
+ return PPC_ID_LDUX;
+
+ case 0x06c:
+ if (d != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_DCBST;
+
+ case 0x06e:
+ return PPC_ID_LWZUX;
+
+ case 0x074:
+ case 0x075:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_CNTLZDx;
+
+ case 0x078:
+ case 0x079:
+ return PPC_ID_ANDCx;
+
+ case 0x07e:
+ if (d != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_DCBSTEP;
+
+ case 0x03c:
+ {
+ if ((word32 & 0x039ff800) != 0)
+ return false;
+
+ uint32_t wc = (word32 >> 21) & 0x3;
+ switch (wc)
+ {
+ case 0: return PPC_ID_WAIT;
+ case 1: return PPC_ID_WAITRSV;
+ case 2: return PPC_ID_WAITIMPL;
+
+ default: return PPC_ID_WAIT;
+ }
+ }
+
+ case 0x088:
+ {
+ uint32_t to = (word32 >> 21) & 0x1f;
+
+ switch (to)
+ {
+ case 1: return PPC_ID_TDLGT;
+ case 2: return PPC_ID_TDLLT;
+ case 4: return PPC_ID_TDEQ;
+ case 8: return PPC_ID_TDGT;
+ case 16: return PPC_ID_TDLT;
+ case 24: return PPC_ID_TDNE;
+ case 31: return PPC_ID_TDU;
+ default: return PPC_ID_TD;
+ }
+ }
+
+ case 0x08e:
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC) != 0)
+ return PPC_ID_AV_LVEWX;
+
+ return PPC_ID_INVALID;
+
+ case 0x092:
+ case 0x093:
+ if ((decodeFlags & DECODE_FLAGS_PPC64) != 0)
+ return PPC_ID_MULHDx;
+
+ return PPC_ID_INVALID;
+
+
+ case 0x096:
+ case 0x097:
+ return PPC_ID_MULHWx;
+
+ case 0x098:
+ case 0x099:
+ return PPC_ID_VSX_LXSIWAX;
+
+ case 0x0a6:
+ if ((a != 0) || (b != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MFMSR;
+
+ case 0x0a8:
+ case 0x0a9:
+ return PPC_ID_LDARX;
+
+ case 0x0ac:
+ {
+ if ((word32 & 0x03800000) != 0)
+ return PPC_ID_INVALID;
+
+ uint32_t l = (word32 >> 21) & 0x3;
+ switch (l)
+ {
+ case 1:
+ return PPC_ID_DCBFL;
+
+ case 3:
+ return PPC_ID_DCBFLP;
+
+ default:
+ return PPC_ID_DCBF;
+ }
+ }
+
+ case 0x0ae:
+ return PPC_ID_LBZX;
+
+ case 0x0be:
+ return PPC_ID_LBEPX;
+
+ case 0x0ce:
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC) != 0)
+ return PPC_ID_AV_LVX;
+
+ return PPC_ID_INVALID;
+
+ case 0x0d0:
+ case 0x0d1:
+ case 0x4d0:
+ case 0x4d1:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_NEGx;
+
+ case 0xe6:
+ case 0xe7:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_MFVSRWZ;
+
+ case 0x0e8:
+ case 0x0e9:
+ return PPC_ID_LHARX;
+
+ case 0x0ee:
+ return PPC_ID_LBZUX;
+
+ case 0x0f4:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_POPCNTB;
+
+ case 0x0f8:
+ case 0x0f9:
+ // TODO: PPC_ID_NOTx pseudo-instruction
+ return PPC_ID_NORx;
+
+ case 0x0fe:
+ if ((word32 & 0x03800000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_DCBFEP;
+
+ case 0x100:
+ if ((word32 & 0x0003f800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SETB;
+
+ case 0x106:
+ if ((a != 0) || (b != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_WRTEE;
+
+ case 0x10e:
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC) != 0)
+ return PPC_ID_AV_STVEBX;
+
+ return PPC_ID_INVALID;
+
+ case 0x110:
+ case 0x111:
+ case 0x510:
+ case 0x511:
+ return PPC_ID_SUBFEx;
+
+ case 0x114:
+ case 0x115:
+ case 0x514:
+ case 0x515:
+ return PPC_ID_ADDEx;
+
+ case 0x118:
+ case 0x119:
+ return PPC_ID_VSX_STXSIWX;
+
+ case 0x120:
+ if ((word32 & 0x00100000) != 0)
+ {
+ if ((word32 & 0x800) != 0)
+ return PPC_ID_INVALID;
+
+ uint32_t fxm = (word32 >> 12) & 0xff;
+ if (fxm == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MTOCRF;
+ }
+
+ if ((word32 & 0x00000800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MTCRF;
+
+ case 0x124:
+ if ((a != 0) || (b != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MTMSR;
+
+ case 0x12a:
+ if ((decodeFlags & DECODE_FLAGS_PPC64) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_STDX;
+
+ case 0x12d:
+ return PPC_ID_STWCX;
+
+ case 0x12e:
+ return PPC_ID_STWX;
+
+ case 0x13a:
+ return PPC_ID_STDEPX;
+
+ case 0x13e:
+ return PPC_ID_STWEPX;
+
+ case 0x146:
+ if ((word32 & 0x03ff7800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_WRTEEI;
+
+ case 0x14e:
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC) != 0)
+ return PPC_ID_AV_STVEHX;
+
+ return PPC_ID_INVALID;
+
+ case 0x164:
+ if ((a != 0) || (b != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MTMSRD;
+
+ case 0x166:
+ case 0x167:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_MTVSRD;
+
+ case 0x16a:
+ return PPC_ID_STDUX;
+
+ case 0x16e:
+ return PPC_ID_STWUX;
+
+ case 0x180:
+ if ((word32 & 0x00400000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_CMPRB;
+
+ case 0x18d:
+ if ((word32 & 0x02000000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_ICBLQ;
+
+ case 0x18e:
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC) != 0)
+ return PPC_ID_AV_STVEWX;
+
+ return PPC_ID_INVALID;
+
+ case 0x190:
+ case 0x191:
+ case 0x590:
+ case 0x591:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SUBFZEx;
+
+ case 0x194:
+ case 0x195:
+ case 0x594:
+ case 0x595:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_ADDZEx;
+
+ case 0x1a4:
+ if ((word32 & 0x0010f800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MTSR;
+
+ case 0x1a6:
+ case 0x1a7:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_MTVSRWA;
+
+ case 0x1ad:
+ return PPC_ID_STDCX;
+
+ case 0x1ae:
+ return PPC_ID_STBX;
+
+ case 0x1be:
+ return PPC_ID_STBEPX;
+
+ case 0x1c0:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_CMPEQB;
+
+ case 0x1cc:
+ if ((word32 & 0x02000000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_ICBLC;
+
+ case 0x1ce:
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC) != 0)
+ return PPC_ID_AV_STVX;
+
+ return PPC_ID_INVALID;
+
+ case 0x1d0:
+ case 0x1d1:
+ case 0x5d0:
+ case 0x5d1:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SUBFMEx;
+
+ case 0x1d2:
+ case 0x1d3:
+ case 0x5d2:
+ case 0x5d3:
+ if ((decodeFlags & DECODE_FLAGS_PPC64) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MULLDx;
+
+ case 0x1d4:
+ case 0x1d5:
+ case 0x5d4:
+ case 0x5d5:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_ADDMEx;
+
+ case 0x1d6:
+ case 0x1d7:
+ case 0x5d6:
+ case 0x5d7:
+ return PPC_ID_MULLWx;
+
+ case 0x1e4:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MTSRIN;
+
+ case 0x1e6:
+ case 0x1e7:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_MTVSRWZ;
+
+ case 0x1ec:
+ {
+ uint32_t th = (word32 >> 21) & 0x1f;
+ if (th == 0x10)
+ return PPC_ID_DCBTSTT;
+ else
+ return PPC_ID_DCBTST;
+ }
+
+ case 0x1ee:
+ return PPC_ID_STBUX;
+
+ case 0x1f8:
+ return PPC_ID_BPERMD;
+
+ case 0x1fe:
+ return PPC_ID_DCBTSTEP;
+
+ case 0x212:
+ return PPC_ID_MODUD;
+
+ case 0x214:
+ case 0x215:
+ case 0x614:
+ case 0x615:
+ return PPC_ID_ADDx;
+
+ case 0x216:
+ return PPC_ID_MODUW;
+
+ case 0x218:
+ case 0x219:
+ return PPC_ID_VSX_LXVX;
+
+ case 0x21a:
+ case 0x21b:
+ return PPC_ID_VSX_LXVL;
+
+ case 0x224:
+ if ((d != 0) || (a != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_TLBIEL;
+
+ case 0x22c:
+ {
+ uint32_t th = (word32 >> 21) & 0x1f;
+ if (th == 0x10)
+ return PPC_ID_DCBTT;
+ else
+ return PPC_ID_DCBT;
+ }
+
+ case 0x22e:
+ return PPC_ID_LHZX;
+
+ case 0x238:
+ case 0x239:
+ return PPC_ID_EQVx;
+
+ case 0x23e:
+ return PPC_ID_LHEPX;
+
+ case 0x25a:
+ case 0x25b:
+ return PPC_ID_VSX_LXVLL;
+
+ case 0x25c:
+ return PPC_ID_MFBHRBE;
+
+ case 0x264:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_TLBIE;
+
+ case 0x266:
+ case 0x267:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_MFVSRLD;
+
+ case 0x26c:
+ return PPC_ID_ECIWX;
+
+ case 0x26e:
+ return PPC_ID_LHZUX;
+
+ case 0x278:
+ case 0x279:
+ return PPC_ID_XORx;
+
+ case 0x27e:
+ return PPC_ID_DCBTEP;
+
+ case 0x286:
+ {
+ uint32_t dcr = GetSpecialRegisterCommon(word32);
+
+ switch (dcr)
+ {
+ case 0x80: return PPC_ID_MFBR0;
+ case 0x81: return PPC_ID_MFBR1;
+ case 0x82: return PPC_ID_MFBR2;
+ case 0x83: return PPC_ID_MFBR3;
+ case 0x84: return PPC_ID_MFBR4;
+ case 0x85: return PPC_ID_MFBR5;
+ case 0x86: return PPC_ID_MFBR6;
+ case 0x87: return PPC_ID_MFBR7;
+
+ default: return PPC_ID_MFDCR;
+ }
+ }
+
+ case 0x298:
+ case 0x299:
+ if ((decodeFlags & DECODE_FLAGS_VSX) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_LXVDSX;
+
+ case 0x29c:
+ return PPC_ID_MFPMR;
+
+ case 0x2a4:
+ if (a != 0 || b != 0 || d != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SLBSYNC;
+
+ case 0x2a6:
+ {
+ uint32_t spr = GetSpecialRegisterCommon(word32);
+
+ // there are a bunch of other MF<some specific SPR>
+ // instructions; instead of handling them all, we just
+ // give a few common SPRs their own special opcodes, and
+ // bundle the rest into MFSPR
+ //
+ // this avoids adding a bazillion separate instructions
+ // that need to be lifted separately, AND are highly
+ // arch-dependent
+ switch (spr)
+ {
+ case 1: return PPC_ID_MFXER;
+ case 8: return PPC_ID_MFLR;
+ case 9: return PPC_ID_MFCTR;
+
+ default: return PPC_ID_MFSPR;
+ }
+ }
+
+ case 0x2aa:
+ return PPC_ID_LWAX;
+
+ case 0x2ac:
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC) == 0)
+ return PPC_ID_INVALID;
+
+ if ((word32 & 0x01800000) != 0)
+ return PPC_ID_INVALID;
+
+ if ((word32 & 0x02000000) != 0)
+ return PPC_ID_AV_DSTT;
+ else
+ return PPC_ID_AV_DST;
+
+ case 0x2ae:
+ return PPC_ID_LHAX;
+
+ case 0x2ce:
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC) != 0)
+ return PPC_ID_AV_LVXL;
+
+ return PPC_ID_INVALID;
+
+ case 0x2d8:
+ case 0x2d9:
+ return PPC_ID_VSX_LXVWSX;
+
+ case 0x2e4:
+ if ((word32 & 0x03fff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_TLBIA;
+
+ case 0x2e6:
+ {
+ uint32_t special = GetSpecialRegisterCommon(word32);
+ switch (special)
+ {
+ case 269: return PPC_ID_MFTBU;
+
+ default: return PPC_ID_MFTB;
+ }
+ }
+
+ case 0x2ea:
+ if ((decodeFlags & DECODE_FLAGS_PPC64) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_LWAUX;
+
+ case 0x2ec:
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC) == 0)
+ return PPC_ID_INVALID;
+
+ if ((word32 & 0x01800000) != 0)
+ return PPC_ID_INVALID;
+
+ if ((word32 & 0x02000000) != 0)
+ return PPC_ID_AV_DSTSTT;
+ else
+ return PPC_ID_AV_DSTST;
+
+ case 0x2ee:
+ return PPC_ID_LHAUX;
+
+ case 0x2f4:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ // TODO: [Category: Server]
+ // TODO: [Category: Embedded.Phased-In]
+ return PPC_ID_POPCNTW;
+
+ case 0x312:
+ case 0x313:
+ case 0x712:
+ case 0x713:
+ return PPC_ID_DIVDEUx;
+
+ case 0x316:
+ case 0x317:
+ case 0x716:
+ case 0x717:
+ return PPC_ID_DIVWEUx;
+
+ case 0x318:
+ case 0x319:
+ return PPC_ID_VSX_STXVX;
+
+ case 0x31a:
+ case 0x31b:
+ return PPC_ID_VSX_STXVL;
+
+ case 0x324:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SLBMTE;
+
+ case 0x326:
+ case 0x327:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_MTVSRWS;
+
+ case 0x32e:
+ return PPC_ID_STHX;
+
+ case 0x338:
+ case 0x339:
+ return PPC_ID_ORCx;
+
+ case 0x33e:
+ return PPC_ID_STHEPX;
+
+ case 0x352:
+ case 0x353:
+ case 0x752:
+ case 0x753:
+ return PPC_ID_DIVDEx;
+
+ case 0x356:
+ case 0x357:
+ case 0x756:
+ case 0x757:
+ return PPC_ID_DIVWEx;
+
+ case 0x35a:
+ case 0x35b:
+ return PPC_ID_VSX_STXVLL;
+
+ case 0x35c:
+ if ((a != 0) || (b != 0) || (d != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_CLRBHRB;
+
+ case 0x364:
+ if ((d != 0) || (a != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SLBIE;
+
+ case 0x366:
+ case 0x367:
+ return PPC_ID_VSX_MTVSRDD;
+
+ case 0x36c:
+ return PPC_ID_ECOWX;
+
+ case 0x36e:
+ return PPC_ID_STHUX;
+
+ case 0x378:
+ case 0x379:
+ // TODO: it would be nice to disassemble "mr.", but
+ // capstone doesn't handle this (and technically
+ // "mr." isn't listed as a valid instruction in
+ // the documentation, but it IS a bit more user
+ // friendly for disassembly purposes)
+ if (b == s && ((word32 & 0x1) == 0))
+ return PPC_ID_MRx;
+ else
+ return PPC_ID_ORx;
+
+ case 0x386:
+ {
+ uint32_t dcr = GetSpecialRegisterCommon(word32);
+
+ switch (dcr)
+ {
+ case 0x80: return PPC_ID_MTBR0;
+ case 0x81: return PPC_ID_MTBR1;
+ case 0x82: return PPC_ID_MTBR2;
+ case 0x83: return PPC_ID_MTBR3;
+ case 0x84: return PPC_ID_MTBR4;
+ case 0x85: return PPC_ID_MTBR5;
+ case 0x86: return PPC_ID_MTBR6;
+ case 0x87: return PPC_ID_MTBR7;
+
+ default: return PPC_ID_MTDCR;
+ }
+ }
+
+ case 0x38c:
+ {
+ if ((word32 & 0x021ff800) != 0)
+ return PPC_ID_INVALID;
+
+ uint32_t ct = (word32 >> 21) & 0xf;
+
+ if (ct == 0)
+ return PPC_ID_DCCCI;
+ else
+ return PPC_ID_DCI;
+ }
+
+ case 0x392:
+ case 0x393:
+ case 0x792:
+ case 0x793:
+ return PPC_ID_DIVDUx;
+
+ case 0x396:
+ case 0x397:
+ case 0x796:
+ case 0x797:
+ return PPC_ID_DIVWUx;
+
+ case 0x39c:
+ return PPC_ID_MTPMR;
+
+ case 0x3a4:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SLBIEG;
+
+ case 0x3a6:
+ {
+ uint32_t spr = GetSpecialRegisterCommon(word32);
+
+ switch (spr)
+ {
+ // there are a bunch of other MF<some specific SPR>
+ // instructions; instead of handling them all, we just
+ // give a few common SPRs their own special opcodes, and
+ // bundle the rest into MFSPR
+ //
+ // this avoids adding a bazillion separate instructions
+ // that need to be lifted separately, AND are highly
+ // arch-dependent
+ case 1: return PPC_ID_MTXER;
+ case 8: return PPC_ID_MTLR;
+ case 9: return PPC_ID_MTCTR;
+
+ default: return PPC_ID_MTSPR;
+ }
+ }
+
+ case 0x3ac:
+ if (d != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_DCBI;
+
+ case 0x3b8:
+ case 0x3b9:
+ return PPC_ID_NANDx;
+
+ case 0x3cc:
+ if ((word32 & 0x02000000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_ICBTLS;
+
+ case 0x3ce:
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC) != 0)
+ return PPC_ID_AV_STVXL;
+
+ return PPC_ID_INVALID;
+
+ case 0x3d2:
+ case 0x3d3:
+ case 0x7d2:
+ case 0x7d3:
+ return PPC_ID_DIVDx;
+
+ case 0x3d6:
+ case 0x3d7:
+ case 0x7d6:
+ case 0x7d7:
+ return PPC_ID_DIVWx;
+
+ case 0x3e4:
+ if ((word32 & 0x03fff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SLBIA;
+
+ case 0x3f4:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ // TODO: [Category: Server.64-bit]
+ // TODO: [Category: Embedded.64-bit.Phased-In]
+ return PPC_ID_POPCNTD;
+
+ case 0x3f8:
+ return PPC_ID_CMPB;
+
+ case 0x400:
+ if ((word32 & 0x00fff800) != 0)
+ return PPC_ID_INVALID;
+
+ break;
+
+ case 0x418:
+ case 0x419:
+ return PPC_ID_VSX_LXSSPX;
+
+ case 0x428:
+ if ((decodeFlags & DECODE_FLAGS_PPC64) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_LDBRX;
+
+ case 0x42a:
+ return PPC_ID_LSWX;
+
+ case 0x42c:
+ return PPC_ID_LWBRX;
+
+ case 0x42e:
+ return PPC_ID_LFSX;
+
+ case 0x430:
+ case 0x431:
+ return PPC_ID_SRWx;
+
+ case 0x434:
+ case 0x435:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_CNTTZWx;
+
+ case 0x436:
+ case 0x437:
+ return PPC_ID_SRDx;
+
+ case 0x46c:
+ if ((word32 & 0x03fff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_TLBSYNC;
+
+ case 0x46e:
+ return PPC_ID_LFSUX;
+
+ case 0x474:
+ case 0x475:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_CNTTZDx;
+
+ case 0x480:
+ if ((word32 & 0x007ff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MCRXRX;
+
+ case 0x48c:
+ return PPC_ID_LWAT;
+
+ case 0x498:
+ case 0x499:
+ if ((decodeFlags & DECODE_FLAGS_VSX) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_LXSDX;
+
+ case 0x4a6:
+ if ((word32 & 0x0010f801) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MFSR;
+
+ case 0x4aa:
+ return PPC_ID_LSWI;
+
+ case 0x4ac:
+ {
+ if ((word32 & 0x039ff800) != 0)
+ return PPC_ID_INVALID;
+
+ uint32_t l = (word32 >> 21) & 0x3;
+ switch (l)
+ {
+ case 0: return PPC_ID_SYNC;
+ case 1: return PPC_ID_LWSYNC;
+ case 2: return PPC_ID_PTESYNC;
+
+ default: return PPC_ID_SYNC;
+
+ }
+ }
+
+ case 0x4ae:
+ return PPC_ID_LFDX;
+
+ case 0x4be:
+ return PPC_ID_LFDEPX;
+
+ case 0x4cc:
+ return PPC_ID_LDAT;
+
+ case 0x4ee:
+ return PPC_ID_LFDUX;
+
+ case 0x4e4:
+ if ((word32 & 0x03fff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_TLBIA;
+
+ case 0x518:
+ case 0x519:
+ return PPC_ID_VSX_STXSSPX;
+
+ case 0x51d:
+ if ((word32 & 0x01dff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_TBEGIN;
+
+ case 0x526:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MFSRIN;
+
+ case 0x528:
+ if ((decodeFlags & DECODE_FLAGS_PPC64) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_STDBRX;
+
+ case 0x52a:
+ return PPC_ID_STSWX;
+
+ case 0x52c:
+ return PPC_ID_STWBRX;
+
+ case 0x52e:
+ return PPC_ID_STFSX;
+
+ case 0x55d:
+ if ((word32 & 0x01fff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_TEND;
+
+ case 0x56d:
+ return PPC_ID_STBCX;
+
+ case 0x56e:
+ return PPC_ID_STFSUX;
+
+ case 0x58c:
+ return PPC_ID_STWAT;
+
+ case 0x598:
+ case 0x599:
+ if ((decodeFlags & DECODE_FLAGS_VSX) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_STXSDX;
+
+ case 0x59c:
+ if ((word32 & 0x007ff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_TCHECK;
+
+ case 0x5aa:
+ return PPC_ID_STSWI;
+
+ case 0x5ad:
+ return PPC_ID_STHCX;
+
+ case 0x5ae:
+ return PPC_ID_STFDX;
+
+ case 0x5be:
+ return PPC_ID_STFDEPX;
+
+ case 0x5cc:
+ return PPC_ID_STDAT;
+
+ case 0x5dd:
+ if ((word32 & 0x03dff800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_TSR;
+
+ case 0x5e6:
+ if ((word32 & 0x001cf800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_DARN;
+
+ case 0x5ec:
+ if (d != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_DCBA;
+
+ case 0x5ee:
+ return PPC_ID_STFDUX;
+
+ case 0x60c:
+ if (d != 1)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_COPY;
+
+ case 0x612:
+ return PPC_ID_MODSD;
+
+ case 0x616:
+ return PPC_ID_MODSW;
+
+ case 0x618:
+ case 0x619:
+ if ((decodeFlags & DECODE_FLAGS_VSX) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_LXVW4X;
+
+ case 0x61a:
+ case 0x61b:
+ return PPC_ID_VSX_LXSIBZX;
+
+ case 0x61d:
+ return PPC_ID_TABORTWC;
+
+ case 0x624:
+ if ((word32 & 0x03e00000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_TLBIVAX;
+
+ case 0x62a:
+ return PPC_ID_LWZCIX;
+
+ case 0x62c:
+ return PPC_ID_LHBRX;
+
+ case 0x630:
+ case 0x631:
+ return PPC_ID_SRAWx;
+
+ case 0x634:
+ case 0x635:
+ if ((decodeFlags & DECODE_FLAGS_PPC64) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SRADx;
+
+ case 0x658:
+ case 0x659:
+ return PPC_ID_VSX_LXVH8X;
+
+ case 0x65a:
+ case 0x65b:
+ return PPC_ID_VSX_LXSIHZX;
+
+ case 0x65d:
+ return PPC_ID_TABORTDC;
+
+ case 0x66a:
+ return PPC_ID_LHZCIX;
+
+ case 0x66c:
+ {
+ if ((word32 & 0x019ff800) != 0)
+ return PPC_ID_INVALID;
+
+ uint32_t all = ((word32 >> 25) & 0x1) != 0;
+
+ if (all)
+ {
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+ else
+ return PPC_ID_AV_DSSALL;
+ }
+ else
+ {
+ return PPC_ID_AV_DSS;
+ }
+ }
+
+ case 0x670:
+ case 0x671:
+ return PPC_ID_SRAWIx;
+
+ case 0x674:
+ case 0x675:
+ case 0x676:
+ case 0x677:
+ if ((decodeFlags & DECODE_FLAGS_PPC64) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SRADIx;
+
+ case 0x68c:
+ if (a != 0 || b != 0 || d != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_CP_ABORT;
+
+ case 0x698:
+ case 0x699:
+ if ((decodeFlags & DECODE_FLAGS_VSX) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_LXVD2X;
+
+ case 0x69d:
+ return PPC_ID_TABORTWCI;
+
+ case 0x6a6:
+ if ((word32 & 0x001e0000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SLBMFEV;
+
+ case 0x6aa:
+ return PPC_ID_LBZCIX;
+
+ case 0x6ac:
+ if ((a != 0) || (b != 0))
+ return PPC_ID_INVALID;
+
+ if (d == 0)
+ return PPC_ID_EIEIO;
+ else
+ return PPC_ID_MBAR;
+
+ case 0x6ae:
+ return PPC_ID_LFIWAX;
+
+ case 0x6d8:
+ case 0x6d9:
+ return PPC_ID_VSX_LXVB16X;
+
+ case 0x6dd:
+ return PPC_ID_TABORTDCI;
+
+ case 0x6ea:
+ return PPC_ID_LDCIX;
+
+ case 0x6ec:
+ if ((a != 0) || (b != 0) || (d != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MSGSYNC;
+
+ case 0x6ee:
+ return PPC_ID_LFIWZX;
+
+ case 0x6f4:
+ case 0x6f5:
+ case 0x6f6:
+ case 0x6f7:
+ return PPC_ID_EXTSWSLIx;
+
+ case 0x70d:
+ if (d != 1)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_PASTE;
+
+ case 0x718:
+ case 0x719:
+ if ((decodeFlags & DECODE_FLAGS_VSX) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_STXVW4X;
+
+ case 0x71a:
+ case 0x71b:
+ return PPC_ID_VSX_STXSIBX;
+
+ case 0x71d:
+ if (d != 0 || b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_TABORT;
+
+ case 0x724:
+ if ((word32 & 0x03e00000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_TLBSX;
+
+ case 0x726:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SLBMFEE;
+
+ case 0x72a:
+ return PPC_ID_STWCIX;
+
+ case 0x72c:
+ return PPC_ID_STHBRX;
+
+ case 0x734:
+ case 0x735:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_EXTSHx;
+
+ case 0x758:
+ case 0x759:
+ return PPC_ID_VSX_STXVH8X;
+
+ case 0x75a:
+ case 0x75b:
+ return PPC_ID_VSX_STXSIHX;
+
+ case 0x75d:
+ if ((d != 0) || (b != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_TRECLAIM;
+
+ case 0x764:
+ if ((word32 & 0x800) != 0)
+ return PPC_ID_TLBREHI;
+ else
+ return PPC_ID_TLBRELO;
+
+ case 0x76a:
+ return PPC_ID_STHCIX;
+
+ case 0x774:
+ case 0x775:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_EXTSBx;
+
+ case 0x78c:
+ {
+ if ((word32 & 0x021ff801) != 0)
+ return PPC_ID_INVALID;
+
+ uint32_t ct = (word32 >> 21) & 0xf;
+
+ if (ct == 0)
+ return PPC_ID_ICCCI;
+ else
+ return PPC_ID_ICI;
+ }
+
+ case 0x798:
+ case 0x799:
+ if ((decodeFlags & DECODE_FLAGS_VSX) == 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_STXVD2X;
+
+ case 0x7a4:
+ if ((word32 & 0x800) != 0)
+ return PPC_ID_TLBWELO;
+ else
+ return PPC_ID_TLBWEHI;
+
+ case 0x7aa:
+ return PPC_ID_STBCIX;
+
+ case 0x7ac:
+ if (d != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_ICBI;
+
+ case 0x7ae:
+ return PPC_ID_STFIWX;
+
+ case 0x7b4:
+ case 0x7b5:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_EXTSWx;
+
+ case 0x7be:
+ if (d != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_ICBIEP;
+
+ case 0x7d8:
+ case 0x7d9:
+ return PPC_ID_VSX_STXVB16X;
+
+ case 0x7dd:
+ if ((a != 0) || (b != 0) || (d != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_TRECHKPT;
+
+ case 0x7e4:
+ if (d != 0 || a != 0)
+ return PPC_ID_INVALID;
+
+ // NOTE: this is only valid for 603 processors?
+ return PPC_ID_TLBLI;
+
+ case 0x7ea:
+ return PPC_ID_STDCIX;
+
+ case 0x7ec:
+ {
+ // NOTE: I can't find anything about the "DCBZL" opcode
+ // anywhere, but this seems to match capstone
+ if ((word32 & 0x03e00000) == 0x00200000)
+ return PPC_ID_DCBZL;
+ else if ((word32 & 0x03e00000) == 0)
+ return PPC_ID_DCBZ;
+ else
+ return PPC_ID_INVALID;
+ }
+
+ case 0x7fe:
+ if (d != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_DCBZEP;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+
+ return true;
+}
+
+static InstructionId DecodeVsx0x39(uint32_t word32, uint32_t flags)
+{
+ uint32_t subop = word32 & 0x3;
+ switch (subop)
+ {
+ case 2:
+ return PPC_ID_VSX_LXSD;
+
+ case 3:
+ return PPC_ID_VSX_LXSSP;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+}
+
+static InstructionId Decode0x3B(uint32_t word32, uint32_t flags)
+{
+ uint32_t a = GetA(word32);
+ uint32_t b = GetB(word32);
+ uint32_t c = GetC(word32);
+
+ uint32_t subop = word32 & 0x3f;
+ switch (subop)
+ {
+ case 0x24:
+ case 0x25:
+ if (c != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FDIVSx;
+
+ case 0x28:
+ case 0x29:
+ if (c != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FSUBSx;
+
+ case 0x2a:
+ case 0x2b:
+ if (c != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FADDSx;
+
+ case 0x2c:
+ case 0x2d:
+ if ((a != 0) || (c != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FSQRTSx;
+
+ case 0x30:
+ case 0x31:
+ if ((a != 0) || (c != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FRESx;
+
+ case 0x32:
+ case 0x33:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FMULSx;
+
+ case 0x34:
+ case 0x35:
+ if ((a != 0) || (c != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FRSQRTESx;
+
+ case 0x38:
+ case 0x39:
+ return PPC_ID_FMSUBSx;
+
+ case 0x3a:
+ case 0x3b:
+ return PPC_ID_FMADDSx;
+
+ case 0x3c:
+ case 0x3d:
+ return PPC_ID_FNMSUBSx;
+
+ case 0x3e:
+ case 0x3f:
+ return PPC_ID_FNMADDSx;
+
+ default:
+ break;
+ }
+
+ subop = word32 & 0x7ff;
+ switch (subop)
+ {
+ case 0x69c:
+ case 0x69d:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FCFIDSx;
+
+ case 0x79c:
+ case 0x79d:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FCFIDUSx;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+
+ return true;
+}
+
+static InstructionId DecodeVsx0x3C(uint32_t word32, uint32_t flags)
+{
+ uint32_t subop = (word32 >> 4) & 0x3;
+ uint32_t vsxA = GetVsxA(word32);
+ uint32_t vsxB = GetVsxB(word32);
+
+ switch (subop)
+ {
+ case 0x3: return PPC_ID_VSX_XXSEL;
+ default: break;
+ }
+
+ subop = (word32 >> 1) & 0x3ff;
+ switch (subop)
+ {
+ case 0x168:
+ if ((word32 & 0x00180000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XXSPLTIB;
+
+ case 0x396:
+ return PPC_ID_VSX_XSIEXPDP;
+
+ default:
+ ;
+ }
+
+ subop = (word32 >> 2) & 0x1ff;
+ switch (subop)
+ {
+ case 0x00a:
+ if ((word32 & 0x001f0000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSRSQRTESP;
+
+ case 0x00b:
+ if ((word32 & 0x001f0000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSSQRTSP;
+
+ case 0x01a:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSRESP;
+
+ case 0x048:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVDPUXWS;
+
+ case 0x049:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSRDPI;
+
+ case 0x04a:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSRSQRTEDP;
+
+ case 0x04b:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSSQRTDP;
+
+ case 0x058:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVDPSXWS;
+
+ case 0x059:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSRDPIZ;
+
+ case 0x05a:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSREDP;
+
+ case 0x069:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSRDPIP;
+
+ case 0x6a:
+ if ((word32 & 0x007f0001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSTSQRTDP;
+
+ case 0x06b:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSRDPIC;
+
+ case 0x079:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSRDPIM;
+
+ case 0x088:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVSPUXWS;
+
+ case 0x089:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVRSPI;
+
+ case 0x08a:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVRSQRTESP;
+
+ case 0x08b:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVSQRTSP;
+
+ case 0x098:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVSPSXWS;
+
+ case 0x099:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVRSPIZ;
+
+ case 0x09a:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVRESP;
+
+ case 0x0a4:
+ if ((word32 & 0x001c0004) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XXSPLTW;
+
+ case 0x0a5:
+ if ((word32 & 0x00100000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XXEXTRACTUW;
+
+ case 0x0a8:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVUXWSP;
+
+ case 0x0a9:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVRSPIP;
+
+ case 0x0aa:
+ if ((word32 & 0x007f0001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVTSQRTSP;
+
+ case 0x0ab:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVRSPIC;
+
+ case 0x0b5:
+ if ((word32 & 0x00100000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XXINSERTW;
+
+ case 0x0b8:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVSXWSP;
+
+ case 0x0b9:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVRSPIM;
+
+ case 0x0c8:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVDPUXWS;
+
+ case 0x0c9:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVRDPI;
+
+ case 0x0ca:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVRSQRTEDP;
+
+ case 0x0cb:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVSQRTDP;
+
+ case 0x0d8:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVDPSXWS;
+
+ case 0x0d9:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVRDPIZ;
+
+ case 0x0da:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVREDP;
+
+ case 0x0e8:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVUXWDP;
+
+ case 0x0e9:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVRDPIP;
+
+ case 0xea:
+ if ((word32 & 0x007f0001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVTSQRTDP;
+
+ case 0x0eb:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVRDPIC;
+
+ case 0x0f8:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVSXWDP;
+
+ case 0x0f9:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVRDPIM;
+
+ case 0x109:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVDPSP;
+
+ case 0x10b:
+ if ((word32 & 0x001f0000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVDPSPN;
+
+ case 0x119:
+ if ((word32 & 0x001f0000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSRSP;
+
+ case 0x128:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVUXDSP;
+
+ case 0x12a:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSTSTDCSP;
+
+ case 0x138:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVSXDSP;
+
+ case 0x148:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVDPUXDS;
+
+ case 0x149:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVSPDP;
+
+ case 0x14b:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVSPDPN;
+
+ case 0x158:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVDPSXDS;
+
+ case 0x159:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSABSDP;
+
+ case 0x15b:
+ {
+ uint32_t subsubop = (word32 >> 16) & 0x1f;
+ switch (subsubop)
+ {
+ case 0x00:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSXEXPDP;
+
+ case 0x01:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSXSIGDP;
+
+ case 0x10:
+ return PPC_ID_VSX_XSCVHPDP;
+
+ case 0x11:
+ return PPC_ID_VSX_XSCVDPHP;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+ }
+
+ case 0x168:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVUXDDP;
+
+ case 0x169:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSNABSDP;
+
+ case 0x16a:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSTSTDCDP;
+
+ case 0x178:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVSXDDP;
+
+ case 0x179:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSNEGDP;
+
+ case 0x188:
+ if ((word32 & 0x001f0000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVSPUXDS;
+
+ case 0x189:
+ if ((word32 & 0x001f0000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVDPSP;
+
+ case 0x198:
+ if ((word32 & 0x001f0000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVSPSXDS;
+
+ case 0x199:
+ if ((word32 & 0x001f0000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVABSSP;
+
+ case 0x1a8:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVUXDSP;
+
+ case 0x1a9:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVNABSSP;
+
+ case 0x1b8:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVSXDSP;
+
+ case 0x1b9:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVNEGSP;
+
+ case 0x1c8:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVDPUXDS;
+
+ case 0x1c9:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVSPDP;
+
+ case 0x1d8:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVDPSXDS;
+
+ case 0x1d9:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVABSDP;
+
+ case 0x1db:
+ {
+ uint32_t subsubop = (word32 >> 16) & 0x1f;
+ switch (subsubop)
+ {
+ case 0x00:
+ return PPC_ID_VSX_XVXEXPDP;
+
+ case 0x01:
+ return PPC_ID_VSX_XVXSIGDP;
+
+ case 0x07:
+ return PPC_ID_VSX_XXBRH;
+
+ case 0x08:
+ return PPC_ID_VSX_XVXEXPSP;
+
+ case 0x09:
+ return PPC_ID_VSX_XVXSIGSP;
+
+ case 0x0f:
+ return PPC_ID_VSX_XXBRW;
+
+ case 0x17:
+ return PPC_ID_VSX_XXBRD;
+
+ case 0x18:
+ return PPC_ID_VSX_XVCVHPSP;
+
+ case 0x19:
+ return PPC_ID_VSX_XVCVSPHP;
+
+ case 0x1f:
+ return PPC_ID_VSX_XXBRQ;
+
+ default:
+ return PPC_ID_INVALID;
+
+ }
+ }
+
+ case 0x1e8:
+ if ((word32 & 0x001f0000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVUXDDP;
+
+ case 0x1e9:
+ if ((word32 & 0x001f0000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVNABSDP;
+
+ case 0x1f8:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVCVSXDDP;
+
+ case 0x1f9:
+ if ((word32 & 0x001f0000) != 0x0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVNEGDP;
+
+ default:
+ break;
+ }
+
+ subop = (word32 >> 3) & 0xff;
+ switch (subop)
+ {
+ case 0x00:
+ return PPC_ID_VSX_XSADDSP;
+
+ case 0x01:
+ return PPC_ID_VSX_XSMADDASP;
+
+ case 0x02:
+ case 0x22:
+ case 0x42:
+ case 0x62:
+ return PPC_ID_VSX_XXSLDWI;
+
+ case 0x03:
+ return PPC_ID_VSX_XSCMPEQDP;
+
+ case 0x08:
+ return PPC_ID_VSX_XSSUBSP;
+
+ case 0x09:
+ return PPC_ID_VSX_XSMADDMSP;
+
+ case 0x0a:
+ case 0x2a:
+ case 0x4a:
+ case 0x6a:
+ {
+ uint32_t dm = (word32 >> 8) & 0x3;
+
+ if (vsxA == vsxB)
+ {
+ switch (dm)
+ {
+ case 0: return PPC_ID_VSX_XXSPLTD;
+ case 2: return PPC_ID_VSX_XXSWAPD;
+ case 3: return PPC_ID_VSX_XXSPLTD;
+ default: return PPC_ID_VSX_XXPERMDI;
+ }
+ }
+ else
+ {
+ switch (dm)
+ {
+ case 0: return PPC_ID_VSX_XXMRGHD;
+ case 3: return PPC_ID_VSX_XXMRGLD;
+ default: return PPC_ID_VSX_XXPERMDI;
+ }
+ }
+ }
+
+ case 0x0b:
+ return PPC_ID_VSX_XSCMPGTDP;
+
+ case 0x10:
+ return PPC_ID_VSX_XSMULSP;
+
+ case 0x11:
+ return PPC_ID_VSX_XSMSUBASP;
+
+ case 0x12:
+ return PPC_ID_VSX_XXMRGHW;
+
+ case 0x13:
+ return PPC_ID_VSX_XSCMPGEDP;
+
+ case 0x18:
+ return PPC_ID_VSX_XSDIVSP;
+
+ case 0x19:
+ return PPC_ID_VSX_XSMSUBMSP;
+
+ case 0x1a:
+ return PPC_ID_VSX_XXPERM;
+
+ case 0x20:
+ return PPC_ID_VSX_XSADDDP;
+
+ case 0x21:
+ return PPC_ID_VSX_XSMADDADP;
+
+ case 0x23:
+ if ((word32 & 0x00600001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCMPUDP;
+
+ case 0x28:
+ return PPC_ID_VSX_XSSUBDP;
+
+ case 0x29:
+ return PPC_ID_VSX_XSMADDMDP;
+
+ case 0x2b:
+ if ((word32 & 0x00600001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCMPODP;
+
+ case 0x30:
+ return PPC_ID_VSX_XSMULDP;
+
+ case 0x31:
+ return PPC_ID_VSX_XSMSUBADP;
+
+ case 0x32:
+ return PPC_ID_VSX_XXMRGLW;
+
+ case 0x38:
+ return PPC_ID_VSX_XSDIVDP;
+
+ case 0x39:
+ return PPC_ID_VSX_XSMSUBMDP;
+
+ case 0x3a:
+ return PPC_ID_VSX_XXPERMR;
+
+ case 0x3b:
+ if ((word32 & 0x00600001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCMPEXPDP;
+
+ case 0x3d:
+ if ((word32 & 0x00600001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSTDIVDP;
+
+ case 0x40:
+ return PPC_ID_VSX_XVADDSP;
+
+ case 0x41:
+ return PPC_ID_VSX_XVMADDASP;
+
+ case 0x43:
+ case 0xc3:
+ return PPC_ID_VSX_XVCMPEQSPx;
+
+ case 0x48:
+ return PPC_ID_VSX_XVSUBSP;
+
+ case 0x49:
+ return PPC_ID_VSX_XVMADDMSP;
+
+ case 0x4b:
+ case 0xcb:
+ return PPC_ID_VSX_XVCMPGTSPx;
+
+ case 0x50:
+ return PPC_ID_VSX_XVMULSP;
+
+ case 0x51:
+ return PPC_ID_VSX_XVMSUBASP;
+
+ case 0x53:
+ case 0xd3:
+ return PPC_ID_VSX_XVCMPGESPx;
+
+ case 0x58:
+ return PPC_ID_VSX_XVDIVSP;
+
+ case 0x59:
+ return PPC_ID_VSX_XVMSUBMSP;
+
+ case 0x5d:
+ if ((word32 & 0x00600001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVTDIVSP;
+
+ case 0x60:
+ return PPC_ID_VSX_XVADDDP;
+
+ case 0x61:
+ return PPC_ID_VSX_XVMADDADP;
+
+ case 0x63:
+ case 0xe3:
+ return PPC_ID_VSX_XVCMPEQDPx;
+
+ case 0x68:
+ return PPC_ID_VSX_XVSUBDP;
+
+ case 0x69:
+ return PPC_ID_VSX_XVMADDMDP;
+
+ case 0x6b:
+ case 0xeb:
+ return PPC_ID_VSX_XVCMPGTDPx;
+
+ case 0x70:
+ return PPC_ID_VSX_XVMULDP;
+
+ case 0x71:
+ return PPC_ID_VSX_XVMSUBADP;
+
+ case 0x73:
+ case 0xf3:
+ return PPC_ID_VSX_XVCMPGEDPx;
+
+ case 0x78:
+ return PPC_ID_VSX_XVDIVDP;
+
+ case 0x79:
+ return PPC_ID_VSX_XVMSUBMDP;
+
+ case 0x7d:
+ if ((word32 & 0x00600001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XVTDIVDP;
+
+ case 0x80:
+ return PPC_ID_VSX_XSMAXCDP;
+
+ case 0x81:
+ return PPC_ID_VSX_XSNMADDASP;
+
+ case 0x82:
+ return PPC_ID_VSX_XXLAND;
+
+ case 0x88:
+ return PPC_ID_VSX_XSMINCDP;
+
+ case 0x89:
+ return PPC_ID_VSX_XSNMADDMSP;
+
+ case 0x8a:
+ return PPC_ID_VSX_XXLANDC;
+
+ case 0x90:
+ return PPC_ID_VSX_XSMAXJDP;
+
+ case 0x91:
+ return PPC_ID_VSX_XSNMSUBASP;
+
+ case 0x92:
+ return PPC_ID_VSX_XXLOR;
+
+ case 0x98:
+ return PPC_ID_VSX_XSMINJDP;
+
+ case 0x99:
+ return PPC_ID_VSX_XSNMSUBMSP;
+
+ case 0x9a:
+ return PPC_ID_VSX_XXLXOR;
+
+ case 0xa0:
+ return PPC_ID_VSX_XSMAXDP;
+
+ case 0xa1:
+ return PPC_ID_VSX_XSNMADDADP;
+
+ case 0xa9:
+ return PPC_ID_VSX_XSNMADDMDP;
+
+ case 0xa2:
+ return PPC_ID_VSX_XXLNOR;
+
+ case 0xa8:
+ return PPC_ID_VSX_XSMINDP;
+
+ case 0xaa:
+ return PPC_ID_VSX_XXLORC;
+
+ case 0xb0:
+ return PPC_ID_VSX_XSCPSGNDP;
+
+ case 0xb1:
+ return PPC_ID_VSX_XSNMSUBADP;
+
+ case 0xb2:
+ return PPC_ID_VSX_XXLNAND;
+
+ case 0xb9:
+ return PPC_ID_VSX_XSNMSUBMDP;
+
+ case 0xba:
+ return PPC_ID_VSX_XXLEQV;
+
+ case 0xc0:
+ return PPC_ID_VSX_XVMAXSP;
+
+ case 0xc1:
+ return PPC_ID_VSX_XVNMADDASP;
+
+ case 0xc8:
+ return PPC_ID_VSX_XVMINSP;
+
+ case 0xc9:
+ return PPC_ID_VSX_XVNMADDMSP;
+
+ case 0xd0:
+ if (vsxA == vsxB)
+ return PPC_ID_VSX_XVMOVSP;
+ else
+ return PPC_ID_VSX_XVCPSGNSP;
+
+ case 0xd1:
+ return PPC_ID_VSX_XVNMSUBASP;
+
+ case 0xd5:
+ case 0xdd:
+ return PPC_ID_VSX_XVTSTDCSP;
+
+ case 0xd8:
+ return PPC_ID_VSX_XVIEXPSP;
+
+ case 0xd9:
+ return PPC_ID_VSX_XVNMSUBMSP;
+
+ case 0xe0:
+ return PPC_ID_VSX_XVMAXDP;
+
+ case 0xe1:
+ return PPC_ID_VSX_XVNMADDADP;
+
+ case 0xe8:
+ return PPC_ID_VSX_XVMINDP;
+
+ case 0xe9:
+ return PPC_ID_VSX_XVNMADDMDP;
+
+ case 0xf0:
+ if (vsxA == vsxB)
+ return PPC_ID_VSX_XVMOVDP;
+ else
+ return PPC_ID_VSX_XVCPSGNDP;
+
+ case 0xf1:
+ return PPC_ID_VSX_XVNMSUBADP;
+
+ case 0xf5:
+ case 0xfd:
+ return PPC_ID_VSX_XVTSTDCDP;
+
+ case 0xf8:
+ return PPC_ID_VSX_XVIEXPDP;
+
+ case 0xf9:
+ return PPC_ID_VSX_XVNMSUBMDP;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+}
+
+static InstructionId DecodeVsx0x3D(uint32_t word32, uint32_t flags)
+{
+ uint32_t subop = word32 & 0x7;
+ switch (subop)
+ {
+ case 1:
+ return PPC_ID_VSX_LXV;
+
+ case 2:
+ case 6:
+ return PPC_ID_VSX_STXSD;
+
+ case 3:
+ case 7:
+ return PPC_ID_VSX_STXSSP;
+
+ case 5:
+ return PPC_ID_VSX_STXV;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+}
+
+static InstructionId Decode0x3F(uint32_t word32, uint32_t flags)
+{
+ uint32_t a = GetA(word32);
+ uint32_t b = GetB(word32);
+
+ uint32_t subop = word32 & 0x3f;
+ switch (subop)
+ {
+ case 0x02e:
+ case 0x02f:
+ return PPC_ID_FSELx;
+
+ case 0x032:
+ case 0x033:
+ if (b != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FMULx;
+
+ case 0x038:
+ case 0x039:
+ return PPC_ID_FMSUBx;
+
+ case 0x03a:
+ case 0x03b:
+ return PPC_ID_FMADDx;
+
+ case 0x03c:
+ case 0x03d:
+ return PPC_ID_FNMSUBx;
+
+ case 0x03e:
+ case 0x03f:
+ return PPC_ID_FNMADDx;
+
+ default:
+ break;
+ }
+
+ subop = word32 & 0x7ff;
+ switch (subop)
+ {
+ case 0x000:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FCMPU;
+
+ case 0x008:
+ case 0x009:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ return PPC_ID_VSX_XSADDQPx;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x00a:
+ case 0x00b:
+ case 0x20a:
+ case 0x20b:
+ case 0x40a:
+ case 0x40b:
+ case 0x60a:
+ case 0x60b:
+ if ((word32 & 0x001e0000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSRQPIx;
+
+ case 0x010:
+ case 0x011:
+ return PPC_ID_FCPSGNx;
+
+ case 0x018:
+ case 0x019:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FRSPx;
+
+ case 0x01c:
+ case 0x01d:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FCTIWx;
+
+ case 0x01e:
+ case 0x01f:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FCTIWZx;
+
+ case 0x024:
+ case 0x025:
+ return PPC_ID_FDIVx;
+
+ case 0x028:
+ case 0x029:
+ return PPC_ID_FSUBx;
+
+ case 0x02a:
+ case 0x02b:
+ return PPC_ID_FADDx;
+
+ case 0x02c:
+ case 0x02d:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FSQRTx;
+
+ case 0x030:
+ case 0x031:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FREx;
+
+ case 0x034:
+ case 0x035:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FRSQRTEx;
+
+ case 0x040:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FCMPO;
+
+ case 0x048:
+ case 0x049:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ return PPC_ID_VSX_XSMULQPx;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x04a:
+ case 0x24a:
+ case 0x44a:
+ case 0x64a:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ {
+ if ((word32 & 0x001e0000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSRQPXP;
+ }
+ else
+ {
+ return PPC_ID_INVALID;
+ }
+
+ case 0x04c:
+ case 0x04d:
+ if ((a != 0) || (b != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MTFSB1x;
+
+ case 0x050:
+ case 0x051:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FNEGx;
+
+ case 0x080:
+ if ((word32 & 0x0063f800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MCRFS;
+
+ case 0x08c:
+ case 0x08d:
+ if ((a != 0) || (b != 0))
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MTFSB0x;
+
+ case 0x090:
+ case 0x091:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FMRx;
+
+ case 0x0c8:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ return PPC_ID_VSX_XSCPSGNQP;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x100:
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FTDIV;
+
+ case 0x108:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ {
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCMPOQP;
+ }
+ else
+ {
+ return PPC_ID_INVALID;
+ }
+
+ case 0x10c:
+ case 0x10d:
+ if ((word32 & 0x007e0800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MTFSFIx;
+
+ case 0x110:
+ case 0x111:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FNABSx;
+
+ case 0x11c:
+ case 0x11d:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FCTIWUx;
+
+ case 0x11e:
+ case 0x11f:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FCTIWUZx;
+
+ case 0x140:
+ if ((word32 & 0x007f0000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FTSQRT;
+
+ case 0x148:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ {
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCMPEXPQP;
+ }
+ else
+ {
+ return PPC_ID_INVALID;
+ }
+
+ case 0x210:
+ case 0x211:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FABSx;
+
+ case 0x308:
+ case 0x309:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ return PPC_ID_VSX_XSMADDQPx;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x310:
+ case 0x311:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FRINx;
+
+ case 0x348:
+ case 0x349:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ return PPC_ID_VSX_XSMSUBQPx;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x350:
+ case 0x351:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FRIZx;
+
+ case 0x388:
+ case 0x389:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ return PPC_ID_VSX_XSNMADDQPx;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x390:
+ case 0x391:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FRIPx;
+
+ case 0x3c8:
+ case 0x3c9:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ return PPC_ID_VSX_XSNMSUBQPx;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x3d0:
+ case 0x3d1:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FRIMx;
+
+ case 0x408:
+ case 0x409:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ return PPC_ID_VSX_XSSUBQPx;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x448:
+ case 0x449:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ return PPC_ID_VSX_XSDIVQPx;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x48e:
+ case 0x48f:
+ {
+ uint32_t subsubop = (word32 >> 16) & 0x1f;
+ switch (subsubop)
+ {
+ case 0x00:
+ if ((word32 & 0x0000f800) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MFFSx;
+
+ case 0x01:
+ if ((word32 & 0x0000f801) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MFFSCE;
+
+ case 0x14:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MFFSCDRN;
+
+ case 0x15:
+ if ((word32 & 0x0000c001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MFFSCDRNI;
+
+ case 0x16:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MFFSCRN;
+
+ case 0x17:
+ if ((word32 & 0x0000e001) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MFFSCRNI;
+
+ case 0x18:
+ if ((word32 & 0x0000f801) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_MFFSL;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+ }
+
+ case 0x508:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ {
+ if ((word32 & 0x00600000) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCMPUQP;
+ }
+ else
+ {
+ return PPC_ID_INVALID;
+ }
+
+ case 0x588:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ return PPC_ID_VSX_XSTSTDCQP;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x58e:
+ case 0x58f:
+ return PPC_ID_MTFSFx;
+
+ case 0x648:
+ case 0x649:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ {
+ uint32_t subsubop = (word32 >> 16) & 0x1f;
+ switch (subsubop)
+ {
+ case 0x00:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSABSQP;
+
+ case 0x02:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSXEXPQP;
+
+ case 0x08:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSNABSQP;
+
+ case 0x10:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSNEGQP;
+
+ case 0x12:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSXSIGQP;
+
+ case 0x1b:
+ return PPC_ID_VSX_XSSQRTQPx;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+ }
+ else
+ {
+ return PPC_ID_INVALID;
+ }
+
+ case 0x65c:
+ case 0x65d:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FCTIDx;
+
+ case 0x65e:
+ case 0x65f:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FCTIDZx;
+
+ case 0x688:
+ case 0x689:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ {
+ uint32_t subsubop = (word32 >> 16) & 0x1f;
+ switch (subsubop)
+ {
+ case 0x01:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVQPUWZ;
+
+ case 0x02:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVUDQP;
+
+ case 0x09:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVQPSWZ;
+
+ case 0x0a:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVSDQP;
+
+ case 0x11:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVQPUDZ;
+
+ case 0x14:
+ return PPC_ID_VSX_XSCVQPDPx;
+
+ case 0x16:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVDPQP;
+
+ case 0x19:
+ if ((word32 & 0x1) != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_VSX_XSCVQPSDZ;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+ }
+ else
+ {
+ return PPC_ID_INVALID;
+ }
+
+ case 0x69c:
+ case 0x69d:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FCFIDx;
+
+ case 0x6c8:
+ if ((flags & DECODE_FLAGS_VSX) != 0)
+ return PPC_ID_VSX_XSIEXPQP;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x75c:
+ case 0x75d:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FCTIDUx;
+
+ case 0x75e:
+ case 0x75f:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FCTIDUZx;
+
+ case 0x79c:
+ case 0x79d:
+ if (a != 0)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_FCFIDUx;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+
+ return true;
+}
+
+InstructionId Decode0x04(uint32_t word32, uint32_t decodeFlags)
+{
+ if ((decodeFlags & DECODE_FLAGS_ALTIVEC))
+ return DecodeAltivec0x04(word32, decodeFlags);
+ else if ((decodeFlags & DECODE_FLAGS_SPE))
+ return DecodeSpe0x04(word32, decodeFlags);
+ else if ((decodeFlags & DECODE_FLAGS_PS))
+ return DecodePairedSingle0x04(word32, decodeFlags);
+ else
+ return PPC_ID_INVALID;
+}
+
+static InstructionId Decode32(uint32_t word32, uint32_t decodeFlags)
+{
+ uint32_t a = GetA(word32);
+
+ uint32_t primary = (word32 >> 26) & 0x3f;
+ switch (primary)
+ {
+ case 0x00:
+ {
+ // "ATTN" instruction documented in section 12.1.1 of
+ // the user manual for the IBM A2 processor
+ if ((word32 & 0x7fe) != 0x200)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_ATTN;
+ }
+
+ case 0x02:
+ {
+ if ((decodeFlags & DECODE_FLAGS_PPC64) == 0)
+ return PPC_ID_INVALID;
+
+ uint32_t to = (word32 >> 21) & 0x1f;
+ switch (to)
+ {
+ case 1: return PPC_ID_TDLGTI;
+ case 2: return PPC_ID_TDLLTI;
+ case 4: return PPC_ID_TDEQI;
+ case 8: return PPC_ID_TDGTI;
+ case 16: return PPC_ID_TDLTI;
+ case 24: return PPC_ID_TDNEI;
+ case 31: return PPC_ID_TDUI;
+ default: return PPC_ID_TDI;
+ }
+ }
+
+ case 0x03:
+ {
+ uint32_t to = (word32 >> 21) & 0x1f;
+
+ switch (to)
+ {
+ case 1: return PPC_ID_TWLGTI;
+ case 2: return PPC_ID_TWLLTI;
+ case 4: return PPC_ID_TWEQI;
+ case 8: return PPC_ID_TWGTI;
+ case 16: return PPC_ID_TWLTI;
+ case 24: return PPC_ID_TWNEI;
+ case 31: return PPC_ID_TWUI;
+ default: return PPC_ID_TWI;
+ }
+ }
+
+ case 0x04:
+ {
+ return Decode0x04(word32, decodeFlags);
+ }
+
+ case 0x07:
+ return PPC_ID_MULLI;
+
+ case 0x08:
+ return PPC_ID_SUBFICx;
+
+
+ case 0x0a:
+ if ((word32 & 0x00400000) == 0)
+ {
+ if ((word32 & 0x00200000) != 0)
+ {
+ if ((decodeFlags & DECODE_FLAGS_PPC64) != 0)
+ return PPC_ID_CMPLDI;
+ else
+ return PPC_ID_INVALID;
+ }
+ else
+ {
+ return PPC_ID_CMPLWI;
+ }
+ }
+
+ return PPC_ID_INVALID;
+
+ case 0x0b:
+ if ((word32 & 0x00400000) == 0)
+ {
+ if ((word32 & 0x00200000) != 0)
+ {
+ if ((decodeFlags & DECODE_FLAGS_PPC64) != 0)
+ return PPC_ID_CMPDI;
+ else
+ return PPC_ID_INVALID;
+
+ }
+ else
+ {
+ return PPC_ID_CMPWI;
+ }
+ }
+
+ return PPC_ID_INVALID;
+
+ case 0x0c:
+ return PPC_ID_ADDICx;
+
+ case 0x0d:
+ return PPC_ID_ADDICx;
+
+ case 0x0e:
+ if (a == 0)
+ return PPC_ID_LI;
+ else
+ return PPC_ID_ADDIx;
+
+ case 0x0f:
+ if (a == 0)
+ return PPC_ID_LIS;
+ else
+ return PPC_ID_ADDIS;
+
+ case 0x10:
+ return PPC_ID_BCx;
+
+ case 0x11:
+ if ((word32 & 0x03fff01f) != 2)
+ return PPC_ID_INVALID;
+
+ return PPC_ID_SC;
+
+ case 0x12:
+ return PPC_ID_Bx;
+
+ case 0x13:
+ return Decode0x13(word32, decodeFlags);
+
+ case 0x14:
+ return PPC_ID_RLWIMIx;
+
+ case 0x15:
+ {
+ uint32_t me = GetME(word32);
+ uint32_t mb = GetMB(word32);
+ uint32_t sh = GetSH(word32);
+
+ if (mb == 0 && ((sh + me) == 31))
+ return PPC_ID_SLWIx;
+ else if (mb == 0 && me == 31)
+ return PPC_ID_ROTLWIx;
+ else if (me == 31 && ((sh + mb) == 32))
+ return PPC_ID_SRWIx;
+ else if (sh == 0 && mb == 0)
+ return PPC_ID_CLRRWIx;
+ else if (sh == 0 && me == 31)
+ return PPC_ID_CLRLWIx;
+ else
+ return PPC_ID_RLWINMx;
+ }
+
+ case 0x17:
+ {
+ uint32_t me = GetME(word32);
+ uint32_t mb = GetMB(word32);
+
+ if (mb == 0 && me == 31)
+ return PPC_ID_ROTLWx;
+ else
+ return PPC_ID_RLWNMx;
+ }
+
+ case 0x18:
+ if (word32 == 0x60000000)
+ return PPC_ID_NOP;
+ else
+ return PPC_ID_ORIx;
+
+ case 0x19:
+ return PPC_ID_ORIS;
+
+ case 0x1a:
+ if (word32 == 0x68000000)
+ return PPC_ID_XNOP;
+ else
+ return PPC_ID_XORIx;
+
+ case 0x1b:
+ return PPC_ID_XORIS;
+
+ case 0x1c:
+ return PPC_ID_ANDIx;
+
+ case 0x1d:
+ return PPC_ID_ANDIS;
+
+ case 0x1e:
+ if ((decodeFlags & DECODE_FLAGS_PPC64) == 0)
+ return PPC_ID_INVALID;
+
+ return Decode0x1E(word32, decodeFlags);
+
+ case 0x1f:
+ return Decode0x1F(word32, decodeFlags);
+
+ case 0x20:
+ return PPC_ID_LWZ;
+
+ case 0x21:
+ return PPC_ID_LWZU;
+
+ case 0x22:
+ return PPC_ID_LBZ;
+
+ case 0x23:
+ return PPC_ID_LBZU;
+
+ case 0x24:
+ return PPC_ID_STW;
+
+ case 0x25:
+ return PPC_ID_STWU;
+
+ case 0x26:
+ return PPC_ID_STB;
+
+ case 0x27:
+ return PPC_ID_STBU;
+
+ case 0x28:
+ return PPC_ID_LHZ;
+
+ case 0x29:
+ return PPC_ID_LHZU;
+
+ case 0x2a:
+ return PPC_ID_LHA;
+
+ case 0x2b:
+ return PPC_ID_LHAU;
+
+ case 0x2c:
+ return PPC_ID_STH;
+
+ case 0x2d:
+ return PPC_ID_STHU;
+
+ case 0x2e:
+ return PPC_ID_LMW;
+
+ case 0x2f:
+ return PPC_ID_STMW;
+
+ case 0x30:
+ return PPC_ID_LFS;
+
+ case 0x31:
+ return PPC_ID_LFSU;
+
+ case 0x32:
+ return PPC_ID_LFD;
+
+ case 0x33:
+ return PPC_ID_LFDU;
+
+ case 0x34:
+ return PPC_ID_STFS;
+
+ case 0x35:
+ return PPC_ID_STFSU;
+
+ case 0x36:
+ return PPC_ID_STFD;
+
+ case 0x37:
+ return PPC_ID_STFDU;
+
+ case 0x38:
+ if ((decodeFlags & DECODE_FLAGS_PS) != 0)
+ return PPC_ID_PAIREDSINGLE_PSQ_L;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x39:
+ if ((decodeFlags & DECODE_FLAGS_VSX) != 0)
+ return DecodeVsx0x39(word32, decodeFlags);
+ else if ((decodeFlags & DECODE_FLAGS_PS) != 0)
+ return PPC_ID_PAIREDSINGLE_PSQ_LU;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x3a:
+ if ((decodeFlags & DECODE_FLAGS_PPC64) == 0)
+ return PPC_ID_INVALID;
+
+ switch (word32 & 0x3)
+ {
+ case 0: return PPC_ID_LD;
+ case 1: return PPC_ID_LDU;
+ case 2: return PPC_ID_LWA;
+ default: return PPC_ID_INVALID;
+ }
+
+ case 0x3b:
+ return Decode0x3B(word32, decodeFlags);
+
+ case 0x3c:
+ if ((decodeFlags & DECODE_FLAGS_VSX) != 0)
+ return DecodeVsx0x3C(word32, decodeFlags);
+ else if ((decodeFlags & DECODE_FLAGS_PS) != 0)
+ return PPC_ID_PAIREDSINGLE_PSQ_ST;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x3d:
+ if ((decodeFlags & DECODE_FLAGS_VSX) != 0)
+ return DecodeVsx0x3D(word32, decodeFlags);
+ else if ((decodeFlags & DECODE_FLAGS_PS) != 0)
+ return PPC_ID_PAIREDSINGLE_PSQ_STU;
+ else
+ return PPC_ID_INVALID;
+
+ case 0x3e:
+ if ((decodeFlags & DECODE_FLAGS_PPC64) == 0)
+ return PPC_ID_INVALID;
+
+ switch (word32 & 0x3)
+ {
+ case 0: return PPC_ID_STD;
+ case 1: return PPC_ID_STDU;
+ default: return PPC_ID_INVALID;
+ }
+
+ case 0x3f:
+ return Decode0x3F(word32, decodeFlags);
+
+ default:
+ return PPC_ID_INVALID;
+ }
+}
+
+bool Decompose16(Instruction* instruction, uint16_t word16, uint64_t address, uint32_t flags)
+{
+ size_t numBytes = instruction->numBytes;
+ memset(instruction, 0, sizeof *instruction);
+ instruction->numBytes = numBytes;
+ if ((flags & DECODE_FLAGS_VLE) != 0)
+ return Decompose16Vle(instruction, word16, address, flags);
+ else
+ return false;
+}
+
+bool Decompose32(Instruction* instruction, uint32_t word32, uint64_t address, uint32_t flags)
+{
+ size_t numBytes = instruction->numBytes;
+ memset(instruction, 0, sizeof *instruction);
+ instruction->numBytes = numBytes;
+
+ if ((flags & DECODE_FLAGS_VLE) != 0)
+ return Decompose32Vle(instruction, word32, address, flags);
+
+ instruction->id = Decode32(word32, flags);
+ if (instruction->id == PPC_ID_INVALID)
+ return false;
+
+ FillOperands32(instruction, word32, address);
+ return true;
+}
+
+size_t VleGetInstructionLength(const uint8_t* data, size_t data_length, uint32_t decodeFlags)
+{
+ if (data_length == 0)
+ return 0;
+
+ switch (data[0] & 0xfc)
+ {
+ case 0x10:
+ case 0x18:
+ case 0x1c:
+ case 0x30:
+ case 0x34:
+ case 0x38:
+ case 0x50:
+ case 0x54:
+ case 0x58:
+ case 0x5c:
+ case 0x70:
+ case 0x74:
+ case 0x78:
+ case 0x7c:
+ return 4;
+
+ default:
+ return 2;
+ }
+}
+
diff --git a/arch/powerpc/decode/decode.h b/arch/powerpc/decode/decode.h
new file mode 100644
index 00000000..f88fd50a
--- /dev/null
+++ b/arch/powerpc/decode/decode.h
@@ -0,0 +1,1901 @@
+#ifndef DECODE_PPC_H
+#define DECODE_PPC_H
+
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+// Procedure for adding a new instruction:
+// * Add its enum to the InstructionId in this file (decode.h)
+// * Add logic to convert instruction bits to the new instruction in decode.c
+// * Add its mnemonic in `GetMnemonic` in `mnemonic.c`
+// * Add its operands in `FillOperands` in `operands.c`
+//
+// This only handles instruction decoding (going from bits --> a powerpc
+// instruction), and not anything like lifting or the behavior of the
+// instruction itself.
+
+#define DECODE_FLAGS_PPC64 0x01
+#define DECODE_FLAGS_ALTIVEC 0x02
+#define DECODE_FLAGS_VSX 0x04
+#define DECODE_FLAGS_QPX 0x08
+#define DECODE_FLAGS_PS 0x10
+#define DECODE_FLAGS_SPE 0x20
+#define DECODE_FLAGS_VLE 0x40
+// When set, disassembly translates to a "normal" PowerPC instruction, which
+// usually amounts to simply dropping the "e_"/"se_" prefix and adding an extra
+// register (changing rX, rY --> rD, rA, rB) , but sometimes totally change the
+// instruction (for example, replacing `se_bgeni` with `li`)
+//
+// Should always be set in `flags` for LLIL, to maximize code reuse
+#define DECODE_FLAGS_VLE_TRANSLATE 0x80
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ enum Register
+ {
+
+ PPC_REG_INVALID = 0,
+
+ PPC_REG_CARRY = 2,
+ PPC_REG_CTR = 3,
+ PPC_REG_LR = 5,
+ PPC_REG_RM = 6,
+ PPC_REG_VRSAVE = 8,
+ PPC_REG_XER = 9,
+ PPC_REG_ZERO = 10,
+ PPC_REG_CTR8 = 20,
+
+ PPC_REG_GPR0 = 87,
+ PPC_REG_GPR1,
+ PPC_REG_GPR2,
+ PPC_REG_GPR3,
+ PPC_REG_GPR4,
+ PPC_REG_GPR5,
+ PPC_REG_GPR6,
+ PPC_REG_GPR7,
+ PPC_REG_GPR8,
+ PPC_REG_GPR9,
+ PPC_REG_GPR10,
+ PPC_REG_GPR11,
+ PPC_REG_GPR12,
+ PPC_REG_GPR13,
+ PPC_REG_GPR14,
+ PPC_REG_GPR15,
+ PPC_REG_GPR16,
+ PPC_REG_GPR17,
+ PPC_REG_GPR18,
+ PPC_REG_GPR19,
+ PPC_REG_GPR20,
+ PPC_REG_GPR21,
+ PPC_REG_GPR22,
+ PPC_REG_GPR23,
+ PPC_REG_GPR24,
+ PPC_REG_GPR25,
+ PPC_REG_GPR26,
+ PPC_REG_GPR27,
+ PPC_REG_GPR28,
+ PPC_REG_GPR29,
+ PPC_REG_GPR30,
+ PPC_REG_GPR31,
+
+ PPC_REG_FR0 = 21,
+ PPC_REG_FR1,
+ PPC_REG_FR2,
+ PPC_REG_FR3,
+ PPC_REG_FR4,
+ PPC_REG_FR5,
+ PPC_REG_FR6,
+ PPC_REG_FR7,
+ PPC_REG_FR8,
+ PPC_REG_FR9,
+ PPC_REG_FR10,
+ PPC_REG_FR11,
+ PPC_REG_FR12,
+ PPC_REG_FR13,
+ PPC_REG_FR14,
+ PPC_REG_FR15,
+ PPC_REG_FR16,
+ PPC_REG_FR17,
+ PPC_REG_FR18,
+ PPC_REG_FR19,
+ PPC_REG_FR20,
+ PPC_REG_FR21,
+ PPC_REG_FR22,
+ PPC_REG_FR23,
+ PPC_REG_FR24,
+ PPC_REG_FR25,
+ PPC_REG_FR26,
+ PPC_REG_FR27,
+ PPC_REG_FR28,
+ PPC_REG_FR29,
+ PPC_REG_FR30,
+ PPC_REG_FR31,
+
+ // each 4-bit CR register
+ PPC_REG_CRF0 = 12,
+ PPC_REG_CRF1,
+ PPC_REG_CRF2,
+ PPC_REG_CRF3,
+ PPC_REG_CRF4,
+ PPC_REG_CRF5,
+ PPC_REG_CRF6,
+ PPC_REG_CRF7,
+
+ PPC_REG_AV_VR0 = 121,
+ PPC_REG_AV_VR1,
+ PPC_REG_AV_VR2,
+ PPC_REG_AV_VR3,
+ PPC_REG_AV_VR4,
+ PPC_REG_AV_VR5,
+ PPC_REG_AV_VR6,
+ PPC_REG_AV_VR7,
+ PPC_REG_AV_VR8,
+ PPC_REG_AV_VR9,
+ PPC_REG_AV_VR10,
+ PPC_REG_AV_VR11,
+ PPC_REG_AV_VR12,
+ PPC_REG_AV_VR13,
+ PPC_REG_AV_VR14,
+ PPC_REG_AV_VR15,
+ PPC_REG_AV_VR16,
+ PPC_REG_AV_VR17,
+ PPC_REG_AV_VR18,
+ PPC_REG_AV_VR19,
+ PPC_REG_AV_VR20,
+ PPC_REG_AV_VR21,
+ PPC_REG_AV_VR22,
+ PPC_REG_AV_VR23,
+ PPC_REG_AV_VR24,
+ PPC_REG_AV_VR25,
+ PPC_REG_AV_VR26,
+ PPC_REG_AV_VR27,
+ PPC_REG_AV_VR28,
+ PPC_REG_AV_VR29,
+ PPC_REG_AV_VR30,
+ PPC_REG_AV_VR31,
+
+ PPC_REG_VSX_VR0 = 215,
+ PPC_REG_VSX_VR1,
+ PPC_REG_VSX_VR2,
+ PPC_REG_VSX_VR3,
+ PPC_REG_VSX_VR4,
+ PPC_REG_VSX_VR5,
+ PPC_REG_VSX_VR6,
+ PPC_REG_VSX_VR7,
+ PPC_REG_VSX_VR8,
+ PPC_REG_VSX_VR9,
+ PPC_REG_VSX_VR10,
+ PPC_REG_VSX_VR11,
+ PPC_REG_VSX_VR12,
+ PPC_REG_VSX_VR13,
+ PPC_REG_VSX_VR14,
+ PPC_REG_VSX_VR15,
+ PPC_REG_VSX_VR16,
+ PPC_REG_VSX_VR17,
+ PPC_REG_VSX_VR18,
+ PPC_REG_VSX_VR19,
+ PPC_REG_VSX_VR20,
+ PPC_REG_VSX_VR21,
+ PPC_REG_VSX_VR22,
+ PPC_REG_VSX_VR23,
+ PPC_REG_VSX_VR24,
+ PPC_REG_VSX_VR25,
+ PPC_REG_VSX_VR26,
+ PPC_REG_VSX_VR27,
+ PPC_REG_VSX_VR28,
+ PPC_REG_VSX_VR29,
+ PPC_REG_VSX_VR30,
+ PPC_REG_VSX_VR31,
+ PPC_REG_VSX_VR32,
+ PPC_REG_VSX_VR33,
+ PPC_REG_VSX_VR34,
+ PPC_REG_VSX_VR35,
+ PPC_REG_VSX_VR36,
+ PPC_REG_VSX_VR37,
+ PPC_REG_VSX_VR38,
+ PPC_REG_VSX_VR39,
+ PPC_REG_VSX_VR40,
+ PPC_REG_VSX_VR41,
+ PPC_REG_VSX_VR42,
+ PPC_REG_VSX_VR43,
+ PPC_REG_VSX_VR44,
+ PPC_REG_VSX_VR45,
+ PPC_REG_VSX_VR46,
+ PPC_REG_VSX_VR47,
+ PPC_REG_VSX_VR48,
+ PPC_REG_VSX_VR49,
+ PPC_REG_VSX_VR50,
+ PPC_REG_VSX_VR51,
+ PPC_REG_VSX_VR52,
+ PPC_REG_VSX_VR53,
+ PPC_REG_VSX_VR54,
+ PPC_REG_VSX_VR55,
+ PPC_REG_VSX_VR56,
+ PPC_REG_VSX_VR57,
+ PPC_REG_VSX_VR58,
+ PPC_REG_VSX_VR59,
+ PPC_REG_VSX_VR60,
+ PPC_REG_VSX_VR61,
+ PPC_REG_VSX_VR62,
+ PPC_REG_VSX_VR63,
+
+ PPC_REG_GQR0 = 345,
+ PPC_REG_GQR1,
+ PPC_REG_GQR2,
+ PPC_REG_GQR3,
+ PPC_REG_GQR4,
+ PPC_REG_GQR5,
+ PPC_REG_GQR6,
+ PPC_REG_GQR7,
+ };
+
+#ifndef __cplusplus
+ typedef enum Register Register;
+#endif
+
+ enum OperandClass
+ {
+ PPC_OP_NONE = 0,
+ PPC_OP_UIMM,
+ PPC_OP_SIMM,
+ PPC_OP_LABEL,
+ PPC_OP_MEM_RA,
+
+ PPC_OP_REG_RA,
+ PPC_OP_REG_RB,
+ PPC_OP_REG_RC,
+ PPC_OP_REG_RD,
+ PPC_OP_REG_RS,
+
+ PPC_OP_REG_FRA,
+ PPC_OP_REG_FRB,
+ PPC_OP_REG_FRC,
+ PPC_OP_REG_FRD,
+ PPC_OP_REG_FRS,
+
+ PPC_OP_REG_CRFD,
+ PPC_OP_REG_CRFD_IMPLY0,
+ PPC_OP_REG_CRFS,
+ PPC_OP_REG_CRFS_IMPLY0,
+ PPC_OP_CRBIT,
+ PPC_OP_CRBIT_A,
+ PPC_OP_CRBIT_B,
+ PPC_OP_CRBIT_D,
+
+ PPC_OP_REG_AV_VA,
+ PPC_OP_REG_AV_VB,
+ PPC_OP_REG_AV_VC,
+ PPC_OP_REG_AV_VD,
+ PPC_OP_REG_AV_VS,
+
+ // DWORD0 means that only the 0th dword is affected, which
+ // has an overlap with floating registers
+ PPC_OP_REG_VSX_RA,
+ PPC_OP_REG_VSX_RA_DWORD0,
+
+ PPC_OP_REG_VSX_RB,
+ PPC_OP_REG_VSX_RB_DWORD0,
+
+ PPC_OP_REG_VSX_RC,
+ PPC_OP_REG_VSX_RC_DWORD0,
+
+ PPC_OP_REG_VSX_RD,
+ PPC_OP_REG_VSX_RD_DWORD0,
+
+ PPC_OP_REG_VSX_RS,
+ PPC_OP_REG_VSX_RS_DWORD0,
+ };
+
+#ifndef __cplusplus
+ typedef enum OperandClass OperandClass;
+#endif
+
+ enum VsxWidth
+ {
+ VSX_WIDTH_FULL,
+ VSX_WIDTH_DWORD0,
+ };
+
+#ifndef __cplusplus
+ typedef enum VsxWidth VsxWidth;
+#endif
+
+ struct MemoryOperand
+ {
+ enum Register reg;
+ int32_t offset;
+ };
+
+#ifndef __cplusplus
+ typedef struct MemoryOperand MemoryOperand;
+#endif
+
+ struct Operand
+ {
+ OperandClass cls;
+ union {
+ enum Register reg;
+ uint64_t uimm;
+ int64_t simm;
+ MemoryOperand mem;
+ uint64_t label;
+ uint32_t crbit;
+ };
+ };
+
+#ifndef __cplusplus
+ typedef struct Operand Operand;
+#endif
+
+ struct OperandsList
+ {
+ size_t numOperands;
+ Operand operands[8];
+ };
+
+#ifndef __cplusplus
+ typedef struct OperandsList OperandsList;
+#endif
+
+ // trailing lowercase 'x' indicates potential other mnemonics (rc, oe, lk,
+ // etc. bits)
+ enum InstructionId
+ {
+ PPC_ID_INVALID,
+
+ PPC_ID_ADDx,
+ PPC_ID_ADDCx,
+ PPC_ID_ADDEx,
+ PPC_ID_ADDIx,
+ PPC_ID_ADDICx,
+ PPC_ID_ADDIS,
+ PPC_ID_ADDMEx,
+ PPC_ID_ADDPCIS,
+ PPC_ID_ADDZEx,
+ PPC_ID_ANDx,
+ PPC_ID_ANDCx,
+ PPC_ID_ANDIx,
+ PPC_ID_ANDIS,
+ PPC_ID_ATTN,
+ PPC_ID_Bx,
+ PPC_ID_BCx,
+ PPC_ID_BCCTRx,
+ PPC_ID_BCLRx,
+ PPC_ID_BPERMD,
+ PPC_ID_CLRBHRB,
+ PPC_ID_CLRLDIx,
+ PPC_ID_CLRRDIx,
+ PPC_ID_CLRLWIx,
+ PPC_ID_CLRRWIx,
+ PPC_ID_CMPB,
+ PPC_ID_CMPD,
+ PPC_ID_CMPDI,
+ PPC_ID_CMPEQB,
+ PPC_ID_CMPRB,
+ PPC_ID_CMPW,
+ PPC_ID_CMPWI,
+ PPC_ID_CMPLD,
+ PPC_ID_CMPLDI,
+ PPC_ID_CMPLW,
+ PPC_ID_CMPLWI,
+ PPC_ID_CNTLZDx,
+ PPC_ID_CNTLZWx,
+ PPC_ID_CNTTZDx,
+ PPC_ID_CNTTZWx,
+ PPC_ID_COPY,
+ PPC_ID_CP_ABORT,
+ PPC_ID_CRAND,
+ PPC_ID_CRANDC,
+ PPC_ID_CRCLR,
+ PPC_ID_CREQV,
+ PPC_ID_CRMOVE,
+ PPC_ID_CRNAND,
+ PPC_ID_CRNOR,
+ PPC_ID_CRNOT,
+ PPC_ID_CROR,
+ PPC_ID_CRORC,
+ PPC_ID_CRSET,
+ PPC_ID_CRXOR,
+ PPC_ID_DARN,
+ PPC_ID_DCBA,
+ PPC_ID_DCBF,
+ PPC_ID_DCBFEP,
+ PPC_ID_DCBFL,
+ PPC_ID_DCBFLP,
+ PPC_ID_DCBI,
+ PPC_ID_DCBST,
+ PPC_ID_DCBSTEP,
+ PPC_ID_DCBT,
+ PPC_ID_DCBTEP,
+ PPC_ID_DCBTST,
+ PPC_ID_DCBTSTEP,
+ PPC_ID_DCBTSTT,
+ PPC_ID_DCBTT,
+ PPC_ID_DCBZ,
+ PPC_ID_DCBZEP,
+ PPC_ID_DCBZL,
+ PPC_ID_DCBZLEP,
+ PPC_ID_DCCCI,
+ PPC_ID_DCI,
+ PPC_ID_DIVDx,
+ PPC_ID_DIVDEx,
+ PPC_ID_DIVDEUx,
+ PPC_ID_DIVDUx,
+ PPC_ID_DIVWx,
+ PPC_ID_DIVWEx,
+ PPC_ID_DIVWEUx,
+ PPC_ID_DIVWUx,
+ PPC_ID_ECIWX,
+ PPC_ID_ECOWX,
+ PPC_ID_EIEIO,
+ PPC_ID_EQVx,
+ PPC_ID_EXTLDIx,
+ PPC_ID_EXTLWIx,
+ PPC_ID_EXTRDIx,
+ PPC_ID_EXTRWIx,
+ PPC_ID_EXTSBx,
+ PPC_ID_EXTSHx,
+ PPC_ID_EXTSWx,
+ PPC_ID_EXTSWSLIx,
+ PPC_ID_FABSx,
+ PPC_ID_FADDx,
+ PPC_ID_FADDSx,
+ PPC_ID_FCFIDx,
+ PPC_ID_FCFIDSx,
+ PPC_ID_FCFIDUx,
+ PPC_ID_FCFIDUSx,
+ PPC_ID_FCMPO,
+ PPC_ID_FCMPU,
+ PPC_ID_FCPSGNx,
+ PPC_ID_FCTIDx,
+ PPC_ID_FCTIDUx,
+ PPC_ID_FCTIDUZx,
+ PPC_ID_FCTIDZx,
+ PPC_ID_FCTIWx,
+ PPC_ID_FCTIWUx,
+ PPC_ID_FCTIWUZx,
+ PPC_ID_FCTIWZx,
+ PPC_ID_FDIVx,
+ PPC_ID_FDIVSx,
+ PPC_ID_FMADDx,
+ PPC_ID_FMADDSx,
+ PPC_ID_FMRx,
+ PPC_ID_FMSUBx,
+ PPC_ID_FMSUBSx,
+ PPC_ID_FMULx,
+ PPC_ID_FMULSx,
+ PPC_ID_FNABSx,
+ PPC_ID_FNEGx,
+ PPC_ID_FNMADDx,
+ PPC_ID_FNMADDSx,
+ PPC_ID_FNMSUBx,
+ PPC_ID_FNMSUBSx,
+ PPC_ID_FREx,
+ PPC_ID_FRESx,
+ PPC_ID_FRIMx,
+ PPC_ID_FRINx,
+ PPC_ID_FRIPx,
+ PPC_ID_FRIZx,
+ PPC_ID_FRSPx,
+ PPC_ID_FRSQRTEx,
+ PPC_ID_FRSQRTESx,
+ PPC_ID_FSELx,
+ PPC_ID_FSQRTx,
+ PPC_ID_FSQRTSx,
+ PPC_ID_FSUBx,
+ PPC_ID_FSUBSx,
+ PPC_ID_FTDIV,
+ PPC_ID_FTSQRT,
+ PPC_ID_HRFID,
+ PPC_ID_ICBI,
+ PPC_ID_ICBIEP,
+ PPC_ID_ICBLC,
+ PPC_ID_ICBLQ,
+ PPC_ID_ICBT,
+ PPC_ID_ICBTLS,
+ PPC_ID_ICCCI,
+ PPC_ID_ICI,
+ PPC_ID_ISEL,
+ PPC_ID_ISYNC,
+ PPC_ID_LBARX,
+ PPC_ID_LBEPX,
+ PPC_ID_LBZ,
+ PPC_ID_LBZCIX,
+ PPC_ID_LBZU,
+ PPC_ID_LBZUX,
+ PPC_ID_LBZX,
+ PPC_ID_LD,
+ PPC_ID_LDAT,
+ PPC_ID_LDARX,
+ PPC_ID_LDBRX,
+ PPC_ID_LDCIX,
+ PPC_ID_LDU,
+ PPC_ID_LDUX,
+ PPC_ID_LDX,
+ PPC_ID_LFD,
+ PPC_ID_LFDEPX,
+ PPC_ID_LFDU,
+ PPC_ID_LFDUX,
+ PPC_ID_LFDX,
+ PPC_ID_LFIWAX,
+ PPC_ID_LFIWZX,
+ PPC_ID_LFS,
+ PPC_ID_LFSU,
+ PPC_ID_LFSUX,
+ PPC_ID_LFSX,
+ PPC_ID_LHA,
+ PPC_ID_LHAU,
+ PPC_ID_LHAUX,
+ PPC_ID_LHAX,
+ PPC_ID_LHARX,
+ PPC_ID_LHBRX,
+ PPC_ID_LHEPX,
+ PPC_ID_LHZ,
+ PPC_ID_LHZCIX,
+ PPC_ID_LHZU,
+ PPC_ID_LHZUX,
+ PPC_ID_LHZX,
+ PPC_ID_LI,
+ PPC_ID_LIS,
+ PPC_ID_LMW,
+ PPC_ID_LNIA,
+ PPC_ID_LSWI,
+ PPC_ID_LSWX,
+ PPC_ID_LWA,
+ PPC_ID_LWAT,
+ PPC_ID_LWAX,
+ PPC_ID_LWARX,
+ PPC_ID_LWAUX,
+ PPC_ID_LWBRX,
+ PPC_ID_LWEPX,
+ PPC_ID_LWSYNC,
+ PPC_ID_LWZ,
+ PPC_ID_LWZCIX,
+ PPC_ID_LWZU,
+ PPC_ID_LWZUX,
+ PPC_ID_LWZX,
+ PPC_ID_MBAR,
+ PPC_ID_MCRF,
+ PPC_ID_MCRFS,
+ PPC_ID_MCRXR,
+ PPC_ID_MCRXRX,
+ PPC_ID_MFBHRBE,
+ PPC_ID_MFBR0,
+ PPC_ID_MFBR1,
+ PPC_ID_MFBR2,
+ PPC_ID_MFBR3,
+ PPC_ID_MFBR4,
+ PPC_ID_MFBR5,
+ PPC_ID_MFBR6,
+ PPC_ID_MFBR7,
+ PPC_ID_MFCR,
+ PPC_ID_MFCTR,
+ PPC_ID_MFDCR,
+ PPC_ID_MFDCRUX,
+ PPC_ID_MFDCRX,
+ PPC_ID_MFFSx,
+ PPC_ID_MFFSCDRN,
+ PPC_ID_MFFSCDRNI,
+ PPC_ID_MFFSCE,
+ PPC_ID_MFFSCRN,
+ PPC_ID_MFFSCRNI,
+ PPC_ID_MFFSL,
+ PPC_ID_MFLR,
+ PPC_ID_MFMSR,
+ PPC_ID_MFOCRF,
+ PPC_ID_MFPMR,
+ PPC_ID_MFSPR,
+ PPC_ID_MFSR,
+ PPC_ID_MFSRIN,
+ PPC_ID_MFTB,
+ PPC_ID_MFTBU,
+ PPC_ID_MFXER,
+ PPC_ID_MRx,
+ PPC_ID_MSGSYNC,
+ PPC_ID_MTAMR,
+ PPC_ID_MTBR0,
+ PPC_ID_MTBR1,
+ PPC_ID_MTBR2,
+ PPC_ID_MTBR3,
+ PPC_ID_MTBR4,
+ PPC_ID_MTBR5,
+ PPC_ID_MTBR6,
+ PPC_ID_MTBR7,
+ PPC_ID_MTCFAR,
+ PPC_ID_MTCRF,
+ PPC_ID_MTCTR,
+ PPC_ID_MTDAR,
+ PPC_ID_MTDCCR,
+ PPC_ID_MTDCR,
+ PPC_ID_MTDCRUX,
+ PPC_ID_MTDCRX,
+ PPC_ID_MTFSB0x,
+ PPC_ID_MTFSB1x,
+ PPC_ID_MTFSFx,
+ PPC_ID_MTFSFIx,
+ PPC_ID_MODSD,
+ PPC_ID_MODSW,
+ PPC_ID_MODUD,
+ PPC_ID_MODUW,
+ PPC_ID_MTICCR,
+ PPC_ID_MTLR,
+ PPC_ID_MTMSR,
+ PPC_ID_MTMSRD,
+ PPC_ID_MTOCRF,
+ PPC_ID_MTPMR,
+ PPC_ID_MTSPR,
+ PPC_ID_MTSR,
+ PPC_ID_MTSRIN,
+ PPC_ID_MTSRR2,
+ PPC_ID_MTSRR3,
+ PPC_ID_MTTBHI,
+ PPC_ID_MTTBL,
+ PPC_ID_MTTBU,
+ PPC_ID_MTXER,
+ PPC_ID_MULHDx,
+ PPC_ID_MULHDUx,
+ PPC_ID_MULHWx,
+ PPC_ID_MULHWUx,
+ PPC_ID_MULLDx,
+ PPC_ID_MULLI,
+ PPC_ID_MULLWx,
+ PPC_ID_NAP,
+ PPC_ID_NANDx,
+ PPC_ID_NEGx,
+ PPC_ID_NOP,
+ PPC_ID_NORx,
+ PPC_ID_ORx,
+ PPC_ID_ORCx,
+ PPC_ID_ORIx,
+ PPC_ID_ORIS,
+ PPC_ID_PASTE,
+ PPC_ID_POPCNTB,
+ PPC_ID_POPCNTD,
+ PPC_ID_POPCNTW,
+ PPC_ID_PTESYNC,
+ PPC_ID_RFCI,
+ PPC_ID_RFDI,
+ PPC_ID_RFEBB,
+ PPC_ID_RFI,
+ PPC_ID_RFID,
+ PPC_ID_RFMCI,
+ PPC_ID_RLDICLx,
+ PPC_ID_RLDICRx,
+ PPC_ID_RLDICx,
+ PPC_ID_RLDIMIx,
+ PPC_ID_RLDCLx,
+ PPC_ID_RLDCRx,
+ PPC_ID_RLWIMIx,
+ PPC_ID_RLWINMx,
+ PPC_ID_RLWNMx,
+ PPC_ID_ROTLDx,
+ PPC_ID_ROTLDIx,
+ PPC_ID_ROTLWx,
+ PPC_ID_ROTLWIx,
+ PPC_ID_ROTRDIx,
+ PPC_ID_ROTRWIx,
+ PPC_ID_SC,
+ PPC_ID_SETB,
+ PPC_ID_SLBIA,
+ PPC_ID_SLBIE,
+ PPC_ID_SLBIEG,
+ PPC_ID_SLBMFEE,
+ PPC_ID_SLBMFEV,
+ PPC_ID_SLBMTE,
+ PPC_ID_SLBSYNC,
+ PPC_ID_SLDx,
+ PPC_ID_SLDIx,
+ PPC_ID_SLWx,
+ PPC_ID_SLWIx,
+ PPC_ID_SRADx,
+ PPC_ID_SRADIx,
+ PPC_ID_SRAWx,
+ PPC_ID_SRAWIx,
+ PPC_ID_SRDx,
+ PPC_ID_SRDIx,
+ PPC_ID_SRWx,
+ PPC_ID_SRWIx,
+ PPC_ID_STB,
+ PPC_ID_STBCX,
+ PPC_ID_STBU,
+ PPC_ID_STBUX,
+ PPC_ID_STBX,
+ PPC_ID_STBCIX,
+ PPC_ID_STBEPX,
+ PPC_ID_STD,
+ PPC_ID_STDAT,
+ PPC_ID_STDBRX,
+ PPC_ID_STDCIX,
+ PPC_ID_STDCX,
+ PPC_ID_STDEPX,
+ PPC_ID_STDU,
+ PPC_ID_STDUX,
+ PPC_ID_STDX,
+ PPC_ID_STFD,
+ PPC_ID_STFDEPX,
+ PPC_ID_STFDU,
+ PPC_ID_STFDUX,
+ PPC_ID_STFDX,
+ PPC_ID_STFIWX,
+ PPC_ID_STFS,
+ PPC_ID_STFSU,
+ PPC_ID_STFSUX,
+ PPC_ID_STFSX,
+ PPC_ID_STH,
+ PPC_ID_STHBRX,
+ PPC_ID_STHCX,
+ PPC_ID_STHCIX,
+ PPC_ID_STHEPX,
+ PPC_ID_STHU,
+ PPC_ID_STHUX,
+ PPC_ID_STHX,
+ PPC_ID_STMW,
+ PPC_ID_STOP,
+ PPC_ID_STSWI,
+ PPC_ID_STSWX,
+ PPC_ID_STW,
+ PPC_ID_STWAT,
+ PPC_ID_STWBRX,
+ PPC_ID_STWCIX,
+ PPC_ID_STWCX,
+ PPC_ID_STWEPX,
+ PPC_ID_STWU,
+ PPC_ID_STWUX,
+ PPC_ID_STWX,
+ PPC_ID_SUBFx,
+ PPC_ID_SUBFCx,
+ PPC_ID_SUBFEx,
+ PPC_ID_SUBFICx,
+ PPC_ID_SUBFMEx,
+ PPC_ID_SUBFZEx,
+ PPC_ID_SYNC,
+ PPC_ID_TABORT,
+ PPC_ID_TABORTDC,
+ PPC_ID_TABORTDCI,
+ PPC_ID_TABORTWC,
+ PPC_ID_TABORTWCI,
+ PPC_ID_TBEGIN,
+ PPC_ID_TCHECK,
+ PPC_ID_TD,
+ PPC_ID_TDEQ,
+ PPC_ID_TDEQI,
+ PPC_ID_TDGT,
+ PPC_ID_TDGTI,
+ PPC_ID_TDI,
+ PPC_ID_TDLGT,
+ PPC_ID_TDLGTI,
+ PPC_ID_TDLLT,
+ PPC_ID_TDLLTI,
+ PPC_ID_TDLT,
+ PPC_ID_TDLTI,
+ PPC_ID_TDNE,
+ PPC_ID_TDNEI,
+ PPC_ID_TDU,
+ PPC_ID_TDUI,
+ PPC_ID_TEND,
+ PPC_ID_TLBIA,
+ PPC_ID_TLBIE,
+ PPC_ID_TLBIEL,
+ PPC_ID_TLBIVAX,
+ PPC_ID_TLBLI,
+ PPC_ID_TLBSX,
+ PPC_ID_TLBSYNC,
+ PPC_ID_TLBRE,
+ PPC_ID_TLBRELO,
+ PPC_ID_TLBREHI,
+ PPC_ID_TLBWE,
+ PPC_ID_TLBWEHI,
+ PPC_ID_TLBWELO,
+ PPC_ID_TRAP,
+ PPC_ID_TRECHKPT,
+ PPC_ID_TRECLAIM,
+ PPC_ID_TSR,
+ PPC_ID_TW,
+ PPC_ID_TWEQ,
+ PPC_ID_TWEQI,
+ PPC_ID_TWGT,
+ PPC_ID_TWGTI,
+ PPC_ID_TWGEI,
+ PPC_ID_TWI,
+ PPC_ID_TWLEI,
+ PPC_ID_TWLLEI,
+ PPC_ID_TWLGT,
+ PPC_ID_TWLGTI,
+ PPC_ID_TWLLT,
+ PPC_ID_TWLLTI,
+ PPC_ID_TWLT,
+ PPC_ID_TWLTI,
+ PPC_ID_TWNE,
+ PPC_ID_TWNEI,
+ PPC_ID_TWU,
+ PPC_ID_TWUI,
+ PPC_ID_WAIT,
+ PPC_ID_WAITIMPL,
+ PPC_ID_WAITRSV,
+ PPC_ID_WRTEE,
+ PPC_ID_WRTEEI,
+ PPC_ID_XNOP,
+ PPC_ID_XORx,
+ PPC_ID_XORIx,
+ PPC_ID_XORIS,
+
+ // AltiVec instructions
+ PPC_ID_AV_VABSDUB,
+ PPC_ID_AV_VABSDUH,
+ PPC_ID_AV_VABSDUW,
+ PPC_ID_AV_VADDUQM,
+ PPC_ID_AV_VADDCUQ,
+ PPC_ID_AV_BCDADD,
+ PPC_ID_AV_BCDCFN,
+ PPC_ID_AV_BCDCFSQ,
+ PPC_ID_AV_BCDCFZ,
+ PPC_ID_AV_BCDCPSGN,
+ PPC_ID_AV_BCDCTN,
+ PPC_ID_AV_BCDCTSQ,
+ PPC_ID_AV_BCDCTZ,
+ PPC_ID_AV_BCDS,
+ PPC_ID_AV_BCDSETSGN,
+ PPC_ID_AV_BCDSR,
+ PPC_ID_AV_BCDSUB,
+ PPC_ID_AV_BCDTRUNC,
+ PPC_ID_AV_BCDUS,
+ PPC_ID_AV_BCDUTRUNC,
+ PPC_ID_AV_DSS,
+ PPC_ID_AV_DSSALL,
+ PPC_ID_AV_DST,
+ PPC_ID_AV_DSTST,
+ PPC_ID_AV_DSTSTT,
+ PPC_ID_AV_DSTT,
+ PPC_ID_AV_LVEBX,
+ PPC_ID_AV_LVEHX,
+ PPC_ID_AV_LVEWX,
+ PPC_ID_AV_LVSL,
+ PPC_ID_AV_LVSR,
+ PPC_ID_AV_LVX,
+ PPC_ID_AV_LVXL,
+ PPC_ID_AV_MADDHD,
+ PPC_ID_AV_MADDHDU,
+ PPC_ID_AV_MADDLD,
+ PPC_ID_AV_MFVSCR,
+ PPC_ID_AV_MTVSCR,
+ PPC_ID_AV_STVEBX,
+ PPC_ID_AV_STVEHX,
+ PPC_ID_AV_STVEWX,
+ PPC_ID_AV_STVX,
+ PPC_ID_AV_STVXL,
+ PPC_ID_AV_VADDCUW,
+ PPC_ID_AV_VADDECUQ,
+ PPC_ID_AV_VADDEUQM,
+ PPC_ID_AV_VADDFP,
+ PPC_ID_AV_VADDSBS,
+ PPC_ID_AV_VADDSHS,
+ PPC_ID_AV_VADDSWS,
+ PPC_ID_AV_VADDUBM,
+ PPC_ID_AV_VADDUBS,
+ PPC_ID_AV_VADDUDM,
+ PPC_ID_AV_VADDUHM,
+ PPC_ID_AV_VADDUHS,
+ PPC_ID_AV_VADDUWM,
+ PPC_ID_AV_VADDUWS,
+ PPC_ID_AV_VAND,
+ PPC_ID_AV_VANDC,
+ PPC_ID_AV_VAVGSB,
+ PPC_ID_AV_VAVGSH,
+ PPC_ID_AV_VAVGSW,
+ PPC_ID_AV_VAVGUB,
+ PPC_ID_AV_VAVGUH,
+ PPC_ID_AV_VAVGUW,
+ PPC_ID_AV_VBPERMD,
+ PPC_ID_AV_VBPERMQ,
+ PPC_ID_AV_VCFSX,
+ PPC_ID_AV_VCFUX,
+ PPC_ID_AV_VCIPHER,
+ PPC_ID_AV_VCIPHERLAST,
+ PPC_ID_AV_VCLZB,
+ PPC_ID_AV_VCLZD,
+ PPC_ID_AV_VCLZH,
+ PPC_ID_AV_VCLZLSBB,
+ PPC_ID_AV_VCLZW,
+ PPC_ID_AV_VCMPBFPx,
+ PPC_ID_AV_VCMPEQFPx,
+ PPC_ID_AV_VCMPEQUBx,
+ PPC_ID_AV_VCMPEQUDx,
+ PPC_ID_AV_VCMPEQUHx,
+ PPC_ID_AV_VCMPEQUWx,
+ PPC_ID_AV_VCMPGEFPx,
+ PPC_ID_AV_VCMPGTFPx,
+ PPC_ID_AV_VCMPGTSBx,
+ PPC_ID_AV_VCMPGTSDx,
+ PPC_ID_AV_VCMPGTSHx,
+ PPC_ID_AV_VCMPGTSWx,
+ PPC_ID_AV_VCMPGTUBx,
+ PPC_ID_AV_VCMPGTUDx,
+ PPC_ID_AV_VCMPGTUHx,
+ PPC_ID_AV_VCMPGTUWx,
+ PPC_ID_AV_VCMPNEBx,
+ PPC_ID_AV_VCMPNEHx,
+ PPC_ID_AV_VCMPNEWx,
+ PPC_ID_AV_VCMPNEZBx,
+ PPC_ID_AV_VCMPNEZHx,
+ PPC_ID_AV_VCMPNEZWx,
+ PPC_ID_AV_VCTSXS,
+ PPC_ID_AV_VCTUXS,
+ PPC_ID_AV_VCTZB,
+ PPC_ID_AV_VCTZD,
+ PPC_ID_AV_VCTZH,
+ PPC_ID_AV_VCTZLSBB,
+ PPC_ID_AV_VCTZW,
+ PPC_ID_AV_VEQV,
+ PPC_ID_AV_VEXPTEFP,
+ PPC_ID_AV_VEXTRACTD,
+ PPC_ID_AV_VEXTRACTUB,
+ PPC_ID_AV_VEXTRACTUH,
+ PPC_ID_AV_VEXTRACTUW,
+ PPC_ID_AV_VEXTSB2D,
+ PPC_ID_AV_VEXTSB2W,
+ PPC_ID_AV_VEXTSH2D,
+ PPC_ID_AV_VEXTSH2W,
+ PPC_ID_AV_VEXTSW2D,
+ PPC_ID_AV_VEXTUBLX,
+ PPC_ID_AV_VEXTUHLX,
+ PPC_ID_AV_VEXTUWLX,
+ PPC_ID_AV_VEXTUBRX,
+ PPC_ID_AV_VEXTUHRX,
+ PPC_ID_AV_VEXTUWRX,
+ PPC_ID_AV_VGBBD,
+ PPC_ID_AV_VINSERTB,
+ PPC_ID_AV_VINSERTD,
+ PPC_ID_AV_VINSERTH,
+ PPC_ID_AV_VINSERTW,
+ PPC_ID_AV_VLOGEFP,
+ PPC_ID_AV_VMADDFP,
+ PPC_ID_AV_VMAXFP,
+ PPC_ID_AV_VMAXSB,
+ PPC_ID_AV_VMAXSD,
+ PPC_ID_AV_VMAXSH,
+ PPC_ID_AV_VMAXSW,
+ PPC_ID_AV_VMAXUB,
+ PPC_ID_AV_VMAXUD,
+ PPC_ID_AV_VMAXUH,
+ PPC_ID_AV_VMAXUW,
+ PPC_ID_AV_VMHADDSHS,
+ PPC_ID_AV_VMHRADDSHS,
+ PPC_ID_AV_VMINFP,
+ PPC_ID_AV_VMINSB,
+ PPC_ID_AV_VMINSD,
+ PPC_ID_AV_VMINSH,
+ PPC_ID_AV_VMINSW,
+ PPC_ID_AV_VMINUB,
+ PPC_ID_AV_VMINUD,
+ PPC_ID_AV_VMINUH,
+ PPC_ID_AV_VMINUW,
+ PPC_ID_AV_VMLADDUHM,
+ PPC_ID_AV_VMR,
+ PPC_ID_AV_VMRGEW,
+ PPC_ID_AV_VMRGHB,
+ PPC_ID_AV_VMRGHH,
+ PPC_ID_AV_VMRGHW,
+ PPC_ID_AV_VMRGLB,
+ PPC_ID_AV_VMRGLH,
+ PPC_ID_AV_VMRGLW,
+ PPC_ID_AV_VMRGOW,
+ PPC_ID_AV_VMSUMMBM,
+ PPC_ID_AV_VMSUMSHM,
+ PPC_ID_AV_VMSUMSHS,
+ PPC_ID_AV_VMSUMUBM,
+ PPC_ID_AV_VMSUMUHM,
+ PPC_ID_AV_VMSUMUHS,
+ PPC_ID_AV_VMUL10CUQ,
+ PPC_ID_AV_VMUL10EUQ,
+ PPC_ID_AV_VMUL10ECUQ,
+ PPC_ID_AV_VMUL10UQ,
+ PPC_ID_AV_VMULESB,
+ PPC_ID_AV_VMULESH,
+ PPC_ID_AV_VMULESW,
+ PPC_ID_AV_VMULEUB,
+ PPC_ID_AV_VMULEUH,
+ PPC_ID_AV_VMULEUW,
+ PPC_ID_AV_VMULOSB,
+ PPC_ID_AV_VMULOSH,
+ PPC_ID_AV_VMULOSW,
+ PPC_ID_AV_VMULOUB,
+ PPC_ID_AV_VMULOUH,
+ PPC_ID_AV_VMULOUW,
+ PPC_ID_AV_VMULUWM,
+ PPC_ID_AV_VNAND,
+ PPC_ID_AV_VNCIPHER,
+ PPC_ID_AV_VNCIPHERLAST,
+ PPC_ID_AV_VNMSUBFP,
+ PPC_ID_AV_VNEGD,
+ PPC_ID_AV_VNEGW,
+ PPC_ID_AV_VNOR,
+ PPC_ID_AV_VNOT,
+ PPC_ID_AV_VOR,
+ PPC_ID_AV_VORC,
+ PPC_ID_AV_VPERM,
+ PPC_ID_AV_VPERMR,
+ PPC_ID_AV_VPERMXOR,
+ PPC_ID_AV_VPKPX,
+ PPC_ID_AV_VPKSDSS,
+ PPC_ID_AV_VPKSDUS,
+ PPC_ID_AV_VPKSHSS,
+ PPC_ID_AV_VPKSHUS,
+ PPC_ID_AV_VPKSWSS,
+ PPC_ID_AV_VPKSWUS,
+ PPC_ID_AV_VPKUDUM,
+ PPC_ID_AV_VPKUDUS,
+ PPC_ID_AV_VPKUHUM,
+ PPC_ID_AV_VPKUHUS,
+ PPC_ID_AV_VPKUWUM,
+ PPC_ID_AV_VPKUWUS,
+ PPC_ID_AV_VPMSUMB,
+ PPC_ID_AV_VPMSUMD,
+ PPC_ID_AV_VPMSUMH,
+ PPC_ID_AV_VPMSUMW,
+ PPC_ID_AV_VPOPCNTB,
+ PPC_ID_AV_VPOPCNTD,
+ PPC_ID_AV_VPOPCNTH,
+ PPC_ID_AV_VPOPCNTW,
+ PPC_ID_AV_VPRTYBD,
+ PPC_ID_AV_VPRTYBQ,
+ PPC_ID_AV_VPRTYBW,
+ PPC_ID_AV_VREFP,
+ PPC_ID_AV_VRFIM,
+ PPC_ID_AV_VRFIN,
+ PPC_ID_AV_VRFIP,
+ PPC_ID_AV_VRFIZ,
+ PPC_ID_AV_VRLB,
+ PPC_ID_AV_VRLD,
+ PPC_ID_AV_VRLDNM,
+ PPC_ID_AV_VRLDMI,
+ PPC_ID_AV_VRLH,
+ PPC_ID_AV_VRLW,
+ PPC_ID_AV_VRLWMI,
+ PPC_ID_AV_VRLWNM,
+ PPC_ID_AV_VRSQRTEFP,
+ PPC_ID_AV_VSBOX,
+ PPC_ID_AV_VSEL,
+ PPC_ID_AV_VSHASIGMAD,
+ PPC_ID_AV_VSHASIGMAW,
+ PPC_ID_AV_VSL,
+ PPC_ID_AV_VSLB,
+ PPC_ID_AV_VSLD,
+ PPC_ID_AV_VSLDOI,
+ PPC_ID_AV_VSLH,
+ PPC_ID_AV_VSLO,
+ PPC_ID_AV_VSLV,
+ PPC_ID_AV_VSLW,
+ PPC_ID_AV_VSPLTB,
+ PPC_ID_AV_VSPLTH,
+ PPC_ID_AV_VSPLTISB,
+ PPC_ID_AV_VSPLTISH,
+ PPC_ID_AV_VSPLTISW,
+ PPC_ID_AV_VSPLTW,
+ PPC_ID_AV_VSR,
+ PPC_ID_AV_VSRAB,
+ PPC_ID_AV_VSRAD,
+ PPC_ID_AV_VSRAH,
+ PPC_ID_AV_VSRAW,
+ PPC_ID_AV_VSRB,
+ PPC_ID_AV_VSRD,
+ PPC_ID_AV_VSRH,
+ PPC_ID_AV_VSRO,
+ PPC_ID_AV_VSRV,
+ PPC_ID_AV_VSRW,
+ PPC_ID_AV_VSUBCUQ,
+ PPC_ID_AV_VSUBCUW,
+ PPC_ID_AV_VSUBECUQ,
+ PPC_ID_AV_VSUBEUQM,
+ PPC_ID_AV_VSUBFP,
+ PPC_ID_AV_VSUBSBS,
+ PPC_ID_AV_VSUBSHS,
+ PPC_ID_AV_VSUBSWS,
+ PPC_ID_AV_VSUBUBM,
+ PPC_ID_AV_VSUBUBS,
+ PPC_ID_AV_VSUBUDM,
+ PPC_ID_AV_VSUBUHM,
+ PPC_ID_AV_VSUBUHS,
+ PPC_ID_AV_VSUBUQM,
+ PPC_ID_AV_VSUBUWM,
+ PPC_ID_AV_VSUBUWS,
+ PPC_ID_AV_VSUMSWS,
+ PPC_ID_AV_VSUM2SWS,
+ PPC_ID_AV_VSUM4SBS,
+ PPC_ID_AV_VSUM4SHS,
+ PPC_ID_AV_VSUM4UBS,
+ PPC_ID_AV_VUPKHPX,
+ PPC_ID_AV_VUPKHSB,
+ PPC_ID_AV_VUPKHSH,
+ PPC_ID_AV_VUPKHSW,
+ PPC_ID_AV_VUPKLPX,
+ PPC_ID_AV_VUPKLSB,
+ PPC_ID_AV_VUPKLSH,
+ PPC_ID_AV_VUPKLSW,
+ PPC_ID_AV_VXOR,
+
+ // VSX instructions
+ PPC_ID_VSX_LXSD,
+ PPC_ID_VSX_LXSDX,
+ PPC_ID_VSX_LXSIBZX,
+ PPC_ID_VSX_LXSIHZX,
+ PPC_ID_VSX_LXSIWAX,
+ PPC_ID_VSX_LXSIWZX,
+ PPC_ID_VSX_LXSSP,
+ PPC_ID_VSX_LXSSPX,
+ PPC_ID_VSX_LXV,
+ PPC_ID_VSX_LXVB16X,
+ PPC_ID_VSX_LXVD2X,
+ PPC_ID_VSX_LXVDSX,
+ PPC_ID_VSX_LXVH8X,
+ PPC_ID_VSX_LXVL,
+ PPC_ID_VSX_LXVLL,
+ PPC_ID_VSX_LXVW4X,
+ PPC_ID_VSX_LXVWSX,
+ PPC_ID_VSX_LXVX,
+ PPC_ID_VSX_MFFPRD,
+ PPC_ID_VSX_MFVSRD,
+ PPC_ID_VSX_MFVSRLD,
+ PPC_ID_VSX_MFVSRWZ,
+ PPC_ID_VSX_MTVSRD,
+ PPC_ID_VSX_MTVSRDD,
+ PPC_ID_VSX_MTVSRWA,
+ PPC_ID_VSX_MTVSRWS,
+ PPC_ID_VSX_MTVSRWZ,
+ PPC_ID_VSX_STXSD,
+ PPC_ID_VSX_STXSDX,
+ PPC_ID_VSX_STXSIBX,
+ PPC_ID_VSX_STXSIHX,
+ PPC_ID_VSX_STXSIWX,
+ PPC_ID_VSX_STXSSP,
+ PPC_ID_VSX_STXSSPX,
+ PPC_ID_VSX_STXV,
+ PPC_ID_VSX_STXVB16X,
+ PPC_ID_VSX_STXVD2X,
+ PPC_ID_VSX_STXVH8X,
+ PPC_ID_VSX_STXVL,
+ PPC_ID_VSX_STXVLL,
+ PPC_ID_VSX_STXVW4X,
+ PPC_ID_VSX_STXVX,
+ PPC_ID_VSX_XSABSDP,
+ PPC_ID_VSX_XSABSQP,
+ PPC_ID_VSX_XSADDDP,
+ PPC_ID_VSX_XSADDSP,
+ PPC_ID_VSX_XSADDQPx,
+ PPC_ID_VSX_XSCMPEQDP,
+ PPC_ID_VSX_XSCMPEXPDP,
+ PPC_ID_VSX_XSCMPEXPQP,
+ PPC_ID_VSX_XSCMPGEDP,
+ PPC_ID_VSX_XSCMPGTDP,
+ PPC_ID_VSX_XSCMPODP,
+ PPC_ID_VSX_XSCMPOQP,
+ PPC_ID_VSX_XSCMPUDP,
+ PPC_ID_VSX_XSCMPUQP,
+ PPC_ID_VSX_XSCPSGNDP,
+ PPC_ID_VSX_XSCPSGNQP,
+ PPC_ID_VSX_XSCVDPHP,
+ PPC_ID_VSX_XSCVDPQP,
+ PPC_ID_VSX_XSCVDPSP,
+ PPC_ID_VSX_XSCVDPSPN,
+ PPC_ID_VSX_XSCVDPSXDS,
+ PPC_ID_VSX_XSCVDPSXWS,
+ PPC_ID_VSX_XSCVDPUXDS,
+ PPC_ID_VSX_XSCVDPUXWS,
+ PPC_ID_VSX_XSCVHPDP,
+ PPC_ID_VSX_XSCVQPDPx,
+ PPC_ID_VSX_XSCVQPSDZ,
+ PPC_ID_VSX_XSCVQPSWZ,
+ PPC_ID_VSX_XSCVQPUDZ,
+ PPC_ID_VSX_XSCVQPUWZ,
+ PPC_ID_VSX_XSCVSDQP,
+ PPC_ID_VSX_XSCVSPDP,
+ PPC_ID_VSX_XSCVSPDPN,
+ PPC_ID_VSX_XSCVSXDDP,
+ PPC_ID_VSX_XSCVSXDSP,
+ PPC_ID_VSX_XSCVUDQP,
+ PPC_ID_VSX_XSCVUXDDP,
+ PPC_ID_VSX_XSCVUXDSP,
+ PPC_ID_VSX_XSDIVDP,
+ PPC_ID_VSX_XSDIVSP,
+ PPC_ID_VSX_XSDIVQPx,
+ PPC_ID_VSX_XSIEXPDP,
+ PPC_ID_VSX_XSIEXPQP,
+ PPC_ID_VSX_XSMADDADP,
+ PPC_ID_VSX_XSMADDASP,
+ PPC_ID_VSX_XSMADDMDP,
+ PPC_ID_VSX_XSMADDMSP,
+ PPC_ID_VSX_XSMADDQPx,
+ PPC_ID_VSX_XSMAXCDP,
+ PPC_ID_VSX_XSMAXDP,
+ PPC_ID_VSX_XSMAXJDP,
+ PPC_ID_VSX_XSMINCDP,
+ PPC_ID_VSX_XSMINDP,
+ PPC_ID_VSX_XSMINJDP,
+ PPC_ID_VSX_XSMSUBADP,
+ PPC_ID_VSX_XSMSUBASP,
+ PPC_ID_VSX_XSMSUBMDP,
+ PPC_ID_VSX_XSMSUBMSP,
+ PPC_ID_VSX_XSMSUBQPx,
+ PPC_ID_VSX_XSMULDP,
+ PPC_ID_VSX_XSMULSP,
+ PPC_ID_VSX_XSMULQPx,
+ PPC_ID_VSX_XSNABSDP,
+ PPC_ID_VSX_XSNABSQP,
+ PPC_ID_VSX_XSNEGDP,
+ PPC_ID_VSX_XSNEGQP,
+ PPC_ID_VSX_XSNMADDADP,
+ PPC_ID_VSX_XSNMADDASP,
+ PPC_ID_VSX_XSNMADDMDP,
+ PPC_ID_VSX_XSNMADDMSP,
+ PPC_ID_VSX_XSNMADDQPx,
+ PPC_ID_VSX_XSNMSUBADP,
+ PPC_ID_VSX_XSNMSUBASP,
+ PPC_ID_VSX_XSNMSUBMDP,
+ PPC_ID_VSX_XSNMSUBMSP,
+ PPC_ID_VSX_XSNMSUBQPx,
+ PPC_ID_VSX_XSRDPI,
+ PPC_ID_VSX_XSRDPIC,
+ PPC_ID_VSX_XSRDPIM,
+ PPC_ID_VSX_XSRDPIP,
+ PPC_ID_VSX_XSRDPIZ,
+ PPC_ID_VSX_XSREDP,
+ PPC_ID_VSX_XSRESP,
+ PPC_ID_VSX_XSRQPIx,
+ PPC_ID_VSX_XSRQPXP,
+ PPC_ID_VSX_XSRSP,
+ PPC_ID_VSX_XSRSQRTEDP,
+ PPC_ID_VSX_XSRSQRTESP,
+ PPC_ID_VSX_XSSQRTDP,
+ PPC_ID_VSX_XSSQRTQPx,
+ PPC_ID_VSX_XSSQRTSP,
+ PPC_ID_VSX_XSSUBDP,
+ PPC_ID_VSX_XSSUBSP,
+ PPC_ID_VSX_XSSUBQPx,
+ PPC_ID_VSX_XSTDIVDP,
+ PPC_ID_VSX_XSTDIVSP,
+ PPC_ID_VSX_XSTSTDCQP,
+ PPC_ID_VSX_XSTSTDCDP,
+ PPC_ID_VSX_XSTSTDCSP,
+ PPC_ID_VSX_XSTSQRTDP,
+ PPC_ID_VSX_XSXEXPDP,
+ PPC_ID_VSX_XSXEXPQP,
+ PPC_ID_VSX_XSXSIGDP,
+ PPC_ID_VSX_XSXSIGQP,
+ PPC_ID_VSX_XVABSDP,
+ PPC_ID_VSX_XVABSSP,
+ PPC_ID_VSX_XVADDDP,
+ PPC_ID_VSX_XVADDSP,
+ PPC_ID_VSX_XVCMPEQDPx,
+ PPC_ID_VSX_XVCMPEQSPx,
+ PPC_ID_VSX_XVCMPGEDPx,
+ PPC_ID_VSX_XVCMPGESPx,
+ PPC_ID_VSX_XVCMPGTDPx,
+ PPC_ID_VSX_XVCMPGTSPx,
+ PPC_ID_VSX_XVCPSGNDP,
+ PPC_ID_VSX_XVCPSGNSP,
+ PPC_ID_VSX_XVCVDPSP,
+ PPC_ID_VSX_XVCVDPSXDS,
+ PPC_ID_VSX_XVCVDPSXWS,
+ PPC_ID_VSX_XVCVDPUXDS,
+ PPC_ID_VSX_XVCVDPUXWS,
+ PPC_ID_VSX_XVCVHPSP,
+ PPC_ID_VSX_XVCVSPDP,
+ PPC_ID_VSX_XVCVSPHP,
+ PPC_ID_VSX_XVCVSPSXDS,
+ PPC_ID_VSX_XVCVSPSXWS,
+ PPC_ID_VSX_XVCVSPUXDS,
+ PPC_ID_VSX_XVCVSPUXWS,
+ PPC_ID_VSX_XVCVSXDDP,
+ PPC_ID_VSX_XVCVSXDSP,
+ PPC_ID_VSX_XVCVSXWDP,
+ PPC_ID_VSX_XVCVSXWSP,
+ PPC_ID_VSX_XVCVUXDDP,
+ PPC_ID_VSX_XVCVUXDSP,
+ PPC_ID_VSX_XVCVUXWDP,
+ PPC_ID_VSX_XVCVUXWSP,
+ PPC_ID_VSX_XVDIVDP,
+ PPC_ID_VSX_XVDIVSP,
+ PPC_ID_VSX_XVIEXPDP,
+ PPC_ID_VSX_XVIEXPSP,
+ PPC_ID_VSX_XVMADDADP,
+ PPC_ID_VSX_XVMADDASP,
+ PPC_ID_VSX_XVMADDMDP,
+ PPC_ID_VSX_XVMADDMSP,
+ PPC_ID_VSX_XVMAXDP,
+ PPC_ID_VSX_XVMAXSP,
+ PPC_ID_VSX_XVMINDP,
+ PPC_ID_VSX_XVMINSP,
+ PPC_ID_VSX_XVMOVDP,
+ PPC_ID_VSX_XVMOVSP,
+ PPC_ID_VSX_XVMSUBADP,
+ PPC_ID_VSX_XVMSUBASP,
+ PPC_ID_VSX_XVMSUBMDP,
+ PPC_ID_VSX_XVMSUBMSP,
+ PPC_ID_VSX_XVMULDP,
+ PPC_ID_VSX_XVMULSP,
+ PPC_ID_VSX_XVNABSDP,
+ PPC_ID_VSX_XVNABSSP,
+ PPC_ID_VSX_XVNMADDADP,
+ PPC_ID_VSX_XVNMADDASP,
+ PPC_ID_VSX_XVNMADDMDP,
+ PPC_ID_VSX_XVNMADDMSP,
+ PPC_ID_VSX_XVNEGDP,
+ PPC_ID_VSX_XVNEGSP,
+ PPC_ID_VSX_XVNMSUBADP,
+ PPC_ID_VSX_XVNMSUBASP,
+ PPC_ID_VSX_XVNMSUBMDP,
+ PPC_ID_VSX_XVNMSUBMSP,
+ PPC_ID_VSX_XVRDPI,
+ PPC_ID_VSX_XVRDPIC,
+ PPC_ID_VSX_XVRDPIM,
+ PPC_ID_VSX_XVRDPIP,
+ PPC_ID_VSX_XVRDPIZ,
+ PPC_ID_VSX_XVREDP,
+ PPC_ID_VSX_XVRESP,
+ PPC_ID_VSX_XVRSPI,
+ PPC_ID_VSX_XVRSPIC,
+ PPC_ID_VSX_XVRSPIM,
+ PPC_ID_VSX_XVRSPIP,
+ PPC_ID_VSX_XVRSPIZ,
+ PPC_ID_VSX_XVRSQRTEDP,
+ PPC_ID_VSX_XVRSQRTESP,
+ PPC_ID_VSX_XVSQRTDP,
+ PPC_ID_VSX_XVSQRTSP,
+ PPC_ID_VSX_XVSUBDP,
+ PPC_ID_VSX_XVSUBSP,
+ PPC_ID_VSX_XVTDIVDP,
+ PPC_ID_VSX_XVTDIVSP,
+ PPC_ID_VSX_XVTSQRTDP,
+ PPC_ID_VSX_XVTSQRTSP,
+ PPC_ID_VSX_XVTSTDCDP,
+ PPC_ID_VSX_XVTSTDCSP,
+ PPC_ID_VSX_XVXEXPDP,
+ PPC_ID_VSX_XVXEXPSP,
+ PPC_ID_VSX_XVXSIGDP,
+ PPC_ID_VSX_XVXSIGSP,
+ PPC_ID_VSX_XXBRD,
+ PPC_ID_VSX_XXBRH,
+ PPC_ID_VSX_XXBRQ,
+ PPC_ID_VSX_XXBRW,
+ PPC_ID_VSX_XXEXTRACTUW,
+ PPC_ID_VSX_XXINSERTW,
+ PPC_ID_VSX_XXLAND,
+ PPC_ID_VSX_XXLANDC,
+ PPC_ID_VSX_XXLEQV,
+ PPC_ID_VSX_XXLNAND,
+ PPC_ID_VSX_XXLNOR,
+ PPC_ID_VSX_XXLOR,
+ PPC_ID_VSX_XXLORC,
+ PPC_ID_VSX_XXLXOR,
+ PPC_ID_VSX_XXMRGHD,
+ PPC_ID_VSX_XXMRGHW,
+ PPC_ID_VSX_XXMRGLD,
+ PPC_ID_VSX_XXMRGLW,
+ PPC_ID_VSX_XXPERM,
+ PPC_ID_VSX_XXPERMDI,
+ PPC_ID_VSX_XXPERMR,
+ PPC_ID_VSX_XXSEL,
+ PPC_ID_VSX_XXSLDWI,
+ PPC_ID_VSX_XXSPLTD,
+ PPC_ID_VSX_XXSPLTIB,
+ PPC_ID_VSX_XXSPLTW,
+ PPC_ID_VSX_XXSWAPD,
+
+ // Pair-stored
+ PPC_ID_PSQ_L,
+ PPC_ID_PSQ_LU,
+ PPC_ID_PSQ_LUX,
+ PPC_ID_PSQ_LX,
+ PPC_ID_PSQ_ST,
+ PPC_ID_PSQ_STU,
+ PPC_ID_PSQ_STUX,
+ PPC_ID_PSQ_STX,
+
+ // Paired-single
+ PPC_ID_PAIREDSINGLE_DCBZ_L,
+ PPC_ID_PAIREDSINGLE_PS_ABSx,
+ PPC_ID_PAIREDSINGLE_PS_ADDx,
+ PPC_ID_PAIREDSINGLE_PS_CMPO0,
+ PPC_ID_PAIREDSINGLE_PS_CMPO1,
+ PPC_ID_PAIREDSINGLE_PS_CMPU0,
+ PPC_ID_PAIREDSINGLE_PS_CMPU1,
+ PPC_ID_PAIREDSINGLE_PS_DIVx,
+ PPC_ID_PAIREDSINGLE_PS_MADDx,
+ PPC_ID_PAIREDSINGLE_PS_MADDS0x,
+ PPC_ID_PAIREDSINGLE_PS_MADDS1x,
+ PPC_ID_PAIREDSINGLE_PS_MERGE00x,
+ PPC_ID_PAIREDSINGLE_PS_MERGE01x,
+ PPC_ID_PAIREDSINGLE_PS_MERGE10x,
+ PPC_ID_PAIREDSINGLE_PS_MERGE11x,
+ PPC_ID_PAIREDSINGLE_PS_MRx,
+ PPC_ID_PAIREDSINGLE_PS_MSUBx,
+ PPC_ID_PAIREDSINGLE_PS_MULx,
+ PPC_ID_PAIREDSINGLE_PS_MULS0x,
+ PPC_ID_PAIREDSINGLE_PS_MULS1x,
+ PPC_ID_PAIREDSINGLE_PS_NABSx,
+ PPC_ID_PAIREDSINGLE_PS_NEGx,
+ PPC_ID_PAIREDSINGLE_PS_NMADDx,
+ PPC_ID_PAIREDSINGLE_PS_NMSUBx,
+ PPC_ID_PAIREDSINGLE_PS_RESx,
+ PPC_ID_PAIREDSINGLE_PS_RSQRTEx,
+ PPC_ID_PAIREDSINGLE_PS_SELx,
+ PPC_ID_PAIREDSINGLE_PS_SUBx,
+ PPC_ID_PAIREDSINGLE_PS_SUM0x,
+ PPC_ID_PAIREDSINGLE_PS_SUM1x,
+ PPC_ID_PAIREDSINGLE_PSQ_L,
+ PPC_ID_PAIREDSINGLE_PSQ_LU,
+ PPC_ID_PAIREDSINGLE_PSQ_LUX,
+ PPC_ID_PAIREDSINGLE_PSQ_LX,
+ PPC_ID_PAIREDSINGLE_PSQ_ST,
+ PPC_ID_PAIREDSINGLE_PSQ_STU,
+ PPC_ID_PAIREDSINGLE_PSQ_STUX,
+ PPC_ID_PAIREDSINGLE_PSQ_STX,
+
+ // SPE (Signal Processing Engine) instructions
+ PPC_ID_SPE_BRINC,
+ PPC_ID_SPE_EFDABS,
+ PPC_ID_SPE_EFDADD,
+ PPC_ID_SPE_EFDCFS,
+ PPC_ID_SPE_EFDCFSF,
+ PPC_ID_SPE_EFDCFSI,
+ PPC_ID_SPE_EFDCFSID,
+ PPC_ID_SPE_EFDCFUF,
+ PPC_ID_SPE_EFDCFUI,
+ PPC_ID_SPE_EFDCFUID,
+ PPC_ID_SPE_EFDCMPEQ,
+ PPC_ID_SPE_EFDCMPGT,
+ PPC_ID_SPE_EFDCMPLT,
+ PPC_ID_SPE_EFDCTSF,
+ PPC_ID_SPE_EFDCTSI,
+ PPC_ID_SPE_EFDCTSIDZ,
+ PPC_ID_SPE_EFDCTSIZ,
+ PPC_ID_SPE_EFDCTUF,
+ PPC_ID_SPE_EFDCTUI,
+ PPC_ID_SPE_EFDCTUIDZ,
+ PPC_ID_SPE_EFDCTUIZ,
+ PPC_ID_SPE_EFDDIV,
+ PPC_ID_SPE_EFDMUL,
+ PPC_ID_SPE_EFDNABS,
+ PPC_ID_SPE_EFDNEG,
+ PPC_ID_SPE_EFDSUB,
+ PPC_ID_SPE_EFDTSTEQ,
+ PPC_ID_SPE_EFDTSTGT,
+ PPC_ID_SPE_EFDTSTLT,
+ PPC_ID_SPE_EFSABS,
+ PPC_ID_SPE_EFSADD,
+ PPC_ID_SPE_EFSCFD,
+ PPC_ID_SPE_EFSCFSF,
+ PPC_ID_SPE_EFSCFSI,
+ PPC_ID_SPE_EFSCFUF,
+ PPC_ID_SPE_EFSCFUI,
+ PPC_ID_SPE_EFSCMPEQ,
+ PPC_ID_SPE_EFSCMPGT,
+ PPC_ID_SPE_EFSCMPLT,
+ PPC_ID_SPE_EFSCTSF,
+ PPC_ID_SPE_EFSCTSI,
+ PPC_ID_SPE_EFSCTSIZ,
+ PPC_ID_SPE_EFSCTUF,
+ PPC_ID_SPE_EFSCTUI,
+ PPC_ID_SPE_EFSCTUIZ,
+ PPC_ID_SPE_EFSDIV,
+ PPC_ID_SPE_EFSMUL,
+ PPC_ID_SPE_EFSNABS,
+ PPC_ID_SPE_EFSNEG,
+ PPC_ID_SPE_EFSSUB,
+ PPC_ID_SPE_EFSTSTEQ,
+ PPC_ID_SPE_EFSTSTGT,
+ PPC_ID_SPE_EFSTSTLT,
+ PPC_ID_SPE_EVABS,
+ PPC_ID_SPE_EVADDIW,
+ PPC_ID_SPE_EVADDSMIAAW,
+ PPC_ID_SPE_EVADDSSIAAW,
+ PPC_ID_SPE_EVADDUMIAAW,
+ PPC_ID_SPE_EVADDUSIAAW,
+ PPC_ID_SPE_EVADDW,
+ PPC_ID_SPE_EVAND,
+ PPC_ID_SPE_EVANDC,
+ PPC_ID_SPE_EVCMPEQ,
+ PPC_ID_SPE_EVCMPGTS,
+ PPC_ID_SPE_EVCMPGTU,
+ PPC_ID_SPE_EVCMPLTS,
+ PPC_ID_SPE_EVCMPLTU,
+ PPC_ID_SPE_EVCNTLSW,
+ PPC_ID_SPE_EVCNTLZW,
+ PPC_ID_SPE_EVDIVWS,
+ PPC_ID_SPE_EVDIVWU,
+ PPC_ID_SPE_EVEQV,
+ PPC_ID_SPE_EVEXTSB,
+ PPC_ID_SPE_EVEXTSH,
+ PPC_ID_SPE_EVFSABS,
+ PPC_ID_SPE_EVFSADD,
+ PPC_ID_SPE_EVFSCFSF,
+ PPC_ID_SPE_EVFSCFSI,
+ PPC_ID_SPE_EVFSCFUF,
+ PPC_ID_SPE_EVFSCFUI,
+ PPC_ID_SPE_EVSCFUI,
+ PPC_ID_SPE_EVFSCMPEQ,
+ PPC_ID_SPE_EVFSCMPGT,
+ PPC_ID_SPE_EVFSCMPLT,
+ PPC_ID_SPE_EVFSCTSF,
+ PPC_ID_SPE_EVFSCTSI,
+ PPC_ID_SPE_EVFSCTSIZ,
+ PPC_ID_SPE_EVFSCTUF,
+ PPC_ID_SPE_EVFSCTUI,
+ PPC_ID_SPE_EVFSCTUIZ,
+ PPC_ID_SPE_EVFSDIV,
+ PPC_ID_SPE_EVFSMUL,
+ PPC_ID_SPE_EVFSNABS,
+ PPC_ID_SPE_EVFSNEG,
+ PPC_ID_SPE_EVFSSUB,
+ PPC_ID_SPE_EVFSTSTEQ,
+ PPC_ID_SPE_EVFSTSTGT,
+ PPC_ID_SPE_EVFSTSTLT,
+ PPC_ID_SPE_EVLDD,
+ PPC_ID_SPE_EVLDDX,
+ PPC_ID_SPE_EVLDH,
+ PPC_ID_SPE_EVLDHX,
+ PPC_ID_SPE_EVLDW,
+ PPC_ID_SPE_EVLDWX,
+ PPC_ID_SPE_EVLHHESPLAT,
+ PPC_ID_SPE_EVLHHESPLATX,
+ PPC_ID_SPE_EVLHHOSSPLAT,
+ PPC_ID_SPE_EVLHHOSSPLATX,
+ PPC_ID_SPE_EVLHHOUSPLAT,
+ PPC_ID_SPE_EVLHHOUSPLATX,
+ PPC_ID_SPE_EVLWHE,
+ PPC_ID_SPE_EVLWHEX,
+ PPC_ID_SPE_EVLWHOS,
+ PPC_ID_SPE_EVLWHOSX,
+ PPC_ID_SPE_EVLWHOU,
+ PPC_ID_SPE_EVLWHOUX,
+ PPC_ID_SPE_EVLWHSPLAT,
+ PPC_ID_SPE_EVLWHSPLATX,
+ PPC_ID_SPE_EVLWWSPLAT,
+ PPC_ID_SPE_EVLWWSPLATX,
+ PPC_ID_SPE_EVMERGEHI,
+ PPC_ID_SPE_EVMERGEHILO,
+ PPC_ID_SPE_EVMERGELO,
+ PPC_ID_SPE_EVMERGELOHI,
+ PPC_ID_SPE_EVMHEGSMFAA,
+ PPC_ID_SPE_EVMHEGSMFAN,
+ PPC_ID_SPE_EVMHEGSMIAA,
+ PPC_ID_SPE_EVMHEGSMIAN,
+ PPC_ID_SPE_EVMHEGUMIAA,
+ PPC_ID_SPE_EVMHEGUMIAN,
+ PPC_ID_SPE_EVMHESMF,
+ PPC_ID_SPE_EVMHESMFA,
+ PPC_ID_SPE_EVMHESMFAAW,
+ PPC_ID_SPE_EVMHESMFANW,
+ PPC_ID_SPE_EVMHESMI,
+ PPC_ID_SPE_EVMHESMIA,
+ PPC_ID_SPE_EVMHESMIAAW,
+ PPC_ID_SPE_EVMHESMIANW,
+ PPC_ID_SPE_EVMHESSF,
+ PPC_ID_SPE_EVMHESSFA,
+ PPC_ID_SPE_EVMHESSFAAW,
+ PPC_ID_SPE_EVMHESSFANW,
+ PPC_ID_SPE_EVMHESSIAAW,
+ PPC_ID_SPE_EVMHESSIANW,
+ PPC_ID_SPE_EVMHEUMI,
+ PPC_ID_SPE_EVMHEUMIA,
+ PPC_ID_SPE_EVMHEUMIAAW,
+ PPC_ID_SPE_EVMHEUMIANW,
+ PPC_ID_SPE_EVMHEUSIAAW,
+ PPC_ID_SPE_EVMHEUSIANW,
+ PPC_ID_SPE_EVMHOGSMFAA,
+ PPC_ID_SPE_EVMHOGSMFAN,
+ PPC_ID_SPE_EVMHOGSMIAA,
+ PPC_ID_SPE_EVMHOGSMIAN,
+ PPC_ID_SPE_EVMHOGUMIAA,
+ PPC_ID_SPE_EVMHOGUMIAN,
+ PPC_ID_SPE_EVMHOSMF,
+ PPC_ID_SPE_EVMHOSMFA,
+ PPC_ID_SPE_EVMHOSMFAAW,
+ PPC_ID_SPE_EVMHOSMFANW,
+ PPC_ID_SPE_EVMHOSMI,
+ PPC_ID_SPE_EVMHOSMIA,
+ PPC_ID_SPE_EVMHOSMIAAW,
+ PPC_ID_SPE_EVMHOSMIANW,
+ PPC_ID_SPE_EVMHOSSF,
+ PPC_ID_SPE_EVMHOSSFA,
+ PPC_ID_SPE_EVMHOSSFAAW,
+ PPC_ID_SPE_EVMHOSSFANW,
+ PPC_ID_SPE_EVMHOSSIAAW,
+ PPC_ID_SPE_EVMHOSSIANW,
+ PPC_ID_SPE_EVMHOUMI,
+ PPC_ID_SPE_EVMHOUMIA,
+ PPC_ID_SPE_EVMHOUMIAAW,
+ PPC_ID_SPE_EVMHOUMIANW,
+ PPC_ID_SPE_EVMHOUSIAAW,
+ PPC_ID_SPE_EVMHOUSIANW,
+ PPC_ID_SPE_EVMR,
+ PPC_ID_SPE_EVMRA,
+ PPC_ID_SPE_EVMWHSMF,
+ PPC_ID_SPE_EVMWHSMFA,
+ PPC_ID_SPE_EVMWHSMI,
+ PPC_ID_SPE_EVMWHSMIA,
+ PPC_ID_SPE_EVMWHSSF,
+ PPC_ID_SPE_EVMWHSSFA,
+ PPC_ID_SPE_EVMWHUMI,
+ PPC_ID_SPE_EVMWHUMIA,
+ PPC_ID_SPE_EVMWHUSIAAW,
+ PPC_ID_SPE_EVMWHUSIANW,
+ PPC_ID_SPE_EVMWLSMIAAW,
+ PPC_ID_SPE_EVMWLSMIANW,
+ PPC_ID_SPE_EVMWLSSIANW,
+ PPC_ID_SPE_EVMWLSSIAAW,
+ PPC_ID_SPE_EVMWLUMI,
+ PPC_ID_SPE_EVMWLUMIA,
+ PPC_ID_SPE_EVMWLUMIAAW,
+ PPC_ID_SPE_EVMWLUMIANW,
+ PPC_ID_SPE_EVMWLUSIAAW,
+ PPC_ID_SPE_EVMWLUSIANW,
+ PPC_ID_SPE_EVMWSMF,
+ PPC_ID_SPE_EVMWSMFA,
+ PPC_ID_SPE_EVMWSMFAA,
+ PPC_ID_SPE_EVMWSMFAN,
+ PPC_ID_SPE_EVMWSMI,
+ PPC_ID_SPE_EVMWSMIA,
+ PPC_ID_SPE_EVMWSMIAA,
+ PPC_ID_SPE_EVMWSMIAN,
+ PPC_ID_SPE_EVMWSSF,
+ PPC_ID_SPE_EVMWSSFA,
+ PPC_ID_SPE_EVMWSSFAA,
+ PPC_ID_SPE_EVMWSSFAN,
+ PPC_ID_SPE_EVMWUMI,
+ PPC_ID_SPE_EVMWUMIA,
+ PPC_ID_SPE_EVMWUMIAA,
+ PPC_ID_SPE_EVMWUMIAN,
+ PPC_ID_SPE_EVNAND,
+ PPC_ID_SPE_EVNEG,
+ PPC_ID_SPE_EVNOR,
+ PPC_ID_SPE_EVNOT,
+ PPC_ID_SPE_EVOR,
+ PPC_ID_SPE_EVORC,
+ PPC_ID_SPE_EVRLW,
+ PPC_ID_SPE_EVRLWI,
+ PPC_ID_SPE_EVRNDW,
+ PPC_ID_SPE_EVSEL,
+ PPC_ID_SPE_EVSLW,
+ PPC_ID_SPE_EVSLWI,
+ PPC_ID_SPE_EVSPLATFI,
+ PPC_ID_SPE_EVSPLATI,
+ PPC_ID_SPE_EVSRWIS,
+ PPC_ID_SPE_EVSRWIU,
+ PPC_ID_SPE_EVSRWS,
+ PPC_ID_SPE_EVSRWU,
+ PPC_ID_SPE_EVSTDD,
+ PPC_ID_SPE_EVSTDDX,
+ PPC_ID_SPE_EVSTDH,
+ PPC_ID_SPE_EVSTDHX,
+ PPC_ID_SPE_EVSTDW,
+ PPC_ID_SPE_EVSTDWX,
+ PPC_ID_SPE_EVSTWHE,
+ PPC_ID_SPE_EVSTWHEX,
+ PPC_ID_SPE_EVSTWHO,
+ PPC_ID_SPE_EVSTWHOX,
+ PPC_ID_SPE_EVSTWWE,
+ PPC_ID_SPE_EVSTWWEX,
+ PPC_ID_SPE_EVSTWWO,
+ PPC_ID_SPE_EVSTWWOX,
+ PPC_ID_SPE_EVSUBFSMIAAW,
+ PPC_ID_SPE_EVSUBFSSIAAW,
+ PPC_ID_SPE_EVSUBFUMIAAW,
+ PPC_ID_SPE_EVSUBFUSIAAW,
+ PPC_ID_SPE_EVSUBFW,
+ PPC_ID_SPE_EVSUBIFW,
+ PPC_ID_SPE_EVXOR,
+
+ // This should be all of the VLE instructions; if any get added
+ // here, make sure `vle32.c:IsVleInstructionId` remains valid
+ //
+ // 32-bit VLE instructions
+ PPC_ID_VLE_E_ADDIx,
+ PPC_ID_VLE_E_ADDICx,
+ PPC_ID_VLE_E_ADD2I,
+ PPC_ID_VLE_E_ADD2IS,
+ PPC_ID_VLE_E_ADD16I,
+ PPC_ID_VLE_E_ANDIx,
+ PPC_ID_VLE_E_AND2I,
+ PPC_ID_VLE_E_AND2IS,
+ PPC_ID_VLE_E_Bx,
+ PPC_ID_VLE_E_BCx,
+ PPC_ID_VLE_E_CMP16I,
+ PPC_ID_VLE_E_CMPH16I,
+ PPC_ID_VLE_E_CMPHL,
+ PPC_ID_VLE_E_CMPHL16I,
+ PPC_ID_VLE_E_CMPI,
+ PPC_ID_VLE_E_CMPL16I,
+ PPC_ID_VLE_E_CMPLI,
+ PPC_ID_VLE_E_CRAND,
+ PPC_ID_VLE_E_CRANDC,
+ PPC_ID_VLE_E_CREQV,
+ PPC_ID_VLE_E_CRNAND,
+ PPC_ID_VLE_E_CRNOR,
+ PPC_ID_VLE_E_CROR,
+ PPC_ID_VLE_E_CRORC,
+ PPC_ID_VLE_E_CRXOR,
+ PPC_ID_VLE_E_LBZ,
+ PPC_ID_VLE_E_LBZU,
+ PPC_ID_VLE_E_LHA,
+ PPC_ID_VLE_E_LHAU,
+ PPC_ID_VLE_E_LHZ,
+ PPC_ID_VLE_E_LHZU,
+ PPC_ID_VLE_E_LI,
+ PPC_ID_VLE_E_LIS,
+ PPC_ID_VLE_E_LMW,
+ PPC_ID_VLE_E_LWZ,
+ PPC_ID_VLE_E_LWZU,
+ PPC_ID_VLE_E_MCRF,
+ PPC_ID_VLE_E_MULL2I,
+ PPC_ID_VLE_E_MULLI,
+ PPC_ID_VLE_E_OR2I,
+ PPC_ID_VLE_E_OR2IS,
+ PPC_ID_VLE_E_ORIx,
+ PPC_ID_VLE_E_RLWx,
+ PPC_ID_VLE_E_RLWIx,
+ PPC_ID_VLE_E_RLWIMI,
+ PPC_ID_VLE_E_RLWINM,
+ PPC_ID_VLE_E_SLWIx,
+ PPC_ID_VLE_E_SRWIx,
+ PPC_ID_VLE_E_STB,
+ PPC_ID_VLE_E_STBU,
+ PPC_ID_VLE_E_STH,
+ PPC_ID_VLE_E_STHU,
+ PPC_ID_VLE_E_STMW,
+ PPC_ID_VLE_E_STW,
+ PPC_ID_VLE_E_STWU,
+ PPC_ID_VLE_E_SUBFICx,
+ PPC_ID_VLE_E_XORIx,
+
+ // Additional 32-bit VLE instructions from NXP EB696
+ //
+ // Note that chapter 3 "Instruction Operation Codes"
+ // and table 4 "Instruction Overview" list these as "LDMxxxx",
+ // but all of the mnemonics used in chapter 5 "Instruction
+ // Listings" are "LDxxxx" (note the lack of M)...assembly
+ // samples from an mpc5744 use the variant without the M, so we
+ // use that.
+ PPC_ID_VLE_E_LDVGPRW,
+ PPC_ID_VLE_E_LDVSPRW,
+ PPC_ID_VLE_E_LDVSRRW,
+ PPC_ID_VLE_E_LDVCSRRW,
+ PPC_ID_VLE_E_LDVDSRRW,
+ PPC_ID_VLE_E_STMVGPRW,
+ PPC_ID_VLE_E_STMVSPRW,
+ PPC_ID_VLE_E_STMVSRRW,
+ PPC_ID_VLE_E_STMVCSRRW,
+ PPC_ID_VLE_E_STMVDSRRW,
+
+ // 16-bit VLE instructions
+ PPC_ID_VLE_SE_ADD,
+ PPC_ID_VLE_SE_ADDI,
+ PPC_ID_VLE_SE_ANDx,
+ PPC_ID_VLE_SE_ANDC,
+ PPC_ID_VLE_SE_ANDI,
+ PPC_ID_VLE_SE_Bx,
+ PPC_ID_VLE_SE_BC,
+ PPC_ID_VLE_SE_BCLRI,
+ PPC_ID_VLE_SE_BCTRx,
+ PPC_ID_VLE_SE_BGENI,
+ PPC_ID_VLE_SE_BLRx,
+ PPC_ID_VLE_SE_BMASKI,
+ PPC_ID_VLE_SE_BSETI,
+ PPC_ID_VLE_SE_BTSTI,
+ PPC_ID_VLE_SE_CMP,
+ PPC_ID_VLE_SE_CMPH,
+ PPC_ID_VLE_SE_CMPHL,
+ PPC_ID_VLE_SE_CMPI,
+ PPC_ID_VLE_SE_CMPL,
+ PPC_ID_VLE_SE_CMPLI,
+ PPC_ID_VLE_SE_EXTSB,
+ PPC_ID_VLE_SE_EXTSH,
+ PPC_ID_VLE_SE_EXTZB,
+ PPC_ID_VLE_SE_EXTZH,
+ PPC_ID_VLE_SE_ILLEGAL,
+ PPC_ID_VLE_SE_ISYNC,
+ PPC_ID_VLE_SE_LBZ,
+ PPC_ID_VLE_SE_LHZ,
+ PPC_ID_VLE_SE_LI,
+ PPC_ID_VLE_SE_LWZ,
+ PPC_ID_VLE_SE_MFAR,
+ PPC_ID_VLE_SE_MFCTR,
+ PPC_ID_VLE_SE_MFLR,
+ PPC_ID_VLE_SE_MR,
+ PPC_ID_VLE_SE_MTAR,
+ PPC_ID_VLE_SE_MTCTR,
+ PPC_ID_VLE_SE_MTLR,
+ PPC_ID_VLE_SE_MULLW,
+ PPC_ID_VLE_SE_NEG,
+ PPC_ID_VLE_SE_NOP,
+ PPC_ID_VLE_SE_NOT,
+ PPC_ID_VLE_SE_OR,
+ PPC_ID_VLE_SE_RFCI,
+ PPC_ID_VLE_SE_RFDI,
+ PPC_ID_VLE_SE_RFI,
+ PPC_ID_VLE_SE_RFMCI,
+ PPC_ID_VLE_SE_SC,
+ PPC_ID_VLE_SE_SLW,
+ PPC_ID_VLE_SE_SLWI,
+ PPC_ID_VLE_SE_SRAW,
+ PPC_ID_VLE_SE_SRAWI,
+ PPC_ID_VLE_SE_SRW,
+ PPC_ID_VLE_SE_SRWI,
+ PPC_ID_VLE_SE_STB,
+ PPC_ID_VLE_SE_STH,
+ PPC_ID_VLE_SE_STW,
+ PPC_ID_VLE_SE_SUB,
+ PPC_ID_VLE_SE_SUBF,
+ PPC_ID_VLE_SE_SUBIx,
+ };
+
+#ifndef __cplusplus
+ typedef enum InstructionId InstructionId;
+#endif
+
+ struct Instruction
+ {
+ // When decoding with VLE -> base PPC translation (ie
+ // `decodeFlags & DECODE_FLAGS_VLE_TRANSLATE != 0), this ID may
+ // not faithfully represent the exact bytes corresponding to this
+ // instruction, but it will always represent something
+ // semantically equivalent; for example, PPC_ID_VLE_SE_BGENI
+ // may end up as a semantically equivalent PPC_ID_LI
+ // instruction.
+ //
+ // When `decodeFlags & DECODE_FLAGS_VLE_TRANSLATE == 0`, this
+ // ID always represents the bytes correspondong to the
+ // instruction
+ InstructionId id;
+
+ // This always represents the number of bytes in the
+ // underlying bytes of the instruction, regardless of whether
+ // it was translated with `DECODE_FLAGS_VLE_TRANSLATE`.
+ size_t numBytes;
+
+ // These acronyms are from the documentation; sometimes they
+ // refer to the same bit (like RC and LK)
+ struct {
+ uint32_t rc: 1;
+ uint32_t oe: 1;
+ uint32_t lk: 1;
+ uint32_t aa: 1;
+ uint32_t branchLikelyHint: 2;
+ uint32_t round2odd: 1;
+ uint32_t inexact: 1;
+ } flags;
+
+ size_t numOperands;
+ Operand operands[8];
+ };
+
+#ifndef __cplusplus
+ typedef struct Instruction Instruction;
+#endif
+
+ // returns 0 if data_length is too small to tell
+ size_t GetInstructionLength(const uint8_t* data, size_t data_length, uint32_t flags);
+
+ bool Decompose16(Instruction* instruction, uint16_t word32, uint64_t address, uint32_t flags);
+ bool Decompose32(Instruction* instruction, uint32_t word32, uint64_t address, uint32_t flags);
+ void FillBcxOperands(OperandsList* bcx, const Instruction* instruction);
+ void FillBcctrxOperands(OperandsList* bcctrx, const Instruction* instruction);
+ void FillBclrxOperands(OperandsList* bclrx, const Instruction* instruction);
+ void FillVle16BcOperands(OperandsList *se_bc, const Instruction *instruction);
+ void FillVle32BcxOperands(OperandsList *e_bcx, const Instruction *instruction);
+ const char* GetMnemonic(const Instruction* instruction);
+ const char* PowerPCRegisterName(uint32_t regId);
+ const char* OperandClassName(uint32_t cls);
+ const char* GetCRBitName(uint32_t crbit);
+
+ size_t VleGetInstructionLength(const uint8_t* data, size_t data_length, uint32_t decodeFlags);
+ bool Decompose16Vle(Instruction* instruction, uint16_t word16, uint64_t address, uint32_t flags);
+ bool Decompose32Vle(Instruction* instruction, uint32_t word32, uint64_t address, uint32_t flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // DECODE_PPC_H
diff --git a/arch/powerpc/decode/mnemonic.c b/arch/powerpc/decode/mnemonic.c
new file mode 100644
index 00000000..2b5fa06d
--- /dev/null
+++ b/arch/powerpc/decode/mnemonic.c
@@ -0,0 +1,2188 @@
+#include "decode.h"
+
+// the hope is to avoid having to manipulate strings in something that's
+// somewhat hot, so we create a bunch of lookup tables for each mnemonic
+
+// for "OP" and "OP."
+#define DEFINE_SUBMNEM_RC(_identifier, base) \
+ const char* _identifier[2] = \
+ { \
+ base, \
+ base ".", \
+ };
+
+// for "OP", "OP.", "OPo", and "OPo."
+#define DEFINE_SUBMNEM_OE_RC(_identifier, base) \
+ const char* _identifier[4] = \
+ { \
+ base, \
+ base ".", \
+ base "o", \
+ base "o.", \
+ };
+
+// for "OP" and "OPl"
+#define DEFINE_SUBMNEM_LK(_identifier, base) \
+ const char* _identifier[2] = \
+ { \
+ base, \
+ base "l", \
+ };
+
+// for "OP" and "OPl" and +/- hints
+#define DEFINE_SUBMNEM_LK_HINT(_identifier, base) \
+ const char* _identifier[8] = \
+ { \
+ base, \
+ base "l", \
+ base, \
+ base "l", \
+ base "-", \
+ base "l-", \
+ base "+", \
+ base "l+", \
+ };
+
+// for "OP", "OPl", "OPa", and "OPla"
+#define DEFINE_SUBMNEM_AA_LK(_identifier, base) \
+ const char* _identifier[4] = \
+ { \
+ base, \
+ base "l", \
+ base "a", \
+ base "la", \
+ };
+
+// for "OP", "OPl", "OPa", "OPla" and +/- hints
+#define DEFINE_SUBMNEM_AA_LK_HINT(_identifier, base) \
+ const char* _identifier[16] = \
+ { \
+ base, \
+ base "l", \
+ base "a", \
+ base "la", \
+ base, \
+ base "l", \
+ base "a", \
+ base "la", \
+ base "-", \
+ base "l-", \
+ base "a-", \
+ base "la-", \
+ base "+", \
+ base "l+", \
+ base "a+", \
+ base "la+" \
+ };
+
+#define DEFINE_SUBMNEM_ROUND2ODD(_identifier, base) \
+ const char* _identifier[2] = \
+ { \
+ base, \
+ base "o", \
+ };
+
+#define DEFINE_SUBMNEM_INEXACT(_identifier, base) \
+ const char* _identifier[2] = \
+ { \
+ base, \
+ base "x", \
+ };
+
+DEFINE_SUBMNEM_OE_RC(SubMnemADDx, "add")
+DEFINE_SUBMNEM_OE_RC(SubMnemADDCx, "addc")
+DEFINE_SUBMNEM_OE_RC(SubMnemADDEx, "adde")
+DEFINE_SUBMNEM_OE_RC(SubMnemADDIx, "addi")
+DEFINE_SUBMNEM_RC(SubMnemADDICx, "addic")
+DEFINE_SUBMNEM_OE_RC(SubMnemADDMEx, "addme")
+DEFINE_SUBMNEM_OE_RC(SubMnemADDZEx, "addze")
+DEFINE_SUBMNEM_RC(SubMnemANDx, "and")
+DEFINE_SUBMNEM_RC(SubMnemANDCx, "andc")
+DEFINE_SUBMNEM_RC(SubMnemANDIx, "andi")
+DEFINE_SUBMNEM_AA_LK(SubMnemBx, "b")
+DEFINE_SUBMNEM_AA_LK(SubMnemBCx, "bc")
+DEFINE_SUBMNEM_LK(SubMnemBCTRx, "bctr")
+DEFINE_SUBMNEM_LK(SubMnemBCCTRx, "bcctr")
+DEFINE_SUBMNEM_LK(SubMnemBCLRx, "bclr")
+DEFINE_SUBMNEM_AA_LK_HINT(SubMnemBDZx, "bdz")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBDZLRx, "bdzlr")
+DEFINE_SUBMNEM_AA_LK_HINT(SubMnemBDNZx, "bdnz")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBDNZLRx, "bdnzlr")
+DEFINE_SUBMNEM_AA_LK(SubMnemBDNZFx, "bdnzf")
+DEFINE_SUBMNEM_LK(SubMnemBDNZFLRx, "bdnzflr")
+DEFINE_SUBMNEM_AA_LK(SubMnemBDNZTx, "bdnzt")
+DEFINE_SUBMNEM_LK(SubMnemBDNZTLRx, "bdnztlr")
+DEFINE_SUBMNEM_AA_LK(SubMnemBDZFx, "bdzf")
+DEFINE_SUBMNEM_LK(SubMnemBDZFLRx, "bdzflr")
+DEFINE_SUBMNEM_LK(SubMnemBDFLRx, "bdzlr")
+DEFINE_SUBMNEM_AA_LK(SubMnemBDZTx, "bdzt")
+DEFINE_SUBMNEM_LK(SubMnemBDZTLRx, "bdztlr")
+DEFINE_SUBMNEM_AA_LK_HINT(SubMnemBEQx, "beq")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBEQCTRx, "beqctr")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBEQLRx, "beqlr")
+DEFINE_SUBMNEM_AA_LK(SubMnemBFx, "bf")
+DEFINE_SUBMNEM_AA_LK(SubMnemBFLRx, "bflr")
+DEFINE_SUBMNEM_AA_LK_HINT(SubMnemBGEx, "bge")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBGECTRx, "bgectr")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBGELRx, "bgelr")
+DEFINE_SUBMNEM_AA_LK_HINT(SubMnemBGTx, "bgt")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBGTCTRx, "bgtctr")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBGTLRx, "bgtlr")
+DEFINE_SUBMNEM_AA_LK_HINT(SubMnemBLEx, "ble")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBLECTRx, "blectr")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBLELRx, "blelr")
+DEFINE_SUBMNEM_AA_LK_HINT(SubMnemBLTx, "blt")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBLTCTRx, "bltctr")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBLTLRx, "bltlr")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBLRx, "blr")
+DEFINE_SUBMNEM_AA_LK_HINT(SubMnemBNEx, "bne")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBNECTRx, "bnectr")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBNELRx, "bnelr")
+DEFINE_SUBMNEM_AA_LK_HINT(SubMnemBNSx, "bns")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBNSCTRx, "bnsctr")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBNSLRx, "bnslr")
+DEFINE_SUBMNEM_AA_LK_HINT(SubMnemBSOx, "bso")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBSOCTRx, "bsoctr")
+DEFINE_SUBMNEM_LK_HINT(SubMnemBSOLRx, "bsolr")
+DEFINE_SUBMNEM_AA_LK(SubMnemBTx, "bt")
+DEFINE_SUBMNEM_AA_LK(SubMnemBTLRx, "btlr")
+DEFINE_SUBMNEM_RC(SubMnemCLRLDIx, "clrldi")
+DEFINE_SUBMNEM_RC(SubMnemCLRLWIx, "clrlwi")
+DEFINE_SUBMNEM_RC(SubMnemCLRRWIx, "clrrwi")
+DEFINE_SUBMNEM_RC(SubMnemCLRRDIx, "clrrdi")
+DEFINE_SUBMNEM_RC(SubMnemEXTLDIx, "extldi")
+DEFINE_SUBMNEM_RC(SubMnemEXTLWIx, "extlwi")
+DEFINE_SUBMNEM_RC(SubMnemEXTRWIx, "extrwi")
+DEFINE_SUBMNEM_RC(SubMnemEXTRDIx, "extrdi")
+DEFINE_SUBMNEM_RC(SubMnemCNTLZDx, "cntlzd")
+DEFINE_SUBMNEM_RC(SubMnemCNTLZWx, "cntlzw")
+DEFINE_SUBMNEM_RC(SubMnemCNTTZDx, "cnttzd")
+DEFINE_SUBMNEM_RC(SubMnemCNTTZWx, "cnttzw")
+DEFINE_SUBMNEM_OE_RC(SubMnemDIVDx, "divd")
+DEFINE_SUBMNEM_OE_RC(SubMnemDIVDEx, "divde")
+DEFINE_SUBMNEM_OE_RC(SubMnemDIVDEUx, "divdeu")
+DEFINE_SUBMNEM_OE_RC(SubMnemDIVDUx, "divdu")
+DEFINE_SUBMNEM_OE_RC(SubMnemDIVWx, "divw")
+DEFINE_SUBMNEM_OE_RC(SubMnemDIVWEx, "divwe")
+DEFINE_SUBMNEM_OE_RC(SubMnemDIVWEUx, "divweu")
+DEFINE_SUBMNEM_OE_RC(SubMnemDIVWUx, "divwu")
+DEFINE_SUBMNEM_RC(SubMnemEQVx, "eqv")
+DEFINE_SUBMNEM_RC(SubMnemEXTSBx, "extsb")
+DEFINE_SUBMNEM_RC(SubMnemEXTSHx, "extsh")
+DEFINE_SUBMNEM_RC(SubMnemEXTSWx, "extsw")
+DEFINE_SUBMNEM_RC(SubMnemEXTSWSLIx, "extswsli")
+DEFINE_SUBMNEM_RC(SubMnemFABSx, "fabs")
+DEFINE_SUBMNEM_RC(SubMnemFADDx, "fadd")
+DEFINE_SUBMNEM_RC(SubMnemFADDSx, "fadds")
+DEFINE_SUBMNEM_RC(SubMnemFCFIDx, "fcfid")
+DEFINE_SUBMNEM_RC(SubMnemFCFIDSx, "fcfids")
+DEFINE_SUBMNEM_RC(SubMnemFCFIDUx, "fcfidu")
+DEFINE_SUBMNEM_RC(SubMnemFCFIDUSx, "fcfidus")
+DEFINE_SUBMNEM_RC(SubMnemFCPSGNx, "fcpsgn")
+DEFINE_SUBMNEM_RC(SubMnemFCTIDx, "fctid")
+DEFINE_SUBMNEM_RC(SubMnemFCTIDUx, "fctidu")
+DEFINE_SUBMNEM_RC(SubMnemFCTIDUZx, "fctiduz")
+DEFINE_SUBMNEM_RC(SubMnemFCTIDZx, "fctidz")
+DEFINE_SUBMNEM_RC(SubMnemFCTIWx, "fctiw")
+DEFINE_SUBMNEM_RC(SubMnemFCTIWUx, "fctiwu")
+DEFINE_SUBMNEM_RC(SubMnemFCTIWUZx, "fctiwuz")
+DEFINE_SUBMNEM_RC(SubMnemFCTIWZx, "fctiwz")
+DEFINE_SUBMNEM_RC(SubMnemFDIVx, "fdiv")
+DEFINE_SUBMNEM_RC(SubMnemFDIVSx, "fdivs")
+DEFINE_SUBMNEM_RC(SubMnemFMADDx, "fmadd")
+DEFINE_SUBMNEM_RC(SubMnemFMADDSx, "fmadds")
+DEFINE_SUBMNEM_RC(SubMnemFMRx, "fmr")
+DEFINE_SUBMNEM_RC(SubMnemFMSUBx, "fmsub")
+DEFINE_SUBMNEM_RC(SubMnemFMSUBSx, "fmsubs")
+DEFINE_SUBMNEM_RC(SubMnemFMULx, "fmul")
+DEFINE_SUBMNEM_RC(SubMnemFMULSx, "fmuls")
+DEFINE_SUBMNEM_RC(SubMnemFNABSx, "fnabs")
+DEFINE_SUBMNEM_RC(SubMnemFNEGx, "fneg")
+DEFINE_SUBMNEM_RC(SubMnemFNMADDx, "fnmadd")
+DEFINE_SUBMNEM_RC(SubMnemFNMADDSx, "fnmadds")
+DEFINE_SUBMNEM_RC(SubMnemFNMSUBx, "fnmsub")
+DEFINE_SUBMNEM_RC(SubMnemFNMSUBSx, "fnmsubs")
+DEFINE_SUBMNEM_RC(SubMnemFREx, "fre")
+DEFINE_SUBMNEM_RC(SubMnemFRESx, "fres")
+DEFINE_SUBMNEM_RC(SubMnemFRIMx, "frim")
+DEFINE_SUBMNEM_RC(SubMnemFRINx, "frin")
+DEFINE_SUBMNEM_RC(SubMnemFRIPx, "frip")
+DEFINE_SUBMNEM_RC(SubMnemFRIZx, "friz")
+DEFINE_SUBMNEM_RC(SubMnemFRSPx, "frsp")
+DEFINE_SUBMNEM_RC(SubMnemFRSQRTEx, "frsqrte")
+DEFINE_SUBMNEM_RC(SubMnemFRSQRTESx, "frsqrtes")
+DEFINE_SUBMNEM_RC(SubMnemFSELx, "fsel")
+DEFINE_SUBMNEM_RC(SubMnemFSQRTx, "fsqrt")
+DEFINE_SUBMNEM_RC(SubMnemFSQRTSx, "fsqrts")
+DEFINE_SUBMNEM_RC(SubMnemFSUBx, "fsub")
+DEFINE_SUBMNEM_RC(SubMnemFSUBSx, "fsubs")
+DEFINE_SUBMNEM_RC(SubMnemMFFSx, "mffs")
+DEFINE_SUBMNEM_RC(SubMnemMTFSB0x, "mtfsb0")
+DEFINE_SUBMNEM_RC(SubMnemMTFSB1x, "mtfsb1")
+DEFINE_SUBMNEM_RC(SubMnemMTFSFx, "mtfsf")
+DEFINE_SUBMNEM_RC(SubMnemMTFSFIx, "mtfsfi")
+DEFINE_SUBMNEM_RC(SubMnemMRx, "mr")
+DEFINE_SUBMNEM_RC(SubMnemMULHDx, "mulhd")
+DEFINE_SUBMNEM_RC(SubMnemMULHDUx, "mulhdu")
+DEFINE_SUBMNEM_RC(SubMnemMULHWx, "mulhw")
+DEFINE_SUBMNEM_RC(SubMnemMULHWUx, "mulhwu")
+DEFINE_SUBMNEM_OE_RC(SubMnemMULLDx, "mulld")
+DEFINE_SUBMNEM_OE_RC(SubMnemMULLWx, "mullw")
+DEFINE_SUBMNEM_RC(SubMnemNANDx, "nand")
+DEFINE_SUBMNEM_OE_RC(SubMnemNEGx, "neg")
+DEFINE_SUBMNEM_RC(SubMnemNORx, "nor")
+DEFINE_SUBMNEM_RC(SubMnemORx, "or")
+DEFINE_SUBMNEM_RC(SubMnemORIx, "ori")
+DEFINE_SUBMNEM_RC(SubMnemORCx, "orc")
+DEFINE_SUBMNEM_RC(SubMnemRLDICLx, "rldicl")
+DEFINE_SUBMNEM_RC(SubMnemRLDICRx, "rldicr")
+DEFINE_SUBMNEM_RC(SubMnemRLDICx, "rldic")
+DEFINE_SUBMNEM_RC(SubMnemRLDIMIx, "rldimi")
+DEFINE_SUBMNEM_RC(SubMnemRLDCLx, "rldcl")
+DEFINE_SUBMNEM_RC(SubMnemRLDCRx, "rldcr")
+DEFINE_SUBMNEM_RC(SubMnemRLWIMIx, "rlwimi")
+DEFINE_SUBMNEM_RC(SubMnemRLWINMx, "rlwinm")
+DEFINE_SUBMNEM_RC(SubMnemRLWNMx, "rlwnm")
+DEFINE_SUBMNEM_RC(SubMnemROTLDx, "rotld")
+DEFINE_SUBMNEM_RC(SubMnemROTLDIx, "rotldi")
+DEFINE_SUBMNEM_RC(SubMnemROTLWx, "rotlw")
+DEFINE_SUBMNEM_RC(SubMnemROTLWIx, "rotlwi")
+DEFINE_SUBMNEM_RC(SubMnemROTRDIx, "rotrdi")
+DEFINE_SUBMNEM_RC(SubMnemROTRWIx, "rotrwi")
+DEFINE_SUBMNEM_RC(SubMnemSLDx, "sld")
+DEFINE_SUBMNEM_RC(SubMnemSLDIx, "sldi")
+DEFINE_SUBMNEM_RC(SubMnemSLWx, "slw")
+DEFINE_SUBMNEM_RC(SubMnemSLWIx, "slwi")
+DEFINE_SUBMNEM_RC(SubMnemSRADx, "srad")
+DEFINE_SUBMNEM_RC(SubMnemSRADIx, "sradi")
+DEFINE_SUBMNEM_RC(SubMnemSRAWx, "sraw")
+DEFINE_SUBMNEM_RC(SubMnemSRAWIx, "srawi")
+DEFINE_SUBMNEM_RC(SubMnemSRDx, "srd")
+DEFINE_SUBMNEM_RC(SubMnemSRDIx, "srdi")
+DEFINE_SUBMNEM_RC(SubMnemSRWx, "srw")
+DEFINE_SUBMNEM_RC(SubMnemSRWIx, "srwi")
+DEFINE_SUBMNEM_OE_RC(SubMnemSUBFx, "subf")
+DEFINE_SUBMNEM_OE_RC(SubMnemSUBFCx, "subfc")
+DEFINE_SUBMNEM_OE_RC(SubMnemSUBFEx, "subfe")
+DEFINE_SUBMNEM_OE_RC(SubMnemSUBFICx, "subfic")
+DEFINE_SUBMNEM_OE_RC(SubMnemSUBFMEx, "subfme")
+DEFINE_SUBMNEM_OE_RC(SubMnemSUBFZEx, "subfze")
+DEFINE_SUBMNEM_RC(SubMnemXORx, "xor")
+DEFINE_SUBMNEM_RC(SubMnemXORIx, "xori")
+
+// ALTIVEC MNEMONICS
+DEFINE_SUBMNEM_RC(SubMnemVCMPBFPx, "vcmpbfp");
+DEFINE_SUBMNEM_RC(SubMnemVCMPEQFPx, "vcmpeqfp");
+DEFINE_SUBMNEM_RC(SubMnemVCMPEQUBx, "vcmpequb");
+DEFINE_SUBMNEM_RC(SubMnemVCMPEQUDx, "vcmpequd");
+DEFINE_SUBMNEM_RC(SubMnemVCMPEQUHx, "vcmpequh");
+DEFINE_SUBMNEM_RC(SubMnemVCMPEQUWx, "vcmpequw");
+DEFINE_SUBMNEM_RC(SubMnemVCMPGEFPx, "vcmpgefp");
+DEFINE_SUBMNEM_RC(SubMnemVCMPGTFPx, "vcmpgtfp");
+DEFINE_SUBMNEM_RC(SubMnemVCMPGTSBx, "vcmpgtsb");
+DEFINE_SUBMNEM_RC(SubMnemVCMPGTSDx, "vcmpgtsd");
+DEFINE_SUBMNEM_RC(SubMnemVCMPGTSHx, "vcmpgtsh");
+DEFINE_SUBMNEM_RC(SubMnemVCMPGTSWx, "vcmpgtsw");
+DEFINE_SUBMNEM_RC(SubMnemVCMPGTUBx, "vcmpgtub");
+DEFINE_SUBMNEM_RC(SubMnemVCMPGTUDx, "vcmpgtud");
+DEFINE_SUBMNEM_RC(SubMnemVCMPGTUHx, "vcmpgtuh");
+DEFINE_SUBMNEM_RC(SubMnemVCMPGTUWx, "vcmpgtuw");
+DEFINE_SUBMNEM_RC(SubMnemVCMPNEBx, "vcmpneb");
+DEFINE_SUBMNEM_RC(SubMnemVCMPNEHx, "vcmpneh");
+DEFINE_SUBMNEM_RC(SubMnemVCMPNEWx, "vcmpnew");
+DEFINE_SUBMNEM_RC(SubMnemVCMPNEZBx, "vcmpnezb");
+DEFINE_SUBMNEM_RC(SubMnemVCMPNEZHx, "vcmpnezh");
+DEFINE_SUBMNEM_RC(SubMnemVCMPNEZWx, "vcmpnezw");
+
+// VSX MNEMONICS
+DEFINE_SUBMNEM_RC(SubMnemXVCMPEQDPx, "xvcmpeqdp");
+DEFINE_SUBMNEM_RC(SubMnemXVCMPEQSPx, "xvcmpeqsp");
+DEFINE_SUBMNEM_RC(SubMnemXVCMPGEDPx, "xvcmpgedp");
+DEFINE_SUBMNEM_RC(SubMnemXVCMPGESPx, "xvcmpgesp");
+DEFINE_SUBMNEM_RC(SubMnemXVCMPGTDPx, "xvcmpgtdp");
+DEFINE_SUBMNEM_RC(SubMnemXVCMPGTSPx, "xvcmpgtsp");
+DEFINE_SUBMNEM_ROUND2ODD(SubMnemXSADDQPx, "xsaddqp");
+DEFINE_SUBMNEM_ROUND2ODD(SubMnemXSCVQPDPx, "xscvqpdp");
+DEFINE_SUBMNEM_ROUND2ODD(SubMnemXSDIVQPx, "xsdivqp");
+DEFINE_SUBMNEM_ROUND2ODD(SubMnemXSMADDQPx, "xsmaddqp");
+DEFINE_SUBMNEM_ROUND2ODD(SubMnemXSMULQPx, "xsmulqp");
+DEFINE_SUBMNEM_ROUND2ODD(SubMnemXSMSUBQPx, "xsmsubqp");
+DEFINE_SUBMNEM_ROUND2ODD(SubMnemXSNMADDQPx, "xsnmaddqp");
+DEFINE_SUBMNEM_ROUND2ODD(SubMnemXSNMSUBQPx, "xsnmsubqp");
+DEFINE_SUBMNEM_ROUND2ODD(SubMnemXSSQRTQPx, "xssqrtqp");
+DEFINE_SUBMNEM_ROUND2ODD(SubMnemXSSUBQPx, "xssubqp");
+DEFINE_SUBMNEM_INEXACT(SubMnemXSRQPIx, "xsrqpi");
+
+// PAIREDSINGLE MNEMONICS
+DEFINE_SUBMNEM_RC(SubMnemPS_ABSx, "ps_abs");
+DEFINE_SUBMNEM_RC(SubMnemPS_ADDx, "ps_add");
+DEFINE_SUBMNEM_RC(SubMnemPS_DIVx, "ps_div");
+DEFINE_SUBMNEM_RC(SubMnemPS_MADDx, "ps_madd");
+DEFINE_SUBMNEM_RC(SubMnemPS_MADDS0x, "ps_madds0");
+DEFINE_SUBMNEM_RC(SubMnemPS_MADDS1x, "ps_madds1");
+DEFINE_SUBMNEM_RC(SubMnemPS_MERGE00x, "ps_merge00");
+DEFINE_SUBMNEM_RC(SubMnemPS_MERGE01x, "ps_merge01");
+DEFINE_SUBMNEM_RC(SubMnemPS_MERGE10x, "ps_merge10");
+DEFINE_SUBMNEM_RC(SubMnemPS_MERGE11x, "ps_merge11");
+DEFINE_SUBMNEM_RC(SubMnemPS_MRx, "ps_mr");
+DEFINE_SUBMNEM_RC(SubMnemPS_MSUBx, "ps_msub");
+DEFINE_SUBMNEM_RC(SubMnemPS_MULx, "ps_mul");
+DEFINE_SUBMNEM_RC(SubMnemPS_MULS0x, "ps_muls0");
+DEFINE_SUBMNEM_RC(SubMnemPS_MULS1x, "ps_muls1");
+DEFINE_SUBMNEM_RC(SubMnemPS_NABSx, "ps_nabs");
+DEFINE_SUBMNEM_RC(SubMnemPS_NEGx, "ps_neg");
+DEFINE_SUBMNEM_RC(SubMnemPS_NMADDx, "ps_nmadd");
+DEFINE_SUBMNEM_RC(SubMnemPS_NMSUBx, "ps_nmsub");
+DEFINE_SUBMNEM_RC(SubMnemPS_RESx, "ps_res");
+DEFINE_SUBMNEM_RC(SubMnemPS_RSQRTEx, "ps_rsqrte");
+DEFINE_SUBMNEM_RC(SubMnemPS_SELx, "ps_sel");
+DEFINE_SUBMNEM_RC(SubMnemPS_SUBx, "ps_sub");
+DEFINE_SUBMNEM_RC(SubMnemPS_SUM0x, "ps_sum0");
+DEFINE_SUBMNEM_RC(SubMnemPS_SUM1x, "ps_sum1");
+
+// VLE MNEMONICS
+DEFINE_SUBMNEM_RC(SubMnemVle32ADDIx, "e_addi");
+DEFINE_SUBMNEM_RC(SubMnemVle32ADDICx, "e_addic");
+DEFINE_SUBMNEM_RC(SubMnemVle32ANDIx, "e_andi");
+DEFINE_SUBMNEM_LK(SubMnemVle32Bx, "e_b");
+DEFINE_SUBMNEM_LK(SubMnemVle32BCx, "e_bc");
+DEFINE_SUBMNEM_LK(SubMnemVle32BDZx, "e_bdz");
+DEFINE_SUBMNEM_LK(SubMnemVle32BDNZx, "e_bdnz");
+DEFINE_SUBMNEM_LK(SubMnemVle32BEQx, "e_beq");
+DEFINE_SUBMNEM_LK(SubMnemVle32BGEx, "e_bge");
+DEFINE_SUBMNEM_LK(SubMnemVle32BGTx, "e_bgt");
+DEFINE_SUBMNEM_LK(SubMnemVle32BNEx, "e_bne");
+DEFINE_SUBMNEM_LK(SubMnemVle32BNSx, "e_bns");
+DEFINE_SUBMNEM_LK(SubMnemVle32BLEx, "e_ble");
+DEFINE_SUBMNEM_LK(SubMnemVle32BLTx, "e_blt");
+DEFINE_SUBMNEM_LK(SubMnemVle32BSOx, "e_bso");
+DEFINE_SUBMNEM_RC(SubMnemVle32ORIx, "e_ori");
+DEFINE_SUBMNEM_RC(SubMnemVle32RLWx, "e_rlw");
+DEFINE_SUBMNEM_RC(SubMnemVle32RLWIx, "e_rlwi");
+DEFINE_SUBMNEM_RC(SubMnemVle32SLWIx, "e_slwi");
+DEFINE_SUBMNEM_RC(SubMnemVle32SRWIx, "e_srwi");
+DEFINE_SUBMNEM_RC(SubMnemVle32SUBFICx, "e_subfic");
+DEFINE_SUBMNEM_RC(SubMnemVle32XORIx, "e_xori");
+
+DEFINE_SUBMNEM_RC(SubMnemVle16ANDx, "se_and");
+DEFINE_SUBMNEM_LK(SubMnemVle16Bx, "se_b");
+DEFINE_SUBMNEM_LK(SubMnemVle16BCTRx, "se_bctr");
+DEFINE_SUBMNEM_LK(SubMnemVle16BLRx, "se_blr");
+DEFINE_SUBMNEM_RC(SubMnemVle16SUBIx, "se_subi");
+
+static const char* RcMnemonic(const Instruction* instruction, const char* names[2])
+{
+ return names[instruction->flags.rc];
+}
+
+static const char* OeRcMnemonic(const Instruction* instruction, const char* names[4])
+{
+ return names[2*instruction->flags.oe + instruction->flags.rc];
+}
+
+static const char* LkMnemonic(const Instruction* instruction, const char* names[2])
+{
+ return names[instruction->flags.lk];
+}
+
+static const char* LkHintMnemonic(const Instruction* instruction, const char* names[8])
+{
+ return names[2*instruction->flags.branchLikelyHint + instruction->flags.lk];
+}
+
+static const char* AaLkMnemonic(const Instruction* instruction, const char* names[4])
+{
+ return names[2*instruction->flags.aa + instruction->flags.lk];
+}
+
+static const char* AaLkHintMnemonic(const Instruction* instruction, const char* names[16])
+{
+ return names[4*instruction->flags.branchLikelyHint + 2*instruction->flags.aa + instruction->flags.lk];
+}
+
+static const char* Round2OddMnemonic(const Instruction* instruction, const char* names[2])
+{
+ return names[instruction->flags.round2odd];
+}
+
+static const char* InexactMnemonic(const Instruction* instruction, const char* names[2])
+{
+ return names[instruction->flags.inexact];
+}
+
+const char* GetMnemonic(const Instruction* instruction)
+{
+ switch (instruction->id)
+ {
+ case PPC_ID_ADDx: return OeRcMnemonic(instruction, SubMnemADDx);
+ case PPC_ID_ADDCx: return OeRcMnemonic(instruction, SubMnemADDCx);
+ case PPC_ID_ADDEx: return OeRcMnemonic(instruction, SubMnemADDEx);
+ case PPC_ID_ADDIx: return OeRcMnemonic(instruction, SubMnemADDIx);
+ case PPC_ID_ADDICx: return RcMnemonic(instruction, SubMnemADDICx);
+ case PPC_ID_ADDIS: return "addis";
+ case PPC_ID_ADDMEx: return OeRcMnemonic(instruction, SubMnemADDMEx);
+ case PPC_ID_ADDPCIS: return "addpcis";
+ case PPC_ID_ADDZEx: return OeRcMnemonic(instruction, SubMnemADDZEx);
+ case PPC_ID_ANDx: return RcMnemonic(instruction, SubMnemANDx);
+ case PPC_ID_ANDCx: return RcMnemonic(instruction, SubMnemANDCx);
+ case PPC_ID_ANDIx: return RcMnemonic(instruction, SubMnemANDIx);
+ case PPC_ID_ANDIS: return "andis.";
+ case PPC_ID_ATTN: return "attn";
+ case PPC_ID_Bx: return AaLkMnemonic(instruction, SubMnemBx);
+ case PPC_ID_BCx:
+ {
+ uint32_t bo = instruction->operands[0].uimm;
+ uint32_t bi = instruction->operands[1].uimm;
+
+ const char** mnemonics = NULL;
+ const char** mnemonicsHint = NULL;
+
+ // mask away the "y" bit
+ switch (bo & 0x1e)
+ {
+ case 0:
+ mnemonics = SubMnemBDNZFx;
+ break;
+
+ case 2:
+ mnemonics = SubMnemBDZFx;
+ break;
+
+ case 4:
+ case 6:
+ switch (bi & 0x3)
+ {
+ case 0:
+ mnemonicsHint = SubMnemBGEx;
+ break;
+ case 1:
+ mnemonicsHint = SubMnemBLEx;
+ break;
+ case 2:
+ mnemonicsHint = SubMnemBNEx;
+ break;
+ case 3:
+ mnemonicsHint = SubMnemBNSx;
+ break;
+
+ // should be unreachable
+ default:
+ return NULL;
+ }
+
+ break;
+
+ case 8:
+ mnemonics = SubMnemBDNZTx;
+ break;
+
+ case 10:
+ mnemonics = SubMnemBDZTx;
+ break;
+
+ case 12:
+ case 14:
+ switch (bi & 0x3)
+ {
+ case 0:
+ mnemonicsHint = SubMnemBLTx;
+ break;
+
+ case 1:
+ mnemonicsHint = SubMnemBGTx;
+ break;
+
+ case 2:
+ mnemonicsHint = SubMnemBEQx;
+ break;
+
+ case 3:
+ mnemonicsHint = SubMnemBSOx;
+ break;
+
+ // should be unreachable
+ default:
+ return NULL;
+ }
+ break;
+
+ // technically these aren't terribly well defined
+ // when BI != 0, since these BOs don't involve
+ // a condition bit to test in BI to test against
+ case 16:
+ case 24:
+ mnemonicsHint = SubMnemBDNZx;
+ break;
+
+ // these represent "branch always" in the BO field, so it's
+ // not super clear why these disassemble to bdnz
+ case 20:
+ case 28:
+ mnemonicsHint = SubMnemBDNZx;
+ break;
+
+ case 18:
+ case 22:
+ case 26:
+ mnemonicsHint = SubMnemBDZx;
+ break;
+
+ // these represent "branch always" in the BO field, so it's
+ // not super clear why these disassemble to bdz
+ case 30:
+ mnemonicsHint = SubMnemBDZx;
+ break;
+
+ default:
+ mnemonics = SubMnemBCx;
+ }
+
+ if (mnemonicsHint)
+ return AaLkHintMnemonic(instruction, mnemonicsHint);
+
+ if (mnemonics)
+ return AaLkMnemonic(instruction, mnemonics);
+
+ // should be unreachable
+ return NULL;
+ }
+
+ case PPC_ID_BCCTRx:
+ {
+ uint32_t bo = instruction->operands[0].uimm;
+ uint32_t bi = instruction->operands[1].uimm;
+
+ // mask away the "y" bit
+ switch (bo & 0x1e)
+ {
+ case 4:
+ case 6:
+ switch (bi & 0x3)
+ {
+ case 0: return LkHintMnemonic(instruction, SubMnemBGECTRx);
+ case 1: return LkHintMnemonic(instruction, SubMnemBLECTRx);
+ case 2: return LkHintMnemonic(instruction, SubMnemBNECTRx);
+ case 3: return LkHintMnemonic(instruction, SubMnemBNSCTRx);
+
+ // should be unreachable
+ default: return NULL;
+ }
+
+ break;
+
+ case 12:
+ case 14:
+ switch (bi & 0x3)
+ {
+ case 0: return LkHintMnemonic(instruction, SubMnemBLTCTRx);
+ case 1: return LkHintMnemonic(instruction, SubMnemBGTCTRx);
+ case 2: return LkHintMnemonic(instruction, SubMnemBEQCTRx);
+ case 3: return LkHintMnemonic(instruction, SubMnemBSOCTRx);
+
+ // should be unreachable
+ default: return NULL;
+ }
+
+ break;
+
+ case 20:
+ return LkMnemonic(instruction, SubMnemBCTRx);
+
+ default:
+ return LkMnemonic(instruction, SubMnemBCCTRx);
+ }
+ }
+
+ case PPC_ID_BCLRx:
+ {
+ uint32_t bo = instruction->operands[0].uimm;
+ uint32_t bi = instruction->operands[1].uimm;
+
+ // mask away the "y" bit
+ switch (bo & 0x1e)
+ {
+ case 0:
+ return LkMnemonic(instruction, SubMnemBDNZFLRx);
+
+ case 2:
+ return LkMnemonic(instruction, SubMnemBDZFLRx);
+
+ case 4:
+ case 6:
+ switch (bi & 0x3)
+ {
+ case 0: return LkHintMnemonic(instruction, SubMnemBGELRx);
+ case 1: return LkHintMnemonic(instruction, SubMnemBLELRx);
+ case 2: return LkHintMnemonic(instruction, SubMnemBNELRx);
+ case 3: return LkHintMnemonic(instruction, SubMnemBNSLRx);
+
+ // should be unreachable
+ default: return NULL;
+ }
+
+ case 8:
+ return LkMnemonic(instruction, SubMnemBDNZTLRx);
+
+ case 10:
+ return LkMnemonic(instruction, SubMnemBDZTLRx);
+
+ case 12:
+ case 14:
+ switch (bi & 0x3)
+ {
+ case 0: return LkHintMnemonic(instruction, SubMnemBLTLRx);
+ case 1: return LkHintMnemonic(instruction, SubMnemBGTLRx);
+ case 2: return LkHintMnemonic(instruction, SubMnemBEQLRx);
+ case 3: return LkHintMnemonic(instruction, SubMnemBSOLRx);
+
+ // should be unreachable
+ default: return NULL;
+ }
+
+ // technically these aren't terribly well defined
+ // when BI != 0, since these BOs don't involve
+ // a condition bit to test in BI to test against
+ case 16:
+ case 24:
+ return LkHintMnemonic(instruction, SubMnemBDNZLRx);
+
+ case 18:
+ case 26:
+ return LkHintMnemonic(instruction, SubMnemBDZLRx);
+
+ case 20:
+ return LkHintMnemonic(instruction, SubMnemBLRx);
+
+ default:
+ return LkMnemonic(instruction, SubMnemBCLRx);
+ }
+ }
+
+ case PPC_ID_BPERMD: return "bpermd";
+ case PPC_ID_CLRBHRB: return "clrbhrb";
+ case PPC_ID_CLRLDIx: return RcMnemonic(instruction, SubMnemCLRLDIx);
+ case PPC_ID_CLRRDIx: return RcMnemonic(instruction, SubMnemCLRRDIx);
+ case PPC_ID_CLRLWIx: return RcMnemonic(instruction, SubMnemCLRLWIx);
+ case PPC_ID_CLRRWIx: return RcMnemonic(instruction, SubMnemCLRRWIx);
+ case PPC_ID_CMPB: return "cmpb";
+ case PPC_ID_CMPD: return "cmpd";
+ case PPC_ID_CMPDI: return "cmpdi";
+ case PPC_ID_CMPEQB: return "cmpeqb";
+ case PPC_ID_CMPRB: return "cmprb";
+ case PPC_ID_CMPW: return "cmpw";
+ case PPC_ID_CMPWI: return "cmpwi";
+ case PPC_ID_CMPLD: return "cmpld";
+ case PPC_ID_CMPLDI: return "cmpldi";
+ case PPC_ID_CMPLW: return "cmplw";
+ case PPC_ID_CMPLWI: return "cmplwi";
+ case PPC_ID_CNTLZDx: return RcMnemonic(instruction, SubMnemCNTLZDx);
+ case PPC_ID_CNTLZWx: return RcMnemonic(instruction, SubMnemCNTLZWx);
+ case PPC_ID_CNTTZDx: return RcMnemonic(instruction, SubMnemCNTTZDx);
+ case PPC_ID_CNTTZWx: return RcMnemonic(instruction, SubMnemCNTTZWx);
+ case PPC_ID_COPY: return "copy";
+ case PPC_ID_CP_ABORT: return "cp_abort";
+ case PPC_ID_CRAND: return "crand";
+ case PPC_ID_CRANDC: return "crandc";
+ case PPC_ID_CRCLR: return "crclr";
+ case PPC_ID_CREQV: return "creqv";
+ case PPC_ID_CRMOVE: return "crmove";
+ case PPC_ID_CRNAND: return "crnand";
+ case PPC_ID_CRNOR: return "crnor";
+ case PPC_ID_CRNOT: return "crnot";
+ case PPC_ID_CROR: return "cror";
+ case PPC_ID_CRORC: return "crorc";
+ case PPC_ID_CRSET: return "crset";
+ case PPC_ID_CRXOR: return "crxor";
+ case PPC_ID_DARN: return "darn";
+ case PPC_ID_DCBA: return "dcba";
+ case PPC_ID_DCBF: return "dcbf";
+ case PPC_ID_DCBFEP: return "dcbfep";
+ case PPC_ID_DCBFL: return "dcbfl";
+ case PPC_ID_DCBFLP: return "dcbflp";
+ case PPC_ID_DCBI: return "dcbi";
+ case PPC_ID_DCBST: return "dcbst";
+ case PPC_ID_DCBSTEP: return "dcbstep";
+ case PPC_ID_DCBT: return "dcbt";
+ case PPC_ID_DCBTT: return "dcbtt";
+ case PPC_ID_DCBTEP: return "dcbtep";
+ case PPC_ID_DCBTST: return "dcbtst";
+ case PPC_ID_DCBTSTEP: return "dcbtstep";
+ case PPC_ID_DCBTSTT: return "dcbtstt";
+ case PPC_ID_DCBZ: return "dcbz";
+ case PPC_ID_DCBZEP: return "dcbzep";
+ case PPC_ID_DCBZL: return "dcbzl";
+ case PPC_ID_DCCCI: return "dccci";
+ case PPC_ID_DCI: return "dci";
+ case PPC_ID_DIVDx: return OeRcMnemonic(instruction, SubMnemDIVDx);
+ case PPC_ID_DIVDEx: return OeRcMnemonic(instruction, SubMnemDIVDEx);
+ case PPC_ID_DIVDEUx: return OeRcMnemonic(instruction, SubMnemDIVDEUx);
+ case PPC_ID_DIVDUx: return OeRcMnemonic(instruction, SubMnemDIVDUx);
+ case PPC_ID_DIVWx: return OeRcMnemonic(instruction, SubMnemDIVWx);
+ case PPC_ID_DIVWEx: return OeRcMnemonic(instruction, SubMnemDIVWEx);
+ case PPC_ID_DIVWEUx: return OeRcMnemonic(instruction, SubMnemDIVWEUx);
+ case PPC_ID_DIVWUx: return OeRcMnemonic(instruction, SubMnemDIVWUx);
+ case PPC_ID_ECIWX: return "eciwx";
+ case PPC_ID_ECOWX: return "ecowx";
+ case PPC_ID_EIEIO: return "eieio";
+ case PPC_ID_EQVx: return RcMnemonic(instruction, SubMnemEQVx);
+ case PPC_ID_EXTLDIx: return RcMnemonic(instruction, SubMnemEXTLDIx);
+ case PPC_ID_EXTRDIx: return RcMnemonic(instruction, SubMnemEXTRDIx);
+ case PPC_ID_EXTLWIx: return RcMnemonic(instruction, SubMnemEXTLWIx);
+ case PPC_ID_EXTRWIx: return RcMnemonic(instruction, SubMnemEXTRWIx);
+ case PPC_ID_EXTSBx: return RcMnemonic(instruction, SubMnemEXTSBx);
+ case PPC_ID_EXTSHx: return RcMnemonic(instruction, SubMnemEXTSHx);
+ case PPC_ID_EXTSWx: return RcMnemonic(instruction, SubMnemEXTSWx);
+ case PPC_ID_EXTSWSLIx: return RcMnemonic(instruction, SubMnemEXTSWSLIx);
+ case PPC_ID_FABSx: return RcMnemonic(instruction, SubMnemFABSx);
+ case PPC_ID_FADDx: return RcMnemonic(instruction, SubMnemFADDx);
+ case PPC_ID_FADDSx: return RcMnemonic(instruction, SubMnemFADDSx);
+ case PPC_ID_FCFIDx: return RcMnemonic(instruction, SubMnemFCFIDx);
+ case PPC_ID_FCFIDSx: return RcMnemonic(instruction, SubMnemFCFIDSx);
+ case PPC_ID_FCFIDUx: return RcMnemonic(instruction, SubMnemFCFIDUx);
+ case PPC_ID_FCFIDUSx: return RcMnemonic(instruction, SubMnemFCFIDUSx);
+ case PPC_ID_FCMPO: return "fcmpo";
+ case PPC_ID_FCMPU: return "fcmpu";
+ case PPC_ID_FCPSGNx: return RcMnemonic(instruction, SubMnemFCPSGNx);
+ case PPC_ID_FCTIDx: return RcMnemonic(instruction, SubMnemFCTIDx);
+ case PPC_ID_FCTIDUx: return RcMnemonic(instruction, SubMnemFCTIDUx);
+ case PPC_ID_FCTIDUZx: return RcMnemonic(instruction, SubMnemFCTIDUZx);
+ case PPC_ID_FCTIDZx: return RcMnemonic(instruction, SubMnemFCTIDZx);
+ case PPC_ID_FCTIWx: return RcMnemonic(instruction, SubMnemFCTIWx);
+ case PPC_ID_FCTIWUx: return RcMnemonic(instruction, SubMnemFCTIWUx);
+ case PPC_ID_FCTIWUZx: return RcMnemonic(instruction, SubMnemFCTIWUZx);
+ case PPC_ID_FCTIWZx: return RcMnemonic(instruction, SubMnemFCTIWZx);
+ case PPC_ID_FDIVx: return RcMnemonic(instruction, SubMnemFDIVx);
+ case PPC_ID_FDIVSx: return RcMnemonic(instruction, SubMnemFDIVSx);
+ case PPC_ID_FMADDx: return RcMnemonic(instruction, SubMnemFMADDx);
+ case PPC_ID_FMADDSx: return RcMnemonic(instruction, SubMnemFMADDSx);
+ case PPC_ID_FMRx: return RcMnemonic(instruction, SubMnemFMRx);
+ case PPC_ID_FMSUBx: return RcMnemonic(instruction, SubMnemFMSUBx);
+ case PPC_ID_FMSUBSx: return RcMnemonic(instruction, SubMnemFMSUBSx);
+ case PPC_ID_FMULx: return RcMnemonic(instruction, SubMnemFMULx);
+ case PPC_ID_FMULSx: return RcMnemonic(instruction, SubMnemFMULSx);
+ case PPC_ID_FNABSx: return RcMnemonic(instruction, SubMnemFNABSx);
+ case PPC_ID_FNEGx: return RcMnemonic(instruction, SubMnemFNEGx);
+ case PPC_ID_FNMADDx: return RcMnemonic(instruction, SubMnemFNMADDx);
+ case PPC_ID_FNMADDSx: return RcMnemonic(instruction, SubMnemFNMADDSx);
+ case PPC_ID_FNMSUBx: return RcMnemonic(instruction, SubMnemFNMSUBx);
+ case PPC_ID_FNMSUBSx: return RcMnemonic(instruction, SubMnemFNMSUBSx);
+ case PPC_ID_FREx: return RcMnemonic(instruction, SubMnemFREx);
+ case PPC_ID_FRESx: return RcMnemonic(instruction, SubMnemFRESx);
+ case PPC_ID_FRIMx: return RcMnemonic(instruction, SubMnemFRIMx);
+ case PPC_ID_FRINx: return RcMnemonic(instruction, SubMnemFRINx);
+ case PPC_ID_FRIPx: return RcMnemonic(instruction, SubMnemFRIPx);
+ case PPC_ID_FRIZx: return RcMnemonic(instruction, SubMnemFRIZx);
+ case PPC_ID_FRSPx: return RcMnemonic(instruction, SubMnemFRSPx);
+ case PPC_ID_FRSQRTEx: return RcMnemonic(instruction, SubMnemFRSQRTEx);
+ case PPC_ID_FRSQRTESx: return RcMnemonic(instruction, SubMnemFRSQRTESx);
+ case PPC_ID_FSELx: return RcMnemonic(instruction, SubMnemFSELx);
+ case PPC_ID_FSQRTx: return RcMnemonic(instruction, SubMnemFSQRTx);
+ case PPC_ID_FSQRTSx: return RcMnemonic(instruction, SubMnemFSQRTSx);
+ case PPC_ID_FSUBx: return RcMnemonic(instruction, SubMnemFSUBx);
+ case PPC_ID_FSUBSx: return RcMnemonic(instruction, SubMnemFSUBSx);
+ case PPC_ID_FTDIV: return "ftdiv";
+ case PPC_ID_FTSQRT: return "ftsqrt";
+ case PPC_ID_HRFID: return "hrfid";
+ case PPC_ID_ICBI: return "icbi";
+ case PPC_ID_ICBIEP: return "icbiep";
+ case PPC_ID_ICBLC: return "icblc";
+ case PPC_ID_ICBLQ: return "icblq.";
+ case PPC_ID_ICBT: return "icbt";
+ case PPC_ID_ICBTLS: return "icbtls";
+ case PPC_ID_ICCCI: return "iccci";
+ case PPC_ID_ICI: return "ici";
+ case PPC_ID_ISEL: return "isel";
+ case PPC_ID_ISYNC: return "isync";
+ case PPC_ID_LBARX: return "lbarx";
+ case PPC_ID_LBEPX: return "lbepx";
+ case PPC_ID_LBZ: return "lbz";
+ case PPC_ID_LBZCIX: return "lbzcix";
+ case PPC_ID_LBZU: return "lbzu";
+ case PPC_ID_LBZUX: return "lbzux";
+ case PPC_ID_LBZX: return "lbzx";
+ case PPC_ID_LDARX: return "ldarx";
+ case PPC_ID_LDAT: return "ldat";
+ case PPC_ID_LDBRX: return "ldbrx";
+ case PPC_ID_LDCIX: return "ldcix";
+ case PPC_ID_LD: return "ld";
+ case PPC_ID_LDU: return "ldu";
+ case PPC_ID_LDUX: return "ldux";
+ case PPC_ID_LDX: return "ldx";
+ case PPC_ID_LFD: return "lfd";
+ case PPC_ID_LFDEPX: return "lfdepx";
+ case PPC_ID_LFDU: return "lfdu";
+ case PPC_ID_LFDUX: return "lfdux";
+ case PPC_ID_LFDX: return "lfdx";
+ case PPC_ID_LFIWAX: return "lfiwax";
+ case PPC_ID_LFIWZX: return "lfiwzx";
+ case PPC_ID_LFS: return "lfs";
+ case PPC_ID_LFSU: return "lfsu";
+ case PPC_ID_LFSUX: return "lfsux";
+ case PPC_ID_LFSX: return "lfsx";
+ case PPC_ID_LHA: return "lha";
+ case PPC_ID_LHARX: return "lharx";
+ case PPC_ID_LHAU: return "lhau";
+ case PPC_ID_LHAUX: return "lhaux";
+ case PPC_ID_LHAX: return "lhax";
+ case PPC_ID_LHBRX: return "lhbrx";
+ case PPC_ID_LHEPX: return "lhepx";
+ case PPC_ID_LHZ: return "lhz";
+ case PPC_ID_LHZCIX: return "lhzcix";
+ case PPC_ID_LHZU: return "lhzu";
+ case PPC_ID_LHZUX: return "lhzux";
+ case PPC_ID_LHZX: return "lhzx";
+ case PPC_ID_LI: return "li";
+ case PPC_ID_LIS: return "lis";
+ case PPC_ID_LMW: return "lmw";
+ case PPC_ID_LNIA: return "lnia";
+ case PPC_ID_LSWI: return "lswi";
+ case PPC_ID_LSWX: return "lswx";
+ case PPC_ID_LWA: return "lwa";
+ case PPC_ID_LWAT: return "lwat";
+ case PPC_ID_LWAX: return "lwax";
+ case PPC_ID_LWARX: return "lwarx";
+ case PPC_ID_LWAUX: return "lwaux";
+ case PPC_ID_LWBRX: return "lwbrx";
+ case PPC_ID_LWEPX: return "lwepx";
+ case PPC_ID_LWSYNC: return "lwsync";
+ case PPC_ID_LWZ: return "lwz";
+ case PPC_ID_LWZCIX: return "lwzcix";
+ case PPC_ID_LWZU: return "lwzu";
+ case PPC_ID_LWZUX: return "lwzux";
+ case PPC_ID_LWZX: return "lwzx";
+ case PPC_ID_MBAR: return "mbar";
+ case PPC_ID_MCRF: return "mcrf";
+ case PPC_ID_MCRFS: return "mcrfs";
+ case PPC_ID_MCRXR: return "mcrxr";
+ case PPC_ID_MCRXRX: return "mcrxrx";
+ case PPC_ID_MFBHRBE: return "mfbhrbe";
+ case PPC_ID_MFBR0: return "mfbr0";
+ case PPC_ID_MFBR1: return "mfbr1";
+ case PPC_ID_MFBR2: return "mfbr2";
+ case PPC_ID_MFBR3: return "mfbr3";
+ case PPC_ID_MFBR4: return "mfbr4";
+ case PPC_ID_MFBR5: return "mfbr5";
+ case PPC_ID_MFBR6: return "mfbr6";
+ case PPC_ID_MFBR7: return "mfbr7";
+ case PPC_ID_MFCR: return "mfcr";
+ case PPC_ID_MFCTR: return "mfctr";
+ case PPC_ID_MFDCR: return "mfdcr";
+ case PPC_ID_MFDCRUX: return "mfdcrux";
+ case PPC_ID_MFDCRX: return "mfdcrx";
+ case PPC_ID_MFFSx: return RcMnemonic(instruction, SubMnemMFFSx);
+ case PPC_ID_MFFSCDRN: return "mffscdrn";
+ case PPC_ID_MFFSCDRNI: return "mffscdrni";
+ case PPC_ID_MFFSCE: return "mffsce";
+ case PPC_ID_MFFSCRN: return "mffscrn";
+ case PPC_ID_MFFSCRNI: return "mffscrni";
+ case PPC_ID_MFFSL: return "mffsl";
+ case PPC_ID_MFLR: return "mflr";
+ case PPC_ID_MFMSR: return "mfmsr";
+ case PPC_ID_MFOCRF: return "mfocrf";
+ case PPC_ID_MFPMR: return "mfpmr";
+ case PPC_ID_MFSPR: return "mfspr";
+ case PPC_ID_MFSR: return "mfsr";
+ case PPC_ID_MFSRIN: return "mfsrin";
+ case PPC_ID_MFTB: return "mftb";
+ case PPC_ID_MFTBU: return "mftbu";
+ case PPC_ID_MFXER: return "mfxer";
+ case PPC_ID_MRx: return RcMnemonic(instruction, SubMnemMRx);
+ case PPC_ID_MSGSYNC: return "msgsync";
+ case PPC_ID_MTAMR: return "mtamr";
+ case PPC_ID_MTBR0: return "mtbr0";
+ case PPC_ID_MTBR1: return "mtbr1";
+ case PPC_ID_MTBR2: return "mtbr2";
+ case PPC_ID_MTBR3: return "mtbr3";
+ case PPC_ID_MTBR4: return "mtbr4";
+ case PPC_ID_MTBR5: return "mtbr5";
+ case PPC_ID_MTBR6: return "mtbr6";
+ case PPC_ID_MTBR7: return "mtbr7";
+ case PPC_ID_MTCRF: return "mtcrf";
+ case PPC_ID_MTCTR: return "mtctr";
+ case PPC_ID_MTDCR: return "mtdcr";
+ case PPC_ID_MTDCRUX: return "mtdcrux";
+ case PPC_ID_MTDCRX: return "mtdcrx";
+ case PPC_ID_MTFSB0x: return RcMnemonic(instruction, SubMnemMTFSB0x);
+ case PPC_ID_MTFSB1x: return RcMnemonic(instruction, SubMnemMTFSB1x);
+ case PPC_ID_MTFSFx: return RcMnemonic(instruction, SubMnemMTFSFx);
+ case PPC_ID_MTFSFIx: return RcMnemonic(instruction, SubMnemMTFSFIx);
+ case PPC_ID_MODSD: return "modsd";
+ case PPC_ID_MODSW: return "modsw";
+ case PPC_ID_MODUD: return "modud";
+ case PPC_ID_MODUW: return "moduw";
+ case PPC_ID_MTLR: return "mtlr";
+ case PPC_ID_MTMSR: return "mtmsr";
+ case PPC_ID_MTMSRD: return "mtmsrd";
+ case PPC_ID_MTOCRF: return "mtocrf";
+ case PPC_ID_MTPMR: return "mtpmr";
+ case PPC_ID_MTSPR: return "mtspr";
+ case PPC_ID_MTSR: return "mtsr";
+ case PPC_ID_MTSRIN: return "mtsrin";
+ case PPC_ID_MTXER: return "mtxer";
+ case PPC_ID_MULHDx: return RcMnemonic(instruction, SubMnemMULHDx);
+ case PPC_ID_MULHDUx: return RcMnemonic(instruction, SubMnemMULHDUx);
+ case PPC_ID_MULHWx: return RcMnemonic(instruction, SubMnemMULHWx);
+ case PPC_ID_MULHWUx: return RcMnemonic(instruction, SubMnemMULHWUx);
+ case PPC_ID_MULLI: return "mulli";
+ case PPC_ID_MULLDx: return OeRcMnemonic(instruction, SubMnemMULLDx);
+ case PPC_ID_MULLWx: return OeRcMnemonic(instruction, SubMnemMULLWx);
+ case PPC_ID_NANDx: return RcMnemonic(instruction, SubMnemNANDx);
+ case PPC_ID_NAP: return "nap";
+ case PPC_ID_NEGx: return OeRcMnemonic(instruction, SubMnemNEGx);
+ case PPC_ID_NOP: return "nop";
+ case PPC_ID_NORx: return RcMnemonic(instruction, SubMnemNORx);
+ case PPC_ID_ORx: return RcMnemonic(instruction, SubMnemORx);
+ case PPC_ID_ORCx: return RcMnemonic(instruction, SubMnemORCx);
+ case PPC_ID_ORIx: return RcMnemonic(instruction, SubMnemORIx);
+ case PPC_ID_ORIS: return "oris";
+ case PPC_ID_PASTE: return "paste.";
+ case PPC_ID_POPCNTB: return "popcntb";
+ case PPC_ID_POPCNTD: return "popcntd";
+ case PPC_ID_POPCNTW: return "popcntw";
+ case PPC_ID_PTESYNC: return "ptesync";
+ case PPC_ID_RFCI: return "rfci";
+ case PPC_ID_RFDI: return "rfdi";
+ case PPC_ID_RFEBB: return "rfebb";
+ case PPC_ID_RFI: return "rfi";
+ case PPC_ID_RFID: return "rfid";
+ case PPC_ID_RFMCI: return "rfmci";
+ case PPC_ID_RLDICLx: return RcMnemonic(instruction, SubMnemRLDICLx);
+ case PPC_ID_RLDICRx: return RcMnemonic(instruction, SubMnemRLDICRx);
+ case PPC_ID_RLDICx: return RcMnemonic(instruction, SubMnemRLDICx);
+ case PPC_ID_RLDIMIx: return RcMnemonic(instruction, SubMnemRLDIMIx);
+ case PPC_ID_RLDCLx: return RcMnemonic(instruction, SubMnemRLDCLx);
+ case PPC_ID_RLDCRx: return RcMnemonic(instruction, SubMnemRLDCRx);
+ case PPC_ID_RLWIMIx: return RcMnemonic(instruction, SubMnemRLWIMIx);
+ case PPC_ID_RLWINMx: return RcMnemonic(instruction, SubMnemRLWINMx);
+ case PPC_ID_RLWNMx: return RcMnemonic(instruction, SubMnemRLWNMx);
+ case PPC_ID_ROTLDx: return RcMnemonic(instruction, SubMnemROTLDx);
+ case PPC_ID_ROTLDIx: return RcMnemonic(instruction, SubMnemROTLDIx);
+ case PPC_ID_ROTLWx: return RcMnemonic(instruction, SubMnemROTLWx);
+ case PPC_ID_ROTLWIx: return RcMnemonic(instruction, SubMnemROTLWIx);
+ case PPC_ID_ROTRDIx: return RcMnemonic(instruction, SubMnemROTRDIx);
+ case PPC_ID_ROTRWIx: return RcMnemonic(instruction, SubMnemROTRWIx);
+ case PPC_ID_SC: return "sc";
+ case PPC_ID_SETB: return "setb";
+ case PPC_ID_SLBIA: return "slbia";
+ case PPC_ID_SLBIE: return "slbie";
+ case PPC_ID_SLBIEG: return "slbieg";
+ case PPC_ID_SLBMFEE: return "slbmfee";
+ case PPC_ID_SLBMFEV: return "slbmfev";
+ case PPC_ID_SLBMTE: return "slbmte";
+ case PPC_ID_SLBSYNC: return "slbsync";
+ case PPC_ID_SLDx: return RcMnemonic(instruction, SubMnemSLDx);
+ case PPC_ID_SLDIx: return RcMnemonic(instruction, SubMnemSLDIx);
+ case PPC_ID_SLWx: return RcMnemonic(instruction, SubMnemSLWx);
+ case PPC_ID_SLWIx: return RcMnemonic(instruction, SubMnemSLWIx);
+ case PPC_ID_SRADx: return RcMnemonic(instruction, SubMnemSRADx);
+ case PPC_ID_SRADIx: return RcMnemonic(instruction, SubMnemSRADIx);
+ case PPC_ID_SRAWx: return RcMnemonic(instruction, SubMnemSRAWx);
+ case PPC_ID_SRAWIx: return RcMnemonic(instruction, SubMnemSRAWIx);
+ case PPC_ID_SRDx: return RcMnemonic(instruction, SubMnemSRDx);
+ case PPC_ID_SRDIx: return RcMnemonic(instruction, SubMnemSRDIx);
+ case PPC_ID_SRWx: return RcMnemonic(instruction, SubMnemSRWx);
+ case PPC_ID_SRWIx: return RcMnemonic(instruction, SubMnemSRWIx);
+ case PPC_ID_STB: return "stb";
+ case PPC_ID_STBCIX: return "stbcix";
+ case PPC_ID_STBCX: return "stbcx.";
+ case PPC_ID_STBEPX: return "stbepx";
+ case PPC_ID_STBU: return "stbu";
+ case PPC_ID_STBUX: return "stbux";
+ case PPC_ID_STBX: return "stbx";
+ case PPC_ID_STD: return "std";
+ case PPC_ID_STDAT: return "stdat";
+ case PPC_ID_STDBRX: return "stdbrx";
+ case PPC_ID_STDCIX: return "stdcix";
+ case PPC_ID_STDCX: return "stdcx.";
+ case PPC_ID_STDEPX: return "stdepx";
+ case PPC_ID_STDU: return "stdu";
+ case PPC_ID_STDUX: return "stdux";
+ case PPC_ID_STDX: return "stdx";
+ case PPC_ID_STFD: return "stfd";
+ case PPC_ID_STFDEPX: return "stfdepx";
+ case PPC_ID_STFDU: return "stfdu";
+ case PPC_ID_STFDUX: return "stfdux";
+ case PPC_ID_STFDX: return "stfdx";
+ case PPC_ID_STFIWX: return "stfiwx";
+ case PPC_ID_STFS: return "stfs";
+ case PPC_ID_STFSU: return "stfsu";
+ case PPC_ID_STFSUX: return "stfsux";
+ case PPC_ID_STFSX: return "stfsx";
+ case PPC_ID_STH: return "sth";
+ case PPC_ID_STHBRX: return "sthbrx";
+ case PPC_ID_STHCIX: return "sthcix";
+ case PPC_ID_STHCX: return "sthcx.";
+ case PPC_ID_STHEPX: return "sthepx";
+ case PPC_ID_STHU: return "sthu";
+ case PPC_ID_STHUX: return "sthux";
+ case PPC_ID_STHX: return "sthx";
+ case PPC_ID_STMW: return "stmw";
+ case PPC_ID_STOP: return "stop";
+ case PPC_ID_STSWI: return "stswi";
+ case PPC_ID_STSWX: return "stswx";
+ case PPC_ID_STW: return "stw";
+ case PPC_ID_STWAT: return "stwat";
+ case PPC_ID_STWBRX: return "stwbrx";
+ case PPC_ID_STWCIX: return "stwcix";
+ case PPC_ID_STWCX: return "stwcx.";
+ case PPC_ID_STWEPX: return "stwepx";
+ case PPC_ID_STWU: return "stwu";
+ case PPC_ID_STWUX: return "stwux";
+ case PPC_ID_STWX: return "stwx";
+ case PPC_ID_SUBFx: return OeRcMnemonic(instruction, SubMnemSUBFx);
+ case PPC_ID_SUBFCx: return OeRcMnemonic(instruction, SubMnemSUBFCx);
+ case PPC_ID_SUBFEx: return OeRcMnemonic(instruction, SubMnemSUBFEx);
+ case PPC_ID_SUBFICx: return OeRcMnemonic(instruction, SubMnemSUBFICx);
+ case PPC_ID_SUBFMEx: return OeRcMnemonic(instruction, SubMnemSUBFMEx);
+ case PPC_ID_SUBFZEx: return OeRcMnemonic(instruction, SubMnemSUBFZEx);
+ case PPC_ID_SYNC: return "sync";
+ case PPC_ID_TABORT: return "tabort.";
+ case PPC_ID_TABORTDC: return "tabortdc.";
+ case PPC_ID_TABORTDCI: return "tabortdci.";
+ case PPC_ID_TABORTWC: return "tabortwc.";
+ case PPC_ID_TABORTWCI: return "tabortwci.";
+ case PPC_ID_TBEGIN: return "tbegin.";
+ case PPC_ID_TCHECK: return "tcheck";
+ case PPC_ID_TD: return "td";
+ case PPC_ID_TDEQ: return "tdeq";
+ case PPC_ID_TDEQI: return "tdeqi";
+ case PPC_ID_TDGT: return "tdgt";
+ case PPC_ID_TDGTI: return "tdgti";
+ case PPC_ID_TDI: return "tdi";
+ case PPC_ID_TDLGT: return "tdlgt";
+ case PPC_ID_TDLGTI: return "tdlgti";
+ case PPC_ID_TDLLT: return "tdllt";
+ case PPC_ID_TDLLTI: return "tdllti";
+ case PPC_ID_TDLT: return "tdlt";
+ case PPC_ID_TDLTI: return "tdlti";
+ case PPC_ID_TDNE: return "tdne";
+ case PPC_ID_TDNEI: return "tdnei";
+ case PPC_ID_TDU: return "tdu";
+ case PPC_ID_TDUI: return "tdui";
+ case PPC_ID_TEND: return "tend.";
+ case PPC_ID_TLBIA: return "tlbia";
+ case PPC_ID_TLBIE: return "tlbie";
+ case PPC_ID_TLBIEL: return "tlbiel";
+ case PPC_ID_TLBIVAX: return "tlbivax";
+ case PPC_ID_TLBLI: return "tlbli";
+ case PPC_ID_TLBSX: return "tlbsx";
+ case PPC_ID_TLBSYNC: return "tlbsync";
+ case PPC_ID_TLBRE: return "tlbre";
+ case PPC_ID_TLBRELO: return "tlbrehi";
+ case PPC_ID_TLBREHI: return "tlbrelo";
+ case PPC_ID_TLBWE: return "tlbwe";
+ case PPC_ID_TLBWEHI: return "tlbwehi";
+ case PPC_ID_TLBWELO: return "tlbwelo";
+ case PPC_ID_TRAP: return "trap";
+ case PPC_ID_TRECHKPT: return "trechkpt.";
+ case PPC_ID_TRECLAIM: return "treclaim.";
+ case PPC_ID_TSR: return "tsr.";
+ case PPC_ID_TW: return "tw";
+ case PPC_ID_TWEQ: return "tweq";
+ case PPC_ID_TWEQI: return "tweqi";
+ case PPC_ID_TWGT: return "twgt";
+ case PPC_ID_TWGTI: return "twgti";
+ case PPC_ID_TWGEI: return "twgei";
+ case PPC_ID_TWI: return "twi";
+ case PPC_ID_TWLEI: return "twlei";
+ case PPC_ID_TWLLEI: return "twllei";
+ case PPC_ID_TWLGT: return "twlgt";
+ case PPC_ID_TWLGTI: return "twlgti";
+ case PPC_ID_TWLLT: return "twllt";
+ case PPC_ID_TWLLTI: return "twllti";
+ case PPC_ID_TWLT: return "twlt";
+ case PPC_ID_TWLTI: return "twlti";
+ case PPC_ID_TWNE: return "twne";
+ case PPC_ID_TWNEI: return "twnei";
+ case PPC_ID_TWU: return "twu";
+ case PPC_ID_TWUI: return "twui";
+ case PPC_ID_WAIT: return "wait";
+ case PPC_ID_WAITIMPL: return "waitimpl";
+ case PPC_ID_WAITRSV: return "waitrsv";
+ case PPC_ID_WRTEE: return "wrtee";
+ case PPC_ID_WRTEEI: return "wrteei";
+ case PPC_ID_XNOP: return "xnop";
+ case PPC_ID_XORx: return RcMnemonic(instruction, SubMnemXORx);
+ case PPC_ID_XORIx: return RcMnemonic(instruction, SubMnemXORIx);
+ case PPC_ID_XORIS: return "xoris";
+
+ case PPC_ID_AV_VABSDUB: return "vabsdub";
+ case PPC_ID_AV_VABSDUH: return "vabsduh";
+ case PPC_ID_AV_VABSDUW: return "vabsduw";
+ case PPC_ID_AV_VADDUQM: return "vadduqm";
+ case PPC_ID_AV_VADDCUQ: return "vaddcuq";
+ case PPC_ID_AV_BCDADD: return "bcdadd.";
+ case PPC_ID_AV_BCDCFN: return "bcdcfn.";
+ case PPC_ID_AV_BCDCFSQ: return "bcdcfsq.";
+ case PPC_ID_AV_BCDCFZ: return "bcdcfz.";
+ case PPC_ID_AV_BCDCPSGN: return "bcdcpsgn.";
+ case PPC_ID_AV_BCDCTN: return "bcdctn.";
+ case PPC_ID_AV_BCDCTSQ: return "bcdctsq.";
+ case PPC_ID_AV_BCDCTZ: return "bcdctz.";
+ case PPC_ID_AV_BCDS: return "bcds.";
+ case PPC_ID_AV_BCDSETSGN: return "bcdsetsgn.";
+ case PPC_ID_AV_BCDSR: return "bcdsr.";
+ case PPC_ID_AV_BCDSUB: return "bcdsub.";
+ case PPC_ID_AV_BCDTRUNC: return "bcdtrunc.";
+ case PPC_ID_AV_BCDUS: return "bcdus.";
+ case PPC_ID_AV_BCDUTRUNC: return "bcdutrunc.";
+ case PPC_ID_AV_DSS: return "dss";
+ case PPC_ID_AV_DSSALL: return "dssall";
+ case PPC_ID_AV_DST: return "dst";
+ case PPC_ID_AV_DSTST: return "dstst";
+ case PPC_ID_AV_DSTSTT: return "dststt";
+ case PPC_ID_AV_DSTT: return "dstt";
+ case PPC_ID_AV_LVEBX: return "lvebx";
+ case PPC_ID_AV_LVEHX: return "lvehx";
+ case PPC_ID_AV_LVEWX: return "lvewx";
+ case PPC_ID_AV_LVSL: return "lvsl";
+ case PPC_ID_AV_LVSR: return "lvsr";
+ case PPC_ID_AV_LVX: return "lvx";
+ case PPC_ID_AV_LVXL: return "lvxl";
+ case PPC_ID_AV_MADDHD: return "maddhd";
+ case PPC_ID_AV_MADDHDU: return "maddhdu";
+ case PPC_ID_AV_MADDLD: return "maddld";
+ case PPC_ID_AV_MFVSCR: return "mfvscr";
+ case PPC_ID_AV_MTVSCR: return "mtvscr";
+ case PPC_ID_AV_STVEBX: return "stvebx";
+ case PPC_ID_AV_STVEHX: return "stvehx";
+ case PPC_ID_AV_STVEWX: return "stvewx";
+ case PPC_ID_AV_STVX: return "stvx";
+ case PPC_ID_AV_STVXL: return "stvxl";
+ case PPC_ID_AV_VADDCUW: return "vaddcuw";
+ case PPC_ID_AV_VADDECUQ: return "vaddecuq";
+ case PPC_ID_AV_VADDEUQM: return "vaddeuqm";
+ case PPC_ID_AV_VADDFP: return "vaddfp";
+ case PPC_ID_AV_VADDSBS: return "vaddsbs";
+ case PPC_ID_AV_VADDSHS: return "vaddshs";
+ case PPC_ID_AV_VADDSWS: return "vaddsws";
+ case PPC_ID_AV_VADDUBM: return "vaddubm";
+ case PPC_ID_AV_VADDUBS: return "vaddubs";
+ case PPC_ID_AV_VADDUDM: return "vaddudm";
+ case PPC_ID_AV_VADDUHM: return "vadduhm";
+ case PPC_ID_AV_VADDUHS: return "vadduhs";
+ case PPC_ID_AV_VADDUWM: return "vadduwm";
+ case PPC_ID_AV_VADDUWS: return "vadduws";
+ case PPC_ID_AV_VAND: return "vand";
+ case PPC_ID_AV_VANDC: return "vandc";
+ case PPC_ID_AV_VAVGSB: return "vavgsb";
+ case PPC_ID_AV_VAVGSH: return "vavgsh";
+ case PPC_ID_AV_VAVGSW: return "vavgsw";
+ case PPC_ID_AV_VAVGUB: return "vavgub";
+ case PPC_ID_AV_VAVGUH: return "vavguh";
+ case PPC_ID_AV_VAVGUW: return "vavguw";
+ case PPC_ID_AV_VBPERMD: return "vbpermd";
+ case PPC_ID_AV_VBPERMQ: return "vbpermq";
+ case PPC_ID_AV_VCFSX: return "vcfsx";
+ case PPC_ID_AV_VCFUX: return "vcfux";
+ case PPC_ID_AV_VCIPHER: return "vcipher";
+ case PPC_ID_AV_VCIPHERLAST: return "vcipherlast";
+ case PPC_ID_AV_VCLZB: return "vclzb";
+ case PPC_ID_AV_VCLZD: return "vclzd";
+ case PPC_ID_AV_VCLZH: return "vclzh";
+ case PPC_ID_AV_VCLZLSBB: return "vclzlsbb";
+ case PPC_ID_AV_VCLZW: return "vclzw";
+ case PPC_ID_AV_VCMPBFPx: return RcMnemonic(instruction, SubMnemVCMPBFPx);
+ case PPC_ID_AV_VCMPEQFPx: return RcMnemonic(instruction, SubMnemVCMPEQFPx);
+ case PPC_ID_AV_VCMPEQUBx: return RcMnemonic(instruction, SubMnemVCMPEQUBx);
+ case PPC_ID_AV_VCMPEQUDx: return RcMnemonic(instruction, SubMnemVCMPEQUDx);
+ case PPC_ID_AV_VCMPEQUHx: return RcMnemonic(instruction, SubMnemVCMPEQUHx);
+ case PPC_ID_AV_VCMPEQUWx: return RcMnemonic(instruction, SubMnemVCMPEQUWx);
+ case PPC_ID_AV_VCMPGEFPx: return RcMnemonic(instruction, SubMnemVCMPGEFPx);
+ case PPC_ID_AV_VCMPGTFPx: return RcMnemonic(instruction, SubMnemVCMPGTFPx);
+ case PPC_ID_AV_VCMPGTSBx: return RcMnemonic(instruction, SubMnemVCMPGTSBx);
+ case PPC_ID_AV_VCMPGTSDx: return RcMnemonic(instruction, SubMnemVCMPGTSDx);
+ case PPC_ID_AV_VCMPGTSHx: return RcMnemonic(instruction, SubMnemVCMPGTSHx);
+ case PPC_ID_AV_VCMPGTSWx: return RcMnemonic(instruction, SubMnemVCMPGTSWx);
+ case PPC_ID_AV_VCMPGTUBx: return RcMnemonic(instruction, SubMnemVCMPGTUBx);
+ case PPC_ID_AV_VCMPGTUDx: return RcMnemonic(instruction, SubMnemVCMPGTUDx);
+ case PPC_ID_AV_VCMPGTUHx: return RcMnemonic(instruction, SubMnemVCMPGTUHx);
+ case PPC_ID_AV_VCMPGTUWx: return RcMnemonic(instruction, SubMnemVCMPGTUWx);
+ case PPC_ID_AV_VCMPNEBx: return RcMnemonic(instruction, SubMnemVCMPNEBx);
+ case PPC_ID_AV_VCMPNEHx: return RcMnemonic(instruction, SubMnemVCMPNEHx);
+ case PPC_ID_AV_VCMPNEWx: return RcMnemonic(instruction, SubMnemVCMPNEWx);
+ case PPC_ID_AV_VCMPNEZBx: return RcMnemonic(instruction, SubMnemVCMPNEZBx);
+ case PPC_ID_AV_VCMPNEZHx: return RcMnemonic(instruction, SubMnemVCMPNEZHx);
+ case PPC_ID_AV_VCMPNEZWx: return RcMnemonic(instruction, SubMnemVCMPNEZWx);
+ case PPC_ID_AV_VCTSXS: return "vctsxs";
+ case PPC_ID_AV_VCTUXS: return "vctuxs";
+ case PPC_ID_AV_VCTZB: return "vctzb";
+ case PPC_ID_AV_VCTZD: return "vctzd";
+ case PPC_ID_AV_VCTZH: return "vctzh";
+ case PPC_ID_AV_VCTZLSBB: return "vctzlsbb";
+ case PPC_ID_AV_VCTZW: return "vctzw";
+ case PPC_ID_AV_VEQV: return "veqv";
+ case PPC_ID_AV_VEXPTEFP: return "vexptefp";
+ case PPC_ID_AV_VEXTRACTD: return "vextractd";
+ case PPC_ID_AV_VEXTRACTUB: return "vextractub";
+ case PPC_ID_AV_VEXTRACTUH: return "vextractuh";
+ case PPC_ID_AV_VEXTRACTUW: return "vextractuw";
+ case PPC_ID_AV_VEXTSB2D: return "vextsb2d";
+ case PPC_ID_AV_VEXTSB2W: return "vextsb2w";
+ case PPC_ID_AV_VEXTSH2D: return "vextsh2d";
+ case PPC_ID_AV_VEXTSH2W: return "vextsh2w";
+ case PPC_ID_AV_VEXTSW2D: return "vextsw2d";
+ case PPC_ID_AV_VEXTUBLX: return "vextublx";
+ case PPC_ID_AV_VEXTUHLX: return "vextuhlx";
+ case PPC_ID_AV_VEXTUWLX: return "vextuwlx";
+ case PPC_ID_AV_VEXTUBRX: return "vextubrx";
+ case PPC_ID_AV_VEXTUHRX: return "vextuhrx";
+ case PPC_ID_AV_VEXTUWRX: return "vextuwrx";
+ case PPC_ID_AV_VGBBD: return "vgbbd";
+ case PPC_ID_AV_VINSERTB: return "vinsertb";
+ case PPC_ID_AV_VINSERTD: return "vinsertd";
+ case PPC_ID_AV_VINSERTH: return "vinserth";
+ case PPC_ID_AV_VINSERTW: return "vinsertw";
+ case PPC_ID_AV_VLOGEFP: return "vlogefp";
+ case PPC_ID_AV_VMADDFP: return "vmaddfp";
+ case PPC_ID_AV_VMAXFP: return "vmaxfp";
+ case PPC_ID_AV_VMAXSB: return "vmaxsb";
+ case PPC_ID_AV_VMAXSD: return "vmaxsd";
+ case PPC_ID_AV_VMAXSH: return "vmaxsh";
+ case PPC_ID_AV_VMAXSW: return "vmaxsw";
+ case PPC_ID_AV_VMAXUB: return "vmaxub";
+ case PPC_ID_AV_VMAXUD: return "vmaxud";
+ case PPC_ID_AV_VMAXUH: return "vmaxuh";
+ case PPC_ID_AV_VMAXUW: return "vmaxuw";
+ case PPC_ID_AV_VMHADDSHS: return "vmhaddshs";
+ case PPC_ID_AV_VMHRADDSHS: return "vmhraddshs";
+ case PPC_ID_AV_VMINFP: return "vminfp";
+ case PPC_ID_AV_VMINSB: return "vminsb";
+ case PPC_ID_AV_VMINSD: return "vminsd";
+ case PPC_ID_AV_VMINSH: return "vminsh";
+ case PPC_ID_AV_VMINSW: return "vminsw";
+ case PPC_ID_AV_VMINUB: return "vminub";
+ case PPC_ID_AV_VMINUD: return "vminud";
+ case PPC_ID_AV_VMINUH: return "vminuh";
+ case PPC_ID_AV_VMINUW: return "vminuw";
+ case PPC_ID_AV_VMLADDUHM: return "vmladduhm";
+ case PPC_ID_AV_VMR: return "vmr";
+ case PPC_ID_AV_VMRGEW: return "vmrgew";
+ case PPC_ID_AV_VMRGHB: return "vmrghb";
+ case PPC_ID_AV_VMRGHH: return "vmrghh";
+ case PPC_ID_AV_VMRGHW: return "vmrghw";
+ case PPC_ID_AV_VMRGLB: return "vmrglb";
+ case PPC_ID_AV_VMRGLH: return "vmrglh";
+ case PPC_ID_AV_VMRGLW: return "vmrglw";
+ case PPC_ID_AV_VMRGOW: return "vmrgow";
+ case PPC_ID_AV_VMSUMMBM: return "vmsummbm";
+ case PPC_ID_AV_VMSUMSHM: return "vmsumshm";
+ case PPC_ID_AV_VMSUMSHS: return "vmsumshs";
+ case PPC_ID_AV_VMSUMUBM: return "vmsumubm";
+ case PPC_ID_AV_VMSUMUHM: return "vmsumuhm";
+ case PPC_ID_AV_VMSUMUHS: return "vmsumuhs";
+ case PPC_ID_AV_VMUL10CUQ: return "vmul10cuq";
+ case PPC_ID_AV_VMUL10EUQ: return "vmul10euq";
+ case PPC_ID_AV_VMUL10ECUQ: return "vmul10ecuq";
+ case PPC_ID_AV_VMUL10UQ: return "vmul10uq";
+ case PPC_ID_AV_VMULESB: return "vmulesb";
+ case PPC_ID_AV_VMULESH: return "vmulesh";
+ case PPC_ID_AV_VMULESW: return "vmulesw";
+ case PPC_ID_AV_VMULEUB: return "vmuleub";
+ case PPC_ID_AV_VMULEUH: return "vmuleuh";
+ case PPC_ID_AV_VMULEUW: return "vmuleuw";
+ case PPC_ID_AV_VMULOSB: return "vmulosb";
+ case PPC_ID_AV_VMULOSH: return "vmulosh";
+ case PPC_ID_AV_VMULOSW: return "vmulosw";
+ case PPC_ID_AV_VMULOUB: return "vmuloub";
+ case PPC_ID_AV_VMULOUH: return "vmulouh";
+ case PPC_ID_AV_VMULOUW: return "vmulouw";
+ case PPC_ID_AV_VMULUWM: return "vmuluwm";
+ case PPC_ID_AV_VNAND: return "vnand";
+ case PPC_ID_AV_VNCIPHER: return "vncipher";
+ case PPC_ID_AV_VNCIPHERLAST: return "vncipherlast";
+ case PPC_ID_AV_VNMSUBFP: return "vnmsubfp";
+ case PPC_ID_AV_VNEGD: return "vnegd";
+ case PPC_ID_AV_VNEGW: return "vnegw";
+ case PPC_ID_AV_VNOR: return "vnor";
+ case PPC_ID_AV_VNOT: return "vnot";
+ case PPC_ID_AV_VOR: return "vor";
+ case PPC_ID_AV_VORC: return "vorc";
+ case PPC_ID_AV_VPERM: return "vperm";
+ case PPC_ID_AV_VPERMR: return "vpermr";
+ case PPC_ID_AV_VPERMXOR: return "vpermxor";
+ case PPC_ID_AV_VPKPX: return "vpkpx";
+ case PPC_ID_AV_VPKSDSS: return "vpksdss";
+ case PPC_ID_AV_VPKSDUS: return "vpksdus";
+ case PPC_ID_AV_VPKSHSS: return "vpkshss";
+ case PPC_ID_AV_VPKSHUS: return "vpkshus";
+ case PPC_ID_AV_VPKSWSS: return "vpkswss";
+ case PPC_ID_AV_VPKSWUS: return "vpkswus";
+ case PPC_ID_AV_VPKUDUM: return "vpkudum";
+ case PPC_ID_AV_VPKUDUS: return "vpkudus";
+ case PPC_ID_AV_VPKUHUM: return "vpkuhum";
+ case PPC_ID_AV_VPKUHUS: return "vpkuhus";
+ case PPC_ID_AV_VPKUWUM: return "vpkuwum";
+ case PPC_ID_AV_VPKUWUS: return "vpkuwus";
+ case PPC_ID_AV_VPMSUMB: return "vpmsumb";
+ case PPC_ID_AV_VPMSUMD: return "vpmsumd";
+ case PPC_ID_AV_VPMSUMH: return "vpmsumh";
+ case PPC_ID_AV_VPMSUMW: return "vpmsumw";
+ case PPC_ID_AV_VPOPCNTB: return "vpopcntb";
+ case PPC_ID_AV_VPOPCNTD: return "vpopcntd";
+ case PPC_ID_AV_VPOPCNTH: return "vpopcnth";
+ case PPC_ID_AV_VPOPCNTW: return "vpopcntw";
+ case PPC_ID_AV_VPRTYBD: return "vprtybd";
+ case PPC_ID_AV_VPRTYBQ: return "vprtybq";
+ case PPC_ID_AV_VPRTYBW: return "vprtybw";
+ case PPC_ID_AV_VREFP: return "vrefp";
+ case PPC_ID_AV_VRFIM: return "vrfim";
+ case PPC_ID_AV_VRFIN: return "vrfin";
+ case PPC_ID_AV_VRFIP: return "vrfip";
+ case PPC_ID_AV_VRFIZ: return "vrfiz";
+ case PPC_ID_AV_VRLB: return "vrlb";
+ case PPC_ID_AV_VRLD: return "vrld";
+ case PPC_ID_AV_VRLDNM: return "vrldnm";
+ case PPC_ID_AV_VRLDMI: return "vrldmi";
+ case PPC_ID_AV_VRLH: return "vrlh";
+ case PPC_ID_AV_VRLW: return "vrlw";
+ case PPC_ID_AV_VRLWMI: return "vrlwmi";
+ case PPC_ID_AV_VRLWNM: return "vrlwnm";
+ case PPC_ID_AV_VRSQRTEFP: return "vrsqrtefp";
+ case PPC_ID_AV_VSBOX: return "vsbox";
+ case PPC_ID_AV_VSEL: return "vsel";
+ case PPC_ID_AV_VSHASIGMAD: return "vshasigmad";
+ case PPC_ID_AV_VSHASIGMAW: return "vshasigmaw";
+ case PPC_ID_AV_VSL: return "vsl";
+ case PPC_ID_AV_VSLB: return "vslb";
+ case PPC_ID_AV_VSLD: return "vsld";
+ case PPC_ID_AV_VSLDOI: return "vsldoi";
+ case PPC_ID_AV_VSLH: return "vslh";
+ case PPC_ID_AV_VSLO: return "vslo";
+ case PPC_ID_AV_VSLV: return "vslv";
+ case PPC_ID_AV_VSLW: return "vslw";
+ case PPC_ID_AV_VSPLTB: return "vspltb";
+ case PPC_ID_AV_VSPLTH: return "vsplth";
+ case PPC_ID_AV_VSPLTISB: return "vspltisb";
+ case PPC_ID_AV_VSPLTISH: return "vspltish";
+ case PPC_ID_AV_VSPLTISW: return "vspltisw";
+ case PPC_ID_AV_VSPLTW: return "vspltw";
+ case PPC_ID_AV_VSR: return "vsr";
+ case PPC_ID_AV_VSRAB: return "vsrab";
+ case PPC_ID_AV_VSRAD: return "vsrad";
+ case PPC_ID_AV_VSRAH: return "vsrah";
+ case PPC_ID_AV_VSRAW: return "vsraw";
+ case PPC_ID_AV_VSRB: return "vsrb";
+ case PPC_ID_AV_VSRD: return "vsrd";
+ case PPC_ID_AV_VSRH: return "vsrh";
+ case PPC_ID_AV_VSRO: return "vsro";
+ case PPC_ID_AV_VSRV: return "vsrv";
+ case PPC_ID_AV_VSRW: return "vsrw";
+ case PPC_ID_AV_VSUBCUQ: return "vsubcuq";
+ case PPC_ID_AV_VSUBCUW: return "vsubcuw";
+ case PPC_ID_AV_VSUBECUQ: return "vsubecuq";
+ case PPC_ID_AV_VSUBEUQM: return "vsubeuqm";
+ case PPC_ID_AV_VSUBFP: return "vsubfp";
+ case PPC_ID_AV_VSUBSBS: return "vsubsbs";
+ case PPC_ID_AV_VSUBSHS: return "vsubshs";
+ case PPC_ID_AV_VSUBSWS: return "vsubsws";
+ case PPC_ID_AV_VSUBUBM: return "vsububm";
+ case PPC_ID_AV_VSUBUBS: return "vsububs";
+ case PPC_ID_AV_VSUBUDM: return "vsubudm";
+ case PPC_ID_AV_VSUBUHM: return "vsubuhm";
+ case PPC_ID_AV_VSUBUHS: return "vsubuhs";
+ case PPC_ID_AV_VSUBUQM: return "vsubuqm";
+ case PPC_ID_AV_VSUBUWM: return "vsubuwm";
+ case PPC_ID_AV_VSUBUWS: return "vsubuws";
+ case PPC_ID_AV_VSUMSWS: return "vsumsws";
+ case PPC_ID_AV_VSUM2SWS: return "vsum2sws";
+ case PPC_ID_AV_VSUM4SBS: return "vsum4sbs";
+ case PPC_ID_AV_VSUM4SHS: return "vsum4shs";
+ case PPC_ID_AV_VSUM4UBS: return "vsum4ubs";
+ case PPC_ID_AV_VUPKHPX: return "vupkhpx";
+ case PPC_ID_AV_VUPKHSB: return "vupkhsb";
+ case PPC_ID_AV_VUPKHSH: return "vupkhsh";
+ case PPC_ID_AV_VUPKHSW: return "vupkhsw";
+ case PPC_ID_AV_VUPKLPX: return "vupklpx";
+ case PPC_ID_AV_VUPKLSB: return "vupklsb";
+ case PPC_ID_AV_VUPKLSH: return "vupklsh";
+ case PPC_ID_AV_VUPKLSW: return "vupklsw";
+ case PPC_ID_AV_VXOR: return "vxor";
+
+ case PPC_ID_VSX_LXSD: return "lxsd";
+ case PPC_ID_VSX_LXSDX: return "lxsdx";
+ case PPC_ID_VSX_LXSIBZX: return "lxsibzx";
+ case PPC_ID_VSX_LXSIHZX: return "lxsihzx";
+ case PPC_ID_VSX_LXSIWAX: return "lxsiwax";
+ case PPC_ID_VSX_LXSIWZX: return "lxsiwzx";
+ case PPC_ID_VSX_LXSSP: return "lxssp";
+ case PPC_ID_VSX_LXSSPX: return "lxsspx";
+ case PPC_ID_VSX_LXV: return "lxv";
+ case PPC_ID_VSX_LXVB16X: return "lxvb16x";
+ case PPC_ID_VSX_LXVD2X: return "lxvd2x";
+ case PPC_ID_VSX_LXVDSX: return "lxvdsx";
+ case PPC_ID_VSX_LXVH8X: return "lxvh8x";
+ case PPC_ID_VSX_LXVL: return "lxvl";
+ case PPC_ID_VSX_LXVLL: return "lxvll";
+ case PPC_ID_VSX_LXVW4X: return "lxvw4x";
+ case PPC_ID_VSX_LXVWSX: return "lxvwsx";
+ case PPC_ID_VSX_LXVX: return "lxvx";
+ case PPC_ID_VSX_MFFPRD: return "mffprd";
+ case PPC_ID_VSX_MFVSRD: return "mfvsrd";
+ case PPC_ID_VSX_MFVSRLD: return "mfvsrld";
+ case PPC_ID_VSX_MFVSRWZ: return "mfvsrwz";
+ case PPC_ID_VSX_MTVSRD: return "mtvsrd";
+ case PPC_ID_VSX_MTVSRDD: return "mtvsrdd";
+ case PPC_ID_VSX_MTVSRWA: return "mtvsrwa";
+ case PPC_ID_VSX_MTVSRWS: return "mtvsrws";
+ case PPC_ID_VSX_MTVSRWZ: return "mtvsrwz";
+ case PPC_ID_VSX_STXSD: return "stxsd";
+ case PPC_ID_VSX_STXSDX: return "stxsdx";
+ case PPC_ID_VSX_STXSIBX: return "stxsibx";
+ case PPC_ID_VSX_STXSIHX: return "stxsihx";
+ case PPC_ID_VSX_STXSIWX: return "stxsiwx";
+ case PPC_ID_VSX_STXSSP: return "stxssp";
+ case PPC_ID_VSX_STXSSPX: return "stxsspx";
+ case PPC_ID_VSX_STXVB16X: return "stxvb16x";
+ case PPC_ID_VSX_STXVD2X: return "stxvd2x";
+ case PPC_ID_VSX_STXVH8X: return "stxvh8x";
+ case PPC_ID_VSX_STXV: return "stxv";
+ case PPC_ID_VSX_STXVL: return "stxvl";
+ case PPC_ID_VSX_STXVLL: return "stxvll";
+ case PPC_ID_VSX_STXVW4X: return "stxvw4x";
+ case PPC_ID_VSX_STXVX: return "stxvx";
+ case PPC_ID_VSX_XSABSDP: return "xsabsdp";
+ case PPC_ID_VSX_XSABSQP: return "xsabsqp";
+ case PPC_ID_VSX_XSADDDP: return "xsadddp";
+ case PPC_ID_VSX_XSADDSP: return "xsaddsp";
+ case PPC_ID_VSX_XSADDQPx: return Round2OddMnemonic(instruction, SubMnemXSADDQPx);
+ case PPC_ID_VSX_XSCMPEQDP: return "xscmpeqdp";
+ case PPC_ID_VSX_XSCMPEXPDP: return "xscmpexpdp";
+ case PPC_ID_VSX_XSCMPEXPQP: return "xscmpexpqp";
+ case PPC_ID_VSX_XSCMPGEDP: return "xscmpgedp";
+ case PPC_ID_VSX_XSCMPGTDP: return "xscmpgtdp";
+ case PPC_ID_VSX_XSCMPODP: return "xscmpodp";
+ case PPC_ID_VSX_XSCMPOQP: return "xscmpoqp";
+ case PPC_ID_VSX_XSCMPUDP: return "xscmpudp";
+ case PPC_ID_VSX_XSCMPUQP: return "xscmpuqp";
+ case PPC_ID_VSX_XSCPSGNDP: return "xscpsgndp";
+ case PPC_ID_VSX_XSCPSGNQP: return "xscpsgnqp";
+ case PPC_ID_VSX_XSCVDPHP: return "xscvdphp";
+ case PPC_ID_VSX_XSCVDPQP: return "xscvdpqp";
+ case PPC_ID_VSX_XSCVDPSP: return "xscvdpsp";
+ case PPC_ID_VSX_XSCVDPSPN: return "xscvdpspn";
+ case PPC_ID_VSX_XSCVDPSXDS: return "xscvdpsxds";
+ case PPC_ID_VSX_XSCVDPSXWS: return "xscvdpsxws";
+ case PPC_ID_VSX_XSCVDPUXDS: return "xscvdpuxds";
+ case PPC_ID_VSX_XSCVDPUXWS: return "xscvdpuxws";
+ case PPC_ID_VSX_XSCVHPDP: return "xscvhpdp";
+ case PPC_ID_VSX_XSCVQPDPx: return Round2OddMnemonic(instruction, SubMnemXSCVQPDPx);
+ case PPC_ID_VSX_XSCVQPSDZ: return "xscvqpsdz";
+ case PPC_ID_VSX_XSCVQPSWZ: return "xscvqpswz";
+ case PPC_ID_VSX_XSCVQPUDZ: return "xscvqpudz";
+ case PPC_ID_VSX_XSCVQPUWZ: return "xscvqpuwz";
+ case PPC_ID_VSX_XSCVSDQP: return "xscvsdqp";
+ case PPC_ID_VSX_XSCVSPDP: return "xscvspdp";
+ case PPC_ID_VSX_XSCVSPDPN: return "xscvspdpn";
+ case PPC_ID_VSX_XSCVSXDDP: return "xscvsxddp";
+ case PPC_ID_VSX_XSCVSXDSP: return "xscvsxdsp";
+ case PPC_ID_VSX_XSCVUDQP: return "xscvudqp";
+ case PPC_ID_VSX_XSCVUXDDP: return "xscvuxddp";
+ case PPC_ID_VSX_XSCVUXDSP: return "xscvuxdsp";
+ case PPC_ID_VSX_XSDIVDP: return "xsdivdp";
+ case PPC_ID_VSX_XSDIVSP: return "xsdivsp";
+ case PPC_ID_VSX_XSDIVQPx: return Round2OddMnemonic(instruction, SubMnemXSDIVQPx);
+ case PPC_ID_VSX_XSIEXPDP: return "xsiexpdp";
+ case PPC_ID_VSX_XSIEXPQP: return "xsiexpqp";
+ case PPC_ID_VSX_XSMADDADP: return "xsmaddadp";
+ case PPC_ID_VSX_XSMADDASP: return "xsmaddasp";
+ case PPC_ID_VSX_XSMADDMDP: return "xsmaddmdp";
+ case PPC_ID_VSX_XSMADDMSP: return "xsmaddmsp";
+ case PPC_ID_VSX_XSMADDQPx: return Round2OddMnemonic(instruction, SubMnemXSMADDQPx);
+ case PPC_ID_VSX_XSMAXCDP: return "xsmaxcdp";
+ case PPC_ID_VSX_XSMAXDP: return "xsmaxdp";
+ case PPC_ID_VSX_XSMAXJDP: return "xsmaxjdp";
+ case PPC_ID_VSX_XSMINDP: return "xsmindp";
+ case PPC_ID_VSX_XSMINCDP: return "xsmincdp";
+ case PPC_ID_VSX_XSMINJDP: return "xsminjdp";
+ case PPC_ID_VSX_XSMSUBADP: return "xsmsubadp";
+ case PPC_ID_VSX_XSMSUBASP: return "xsmsubasp";
+ case PPC_ID_VSX_XSMSUBMDP: return "xsmsubmdp";
+ case PPC_ID_VSX_XSMSUBMSP: return "xsmsubmsp";
+ case PPC_ID_VSX_XSMSUBQPx: return Round2OddMnemonic(instruction, SubMnemXSMSUBQPx);
+ case PPC_ID_VSX_XSMULDP: return "xsmuldp";
+ case PPC_ID_VSX_XSMULSP: return "xsmulsp";
+ case PPC_ID_VSX_XSMULQPx: return Round2OddMnemonic(instruction, SubMnemXSMULQPx);
+ case PPC_ID_VSX_XSNABSDP: return "xsnabsdp";
+ case PPC_ID_VSX_XSNABSQP: return "xsnabsqp";
+ case PPC_ID_VSX_XSNEGDP: return "xsnegdp";
+ case PPC_ID_VSX_XSNEGQP: return "xsnegqp";
+ case PPC_ID_VSX_XSNMADDADP: return "xsnmaddadp";
+ case PPC_ID_VSX_XSNMADDASP: return "xsnmaddasp";
+ case PPC_ID_VSX_XSNMADDQPx: return Round2OddMnemonic(instruction, SubMnemXSNMADDQPx);
+ case PPC_ID_VSX_XSNMADDMDP: return "xsnmaddmdp";
+ case PPC_ID_VSX_XSNMADDMSP: return "xsnmaddmsp";
+ case PPC_ID_VSX_XSNMSUBADP: return "xsnmsubadp";
+ case PPC_ID_VSX_XSNMSUBASP: return "xsnmsubasp";
+ case PPC_ID_VSX_XSNMSUBMDP: return "xsnmsubmdp";
+ case PPC_ID_VSX_XSNMSUBMSP: return "xsnmsubmsp";
+ case PPC_ID_VSX_XSNMSUBQPx: return Round2OddMnemonic(instruction, SubMnemXSNMSUBQPx);
+ case PPC_ID_VSX_XSRDPI: return "xsrdpi";
+ case PPC_ID_VSX_XSRDPIC: return "xsrdpic";
+ case PPC_ID_VSX_XSRDPIM: return "xsrdpim";
+ case PPC_ID_VSX_XSRDPIP: return "xsrdpip";
+ case PPC_ID_VSX_XSRDPIZ: return "xsrdpiz";
+ case PPC_ID_VSX_XSREDP: return "xsredp";
+ case PPC_ID_VSX_XSRESP: return "xsresp";
+ case PPC_ID_VSX_XSRSP: return "xsrsp";
+ case PPC_ID_VSX_XSRSQRTEDP: return "xsrsqrtedp";
+ case PPC_ID_VSX_XSRSQRTESP: return "xsrsqrtesp";
+ case PPC_ID_VSX_XSSQRTDP: return "xssqrtdp";
+ case PPC_ID_VSX_XSSQRTQPx: return Round2OddMnemonic(instruction, SubMnemXSSQRTQPx);
+ case PPC_ID_VSX_XSSQRTSP: return "xssqrtsp";
+ case PPC_ID_VSX_XSSUBDP: return "xssubdp";
+ case PPC_ID_VSX_XSSUBSP: return "xssubsp";
+ case PPC_ID_VSX_XSSUBQPx: return Round2OddMnemonic(instruction, SubMnemXSSUBQPx);
+ case PPC_ID_VSX_XSRQPIx: return InexactMnemonic(instruction, SubMnemXSRQPIx);
+ case PPC_ID_VSX_XSRQPXP: return "xsrqpxp";
+ case PPC_ID_VSX_XSTDIVDP: return "xstdivdp";
+ case PPC_ID_VSX_XSTDIVSP: return "xstdivsp";
+ case PPC_ID_VSX_XSTSTDCDP: return "xststdcdp";
+ case PPC_ID_VSX_XSTSTDCQP: return "xststdcqp";
+ case PPC_ID_VSX_XSTSTDCSP: return "xststdcsp";
+ case PPC_ID_VSX_XSTSQRTDP: return "xstsqrtdp";
+ case PPC_ID_VSX_XSXEXPDP: return "xsxexpdp";
+ case PPC_ID_VSX_XSXEXPQP: return "xsxexpqp";
+ case PPC_ID_VSX_XSXSIGDP: return "xsxsigdp";
+ case PPC_ID_VSX_XSXSIGQP: return "xsxsigqp";
+ case PPC_ID_VSX_XVABSSP: return "xvabssp";
+ case PPC_ID_VSX_XVABSDP: return "xvabsdp";
+ case PPC_ID_VSX_XVADDSP: return "xvaddsp";
+ case PPC_ID_VSX_XVADDDP: return "xvadddp";
+ case PPC_ID_VSX_XVCMPEQDPx: return RcMnemonic(instruction, SubMnemXVCMPEQDPx);
+ case PPC_ID_VSX_XVCMPEQSPx: return RcMnemonic(instruction, SubMnemXVCMPEQSPx);
+ case PPC_ID_VSX_XVCMPGEDPx: return RcMnemonic(instruction, SubMnemXVCMPGEDPx);
+ case PPC_ID_VSX_XVCMPGESPx: return RcMnemonic(instruction, SubMnemXVCMPGESPx);
+ case PPC_ID_VSX_XVCMPGTDPx: return RcMnemonic(instruction, SubMnemXVCMPGTDPx);
+ case PPC_ID_VSX_XVCMPGTSPx: return RcMnemonic(instruction, SubMnemXVCMPGTSPx);
+ case PPC_ID_VSX_XVCPSGNDP: return "xvcpsgndp";
+ case PPC_ID_VSX_XVCPSGNSP: return "xvcpsgnsp";
+ case PPC_ID_VSX_XVCVDPSP: return "xvcvdpsp";
+ case PPC_ID_VSX_XVCVDPSXDS: return "xvcvdpsxds";
+ case PPC_ID_VSX_XVCVDPSXWS: return "xvcvdpsxws";
+ case PPC_ID_VSX_XVCVDPUXDS: return "xvcvdpuxds";
+ case PPC_ID_VSX_XVCVDPUXWS: return "xvcvdpuxws";
+ case PPC_ID_VSX_XVCVHPSP: return "xvcvhpsp";
+ case PPC_ID_VSX_XVCVSPDP: return "xvcvspdp";
+ case PPC_ID_VSX_XVCVSPHP: return "xvcvsphp";
+ case PPC_ID_VSX_XVCVSPSXDS: return "xvcvspsxds";
+ case PPC_ID_VSX_XVCVSPSXWS: return "xvcvspsxws";
+ case PPC_ID_VSX_XVCVSPUXDS: return "xvcvspuxds";
+ case PPC_ID_VSX_XVCVSPUXWS: return "xvcvspuxws";
+ case PPC_ID_VSX_XVCVSXDDP: return "xvcvsxddp";
+ case PPC_ID_VSX_XVCVSXDSP: return "xvcvsxdsp";
+ case PPC_ID_VSX_XVCVSXWDP: return "xvcvsxwdp";
+ case PPC_ID_VSX_XVCVSXWSP: return "xvcvsxwsp";
+ case PPC_ID_VSX_XVCVUXDDP: return "xvcvuxddp";
+ case PPC_ID_VSX_XVCVUXDSP: return "xvcvuxdsp";
+ case PPC_ID_VSX_XVCVUXWDP: return "xvcvuxwdp";
+ case PPC_ID_VSX_XVCVUXWSP: return "xvcvuxwsp";
+ case PPC_ID_VSX_XVDIVDP: return "xvdivdp";
+ case PPC_ID_VSX_XVDIVSP: return "xvdivsp";
+ case PPC_ID_VSX_XVIEXPDP: return "xviexpdp";
+ case PPC_ID_VSX_XVIEXPSP: return "xviexpsp";
+ case PPC_ID_VSX_XVMADDADP: return "xvmaddadp";
+ case PPC_ID_VSX_XVMADDASP: return "xvmaddasp";
+ case PPC_ID_VSX_XVMADDMDP: return "xvmaddmdp";
+ case PPC_ID_VSX_XVMADDMSP: return "xvmaddmsp";
+ case PPC_ID_VSX_XVMAXDP: return "xvmaxdp";
+ case PPC_ID_VSX_XVMAXSP: return "xvmaxsp";
+ case PPC_ID_VSX_XVMINDP: return "xvmindp";
+ case PPC_ID_VSX_XVMINSP: return "xvminsp";
+ case PPC_ID_VSX_XVMOVDP: return "xvmovdp";
+ case PPC_ID_VSX_XVMOVSP: return "xvmovsp";
+ case PPC_ID_VSX_XVMSUBADP: return "xvmsubadp";
+ case PPC_ID_VSX_XVMSUBASP: return "xvmsubasp";
+ case PPC_ID_VSX_XVMSUBMDP: return "xvmsubmdp";
+ case PPC_ID_VSX_XVMSUBMSP: return "xvmsubmsp";
+ case PPC_ID_VSX_XVMULSP: return "xvmulsp";
+ case PPC_ID_VSX_XVMULDP: return "xvmuldp";
+ case PPC_ID_VSX_XVNABSDP: return "xvnabsdp";
+ case PPC_ID_VSX_XVNABSSP: return "xvnabssp";
+ case PPC_ID_VSX_XVNMADDADP: return "xvnmaddadp";
+ case PPC_ID_VSX_XVNMADDASP: return "xvnmaddasp";
+ case PPC_ID_VSX_XVNMADDMDP: return "xvnmaddmdp";
+ case PPC_ID_VSX_XVNMADDMSP: return "xvnmaddmsp";
+ case PPC_ID_VSX_XVNEGDP: return "xvnegdp";
+ case PPC_ID_VSX_XVNEGSP: return "xvnegsp";
+ case PPC_ID_VSX_XVNMSUBADP: return "xvnmsubadp";
+ case PPC_ID_VSX_XVNMSUBASP: return "xvnmsubasp";
+ case PPC_ID_VSX_XVNMSUBMSP: return "xvnmsubmsp";
+ case PPC_ID_VSX_XVNMSUBMDP: return "xvnmsubmdp";
+ case PPC_ID_VSX_XVRDPI: return "xvrdpi";
+ case PPC_ID_VSX_XVRDPIC: return "xvrdpic";
+ case PPC_ID_VSX_XVRDPIM: return "xvrdpim";
+ case PPC_ID_VSX_XVRDPIP: return "xvrdpip";
+ case PPC_ID_VSX_XVRDPIZ: return "xvrdpiz";
+ case PPC_ID_VSX_XVREDP: return "xvredp";
+ case PPC_ID_VSX_XVRESP: return "xvresp";
+ case PPC_ID_VSX_XVRSPI: return "xvrspi";
+ case PPC_ID_VSX_XVRSPIC: return "xvrspic";
+ case PPC_ID_VSX_XVRSPIM: return "xvrspim";
+ case PPC_ID_VSX_XVRSPIP: return "xvrspip";
+ case PPC_ID_VSX_XVRSPIZ: return "xvrspiz";
+ case PPC_ID_VSX_XVRSQRTEDP: return "xvrsqrtedp";
+ case PPC_ID_VSX_XVRSQRTESP: return "xvrsqrtesp";
+ case PPC_ID_VSX_XVSQRTDP: return "xvsqrtdp";
+ case PPC_ID_VSX_XVSQRTSP: return "xvsqrtsp";
+ case PPC_ID_VSX_XVSUBSP: return "xvsubsp";
+ case PPC_ID_VSX_XVSUBDP: return "xvsubdp";
+ case PPC_ID_VSX_XVTDIVDP: return "xvtdivdp";
+ case PPC_ID_VSX_XVTDIVSP: return "xvtdivsp";
+ case PPC_ID_VSX_XVTSQRTDP: return "xvtsqrtdp";
+ case PPC_ID_VSX_XVTSQRTSP: return "xvtsqrtsp";
+ case PPC_ID_VSX_XVTSTDCDP: return "xvtstdcdp";
+ case PPC_ID_VSX_XVTSTDCSP: return "xvtstdcsp";
+ case PPC_ID_VSX_XVXEXPDP: return "xvxexpdp";
+ case PPC_ID_VSX_XVXEXPSP: return "xvxexpsp";
+ case PPC_ID_VSX_XVXSIGDP: return "xvxsigdp";
+ case PPC_ID_VSX_XVXSIGSP: return "xvxsigsp";
+ case PPC_ID_VSX_XXBRD: return "xxbrd";
+ case PPC_ID_VSX_XXBRH: return "xxbrh";
+ case PPC_ID_VSX_XXBRQ: return "xxbrq";
+ case PPC_ID_VSX_XXBRW: return "xxbrw";
+ case PPC_ID_VSX_XXEXTRACTUW: return "xxextractuw";
+ case PPC_ID_VSX_XXINSERTW: return "xxinsertw";
+ case PPC_ID_VSX_XXLAND: return "xxland";
+ case PPC_ID_VSX_XXLANDC: return "xxlandc";
+ case PPC_ID_VSX_XXLEQV: return "xxleqv";
+ case PPC_ID_VSX_XXLNAND: return "xxlnand";
+ case PPC_ID_VSX_XXLNOR: return "xxlnor";
+ case PPC_ID_VSX_XXLORC: return "xxlorc";
+ case PPC_ID_VSX_XXMRGHD: return "xxmrghd";
+ case PPC_ID_VSX_XXMRGHW: return "xxmrghw";
+ case PPC_ID_VSX_XXMRGLD: return "xxmrgld";
+ case PPC_ID_VSX_XXMRGLW: return "xxmrglw";
+ case PPC_ID_VSX_XXLOR: return "xxlor";
+ case PPC_ID_VSX_XXLXOR: return "xxlxor";
+ case PPC_ID_VSX_XXPERM: return "xxperm";
+ case PPC_ID_VSX_XXPERMDI: return "xxpermdi";
+ case PPC_ID_VSX_XXPERMR: return "xxpermr";
+ case PPC_ID_VSX_XXSEL: return "xxsel";
+ case PPC_ID_VSX_XXSLDWI: return "xxsldwi";
+ case PPC_ID_VSX_XXSPLTD: return "xxspltd";
+ case PPC_ID_VSX_XXSPLTIB: return "xxspltib";
+ case PPC_ID_VSX_XXSPLTW: return "xxspltw";
+ case PPC_ID_VSX_XXSWAPD: return "xxswapd";
+
+ case PPC_ID_PSQ_L: return "psq_l";
+ case PPC_ID_PSQ_LU: return "psq_lu";
+ case PPC_ID_PSQ_LUX: return "psq_lux";
+ case PPC_ID_PSQ_LX: return "psq_lx";
+ case PPC_ID_PSQ_ST: return "psq_st";
+ case PPC_ID_PSQ_STU: return "psq_stu";
+ case PPC_ID_PSQ_STUX: return "psq_stux";
+ case PPC_ID_PSQ_STX: return "psq_stx";
+
+ case PPC_ID_PAIREDSINGLE_DCBZ_L: return "dcbz_l";
+ case PPC_ID_PAIREDSINGLE_PS_ABSx: return RcMnemonic(instruction, SubMnemPS_ABSx);
+ case PPC_ID_PAIREDSINGLE_PS_ADDx: return RcMnemonic(instruction, SubMnemPS_ADDx);
+ case PPC_ID_PAIREDSINGLE_PS_CMPO0: return "ps_cmpo0";
+ case PPC_ID_PAIREDSINGLE_PS_CMPO1: return "ps_cmpo1";
+ case PPC_ID_PAIREDSINGLE_PS_CMPU0: return "ps_cmpu0";
+ case PPC_ID_PAIREDSINGLE_PS_CMPU1: return "ps_cmpu1";
+ case PPC_ID_PAIREDSINGLE_PS_DIVx: return RcMnemonic(instruction, SubMnemPS_DIVx);
+ case PPC_ID_PAIREDSINGLE_PS_MADDx: return RcMnemonic(instruction, SubMnemPS_MADDx);
+ case PPC_ID_PAIREDSINGLE_PS_MADDS0x: return RcMnemonic(instruction, SubMnemPS_MADDS0x);
+ case PPC_ID_PAIREDSINGLE_PS_MADDS1x: return RcMnemonic(instruction, SubMnemPS_MADDS1x);
+ case PPC_ID_PAIREDSINGLE_PS_MERGE00x: return RcMnemonic(instruction, SubMnemPS_MERGE00x);
+ case PPC_ID_PAIREDSINGLE_PS_MERGE01x: return RcMnemonic(instruction, SubMnemPS_MERGE01x);
+ case PPC_ID_PAIREDSINGLE_PS_MERGE10x: return RcMnemonic(instruction, SubMnemPS_MERGE10x);
+ case PPC_ID_PAIREDSINGLE_PS_MERGE11x: return RcMnemonic(instruction, SubMnemPS_MERGE11x);
+ case PPC_ID_PAIREDSINGLE_PS_MRx: return RcMnemonic(instruction, SubMnemPS_MRx);
+ case PPC_ID_PAIREDSINGLE_PS_MSUBx: return RcMnemonic(instruction, SubMnemPS_MSUBx);
+ case PPC_ID_PAIREDSINGLE_PS_MULx: return RcMnemonic(instruction, SubMnemPS_MULx);
+ case PPC_ID_PAIREDSINGLE_PS_MULS0x: return RcMnemonic(instruction, SubMnemPS_MULS0x);
+ case PPC_ID_PAIREDSINGLE_PS_MULS1x: return RcMnemonic(instruction, SubMnemPS_MULS1x);
+ case PPC_ID_PAIREDSINGLE_PS_NABSx: return RcMnemonic(instruction, SubMnemPS_NABSx);
+ case PPC_ID_PAIREDSINGLE_PS_NEGx: return RcMnemonic(instruction, SubMnemPS_NEGx);
+ case PPC_ID_PAIREDSINGLE_PS_NMADDx: return RcMnemonic(instruction, SubMnemPS_NMADDx);
+ case PPC_ID_PAIREDSINGLE_PS_NMSUBx: return RcMnemonic(instruction, SubMnemPS_NMSUBx);
+ case PPC_ID_PAIREDSINGLE_PS_RESx: return RcMnemonic(instruction, SubMnemPS_RESx);
+ case PPC_ID_PAIREDSINGLE_PS_RSQRTEx: return RcMnemonic(instruction, SubMnemPS_RSQRTEx);
+ case PPC_ID_PAIREDSINGLE_PS_SELx: return RcMnemonic(instruction, SubMnemPS_SELx);
+ case PPC_ID_PAIREDSINGLE_PS_SUBx: return RcMnemonic(instruction, SubMnemPS_SUBx);
+ case PPC_ID_PAIREDSINGLE_PS_SUM0x: return RcMnemonic(instruction, SubMnemPS_SUM0x);
+ case PPC_ID_PAIREDSINGLE_PS_SUM1x: return RcMnemonic(instruction, SubMnemPS_SUM1x);
+ case PPC_ID_PAIREDSINGLE_PSQ_L: return "psq_l";
+ case PPC_ID_PAIREDSINGLE_PSQ_LU: return "psq_lu";
+ case PPC_ID_PAIREDSINGLE_PSQ_LUX: return "psq_lux";
+ case PPC_ID_PAIREDSINGLE_PSQ_LX: return "psq_lx";
+ case PPC_ID_PAIREDSINGLE_PSQ_ST: return "psq_st";
+ case PPC_ID_PAIREDSINGLE_PSQ_STU: return "psq_stu";
+ case PPC_ID_PAIREDSINGLE_PSQ_STUX: return "psq_stux";
+ case PPC_ID_PAIREDSINGLE_PSQ_STX: return "psq_stx";
+
+ case PPC_ID_SPE_BRINC: return "brinc";
+ case PPC_ID_SPE_EFDABS: return "efdabs";
+ case PPC_ID_SPE_EFDADD: return "efdadd";
+ case PPC_ID_SPE_EFDCFS: return "efdcfs";
+ case PPC_ID_SPE_EFDCFSF: return "efdcfsf";
+ case PPC_ID_SPE_EFDCFSI: return "efdcfsi";
+ case PPC_ID_SPE_EFDCFSID: return "efdcfsid";
+ case PPC_ID_SPE_EFDCFUF: return "efdcfuf";
+ case PPC_ID_SPE_EFDCFUI: return "efdcfui";
+ case PPC_ID_SPE_EFDCFUID: return "efdcfuid";
+ case PPC_ID_SPE_EFDCMPEQ: return "efdcmpeq";
+ case PPC_ID_SPE_EFDCMPGT: return "efdcmpgt";
+ case PPC_ID_SPE_EFDCMPLT: return "efdcmplt";
+ case PPC_ID_SPE_EFDCTSF: return "efdctsf";
+ case PPC_ID_SPE_EFDCTSI: return "efdctsi";
+ case PPC_ID_SPE_EFDCTSIDZ: return "efdctsidz";
+ case PPC_ID_SPE_EFDCTSIZ: return "efdctsiz";
+ case PPC_ID_SPE_EFDCTUF: return "efdctuf";
+ case PPC_ID_SPE_EFDCTUI: return "efdctui";
+ case PPC_ID_SPE_EFDCTUIDZ: return "efdctuidz";
+ case PPC_ID_SPE_EFDCTUIZ: return "efdctuiz";
+ case PPC_ID_SPE_EFDDIV: return "efddiv";
+ case PPC_ID_SPE_EFDMUL: return "efdmul";
+ case PPC_ID_SPE_EFDNABS: return "efdnabs";
+ case PPC_ID_SPE_EFDNEG: return "efdneg";
+ case PPC_ID_SPE_EFDSUB: return "efdsub";
+ case PPC_ID_SPE_EFDTSTEQ: return "efdtsteq";
+ case PPC_ID_SPE_EFDTSTGT: return "efdtstgt";
+ case PPC_ID_SPE_EFDTSTLT: return "efdtstlt";
+ case PPC_ID_SPE_EFSABS: return "efsabs";
+ case PPC_ID_SPE_EFSADD: return "efsadd";
+ case PPC_ID_SPE_EFSCFD: return "efscfd";
+ case PPC_ID_SPE_EFSCFSF: return "efscfsf";
+ case PPC_ID_SPE_EFSCFSI: return "efscfsi";
+ case PPC_ID_SPE_EFSCFUF: return "efscfuf";
+ case PPC_ID_SPE_EFSCFUI: return "efscfui";
+ case PPC_ID_SPE_EFSCMPEQ: return "efscmpeq";
+ case PPC_ID_SPE_EFSCMPGT: return "efscmpgt";
+ case PPC_ID_SPE_EFSCMPLT: return "efscmplt";
+ case PPC_ID_SPE_EFSCTSF: return "efsctsf";
+ case PPC_ID_SPE_EFSCTSI: return "efsctsi";
+ case PPC_ID_SPE_EFSCTSIZ: return "efsctsiz";
+ case PPC_ID_SPE_EFSCTUF: return "efsctuf";
+ case PPC_ID_SPE_EFSCTUI: return "efsctui";
+ case PPC_ID_SPE_EFSCTUIZ: return "efsctuiz";
+ case PPC_ID_SPE_EFSDIV: return "efsdiv";
+ case PPC_ID_SPE_EFSMUL: return "efsmul";
+ case PPC_ID_SPE_EFSNABS: return "efsnabs";
+ case PPC_ID_SPE_EFSNEG: return "efsneg";
+ case PPC_ID_SPE_EFSSUB: return "efssub";
+ case PPC_ID_SPE_EFSTSTEQ: return "efststeq";
+ case PPC_ID_SPE_EFSTSTGT: return "efststgt";
+ case PPC_ID_SPE_EFSTSTLT: return "efststlt";
+ case PPC_ID_SPE_EVABS: return "evabs";
+ case PPC_ID_SPE_EVADDIW: return "evaddiw";
+ case PPC_ID_SPE_EVADDSMIAAW: return "evaddsmiaaw";
+ case PPC_ID_SPE_EVADDSSIAAW: return "evaddssiaaw";
+ case PPC_ID_SPE_EVADDUMIAAW: return "evaddumiaaw";
+ case PPC_ID_SPE_EVADDUSIAAW: return "evaddusiaaw";
+ case PPC_ID_SPE_EVADDW: return "evaddw";
+ case PPC_ID_SPE_EVAND: return "evand";
+ case PPC_ID_SPE_EVANDC: return "evandc";
+ case PPC_ID_SPE_EVCMPEQ: return "evcmpeq";
+ case PPC_ID_SPE_EVCMPGTS: return "evcmpgts";
+ case PPC_ID_SPE_EVCMPGTU: return "evcmpgtu";
+ case PPC_ID_SPE_EVCMPLTS: return "evcmplts";
+ case PPC_ID_SPE_EVCMPLTU: return "evcmpltu";
+ case PPC_ID_SPE_EVCNTLSW: return "evcntlsw";
+ case PPC_ID_SPE_EVCNTLZW: return "evcntlzw";
+ case PPC_ID_SPE_EVDIVWS: return "evdivws";
+ case PPC_ID_SPE_EVDIVWU: return "evdivwu";
+ case PPC_ID_SPE_EVEQV: return "eveqv";
+ case PPC_ID_SPE_EVEXTSB: return "evextsb";
+ case PPC_ID_SPE_EVEXTSH: return "evextsh";
+ case PPC_ID_SPE_EVFSABS: return "evfsabs";
+ case PPC_ID_SPE_EVFSADD: return "evfsadd";
+ case PPC_ID_SPE_EVFSCFSF: return "evfscfsf";
+ case PPC_ID_SPE_EVFSCFSI: return "evfscfsi";
+ case PPC_ID_SPE_EVFSCFUF: return "evfscfuf";
+ case PPC_ID_SPE_EVFSCFUI: return "evfscfui";
+ case PPC_ID_SPE_EVSCFUI: return "evscfui";
+ case PPC_ID_SPE_EVFSCMPEQ: return "evfscmpeq";
+ case PPC_ID_SPE_EVFSCMPGT: return "evfscmpgt";
+ case PPC_ID_SPE_EVFSCMPLT: return "evfscmplt";
+ case PPC_ID_SPE_EVFSCTSF: return "evfsctsf";
+ case PPC_ID_SPE_EVFSCTSI: return "evfsctsi";
+ case PPC_ID_SPE_EVFSCTSIZ: return "evfsctsiz";
+ case PPC_ID_SPE_EVFSCTUF: return "evfsctuf";
+ case PPC_ID_SPE_EVFSCTUI: return "evfsctui";
+ case PPC_ID_SPE_EVFSCTUIZ: return "evfsctuiz";
+ case PPC_ID_SPE_EVFSDIV: return "evfsdiv";
+ case PPC_ID_SPE_EVFSMUL: return "evfsmul";
+ case PPC_ID_SPE_EVFSNABS: return "evfsnabs";
+ case PPC_ID_SPE_EVFSNEG: return "evfsneg";
+ case PPC_ID_SPE_EVFSSUB: return "evfssub";
+ case PPC_ID_SPE_EVFSTSTEQ: return "evfststeq";
+ case PPC_ID_SPE_EVFSTSTGT: return "evfststgt";
+ case PPC_ID_SPE_EVFSTSTLT: return "evfststlt";
+ case PPC_ID_SPE_EVLDD: return "evldd";
+ case PPC_ID_SPE_EVLDDX: return "evlddx";
+ case PPC_ID_SPE_EVLDH: return "evldh";
+ case PPC_ID_SPE_EVLDHX: return "evldhx";
+ case PPC_ID_SPE_EVLDW: return "evldw";
+ case PPC_ID_SPE_EVLDWX: return "evldwx";
+ case PPC_ID_SPE_EVLHHESPLAT: return "evlhhesplat";
+ case PPC_ID_SPE_EVLHHESPLATX: return "evlhhesplatx";
+ case PPC_ID_SPE_EVLHHOSSPLAT: return "evlhhossplat";
+ case PPC_ID_SPE_EVLHHOSSPLATX: return "evlhhossplatx";
+ case PPC_ID_SPE_EVLHHOUSPLAT: return "evlhhousplat";
+ case PPC_ID_SPE_EVLHHOUSPLATX: return "evlhhousplatx";
+ case PPC_ID_SPE_EVLWHE: return "evlwhe";
+ case PPC_ID_SPE_EVLWHEX: return "evlwhex";
+ case PPC_ID_SPE_EVLWHOS: return "evlwhos";
+ case PPC_ID_SPE_EVLWHOSX: return "evlwhosx";
+ case PPC_ID_SPE_EVLWHOU: return "evlwhou";
+ case PPC_ID_SPE_EVLWHOUX: return "evlwhoux";
+ case PPC_ID_SPE_EVLWHSPLAT: return "evlwhsplat";
+ case PPC_ID_SPE_EVLWHSPLATX: return "evlwhsplatx";
+ case PPC_ID_SPE_EVLWWSPLAT: return "evlwwsplat";
+ case PPC_ID_SPE_EVLWWSPLATX: return "evlwwsplatx";
+ case PPC_ID_SPE_EVMERGEHI: return "evmergehi";
+ case PPC_ID_SPE_EVMERGEHILO: return "evmergehilo";
+ case PPC_ID_SPE_EVMERGELO: return "evmergelo";
+ case PPC_ID_SPE_EVMERGELOHI: return "evmergelohi";
+ case PPC_ID_SPE_EVMHEGSMFAA: return "evmhegsmfaa";
+ case PPC_ID_SPE_EVMHEGSMFAN: return "evmhegsmfan";
+ case PPC_ID_SPE_EVMHEGSMIAA: return "evmhegsmiaa";
+ case PPC_ID_SPE_EVMHEGSMIAN: return "evmhegsmian";
+ case PPC_ID_SPE_EVMHEGUMIAA: return "evmhegumiaa";
+ case PPC_ID_SPE_EVMHEGUMIAN: return "evmhegumian";
+ case PPC_ID_SPE_EVMHESMF: return "evmhesmf";
+ case PPC_ID_SPE_EVMHESMFA: return "evmhesmfa";
+ case PPC_ID_SPE_EVMHESMFAAW: return "evmhesmfaaw";
+ case PPC_ID_SPE_EVMHESMFANW: return "evmhesmfanw";
+ case PPC_ID_SPE_EVMHESMI: return "evmhesmi";
+ case PPC_ID_SPE_EVMHESMIA: return "evmhesmia";
+ case PPC_ID_SPE_EVMHESMIAAW: return "evmhesmiaaw";
+ case PPC_ID_SPE_EVMHESMIANW: return "evmhesmianw";
+ case PPC_ID_SPE_EVMHESSF: return "evmhessf";
+ case PPC_ID_SPE_EVMHESSFA: return "evmhessfa";
+ case PPC_ID_SPE_EVMHESSFAAW: return "evmhessfaaw";
+ case PPC_ID_SPE_EVMHESSFANW: return "evmhessfanw";
+ case PPC_ID_SPE_EVMHESSIAAW: return "evmhessiaaw";
+ case PPC_ID_SPE_EVMHESSIANW: return "evmhessianw";
+ case PPC_ID_SPE_EVMHEUMI: return "evmheumi";
+ case PPC_ID_SPE_EVMHEUMIA: return "evmheumia";
+ case PPC_ID_SPE_EVMHEUMIAAW: return "evmheumiaaw";
+ case PPC_ID_SPE_EVMHEUMIANW: return "evmheumianw";
+ case PPC_ID_SPE_EVMHEUSIAAW: return "evmheusiaaw";
+ case PPC_ID_SPE_EVMHEUSIANW: return "evmheusianw";
+ case PPC_ID_SPE_EVMHOGSMFAA: return "evmhogsmfaa";
+ case PPC_ID_SPE_EVMHOGSMFAN: return "evmhogsmfan";
+ case PPC_ID_SPE_EVMHOGSMIAA: return "evmhogsmiaa";
+ case PPC_ID_SPE_EVMHOGSMIAN: return "evmhogsmian";
+ case PPC_ID_SPE_EVMHOGUMIAA: return "evmhogumiaa";
+ case PPC_ID_SPE_EVMHOGUMIAN: return "evmhogumian";
+ case PPC_ID_SPE_EVMHOSMF: return "evmhosmf";
+ case PPC_ID_SPE_EVMHOSMFA: return "evmhosmfa";
+ case PPC_ID_SPE_EVMHOSMFAAW: return "evmhosmfaaw";
+ case PPC_ID_SPE_EVMHOSMFANW: return "evmhosmfanw";
+ case PPC_ID_SPE_EVMHOSMI: return "evmhosmi";
+ case PPC_ID_SPE_EVMHOSMIA: return "evmhosmia";
+ case PPC_ID_SPE_EVMHOSMIAAW: return "evmhosmiaaw";
+ case PPC_ID_SPE_EVMHOSMIANW: return "evmhosmianw";
+ case PPC_ID_SPE_EVMHOSSF: return "evmhossf";
+ case PPC_ID_SPE_EVMHOSSFA: return "evmhossfa";
+ case PPC_ID_SPE_EVMHOSSFAAW: return "evmhossfaaw";
+ case PPC_ID_SPE_EVMHOSSFANW: return "evmhossfanw";
+ case PPC_ID_SPE_EVMHOSSIAAW: return "evmhossiaaw";
+ case PPC_ID_SPE_EVMHOSSIANW: return "evmhossianw";
+ case PPC_ID_SPE_EVMHOUMI: return "evmhoumi";
+ case PPC_ID_SPE_EVMHOUMIA: return "evmhoumia";
+ case PPC_ID_SPE_EVMHOUMIAAW: return "evmhoumiaaw";
+ case PPC_ID_SPE_EVMHOUMIANW: return "evmhoumianw";
+ case PPC_ID_SPE_EVMHOUSIAAW: return "evmhousiaaw";
+ case PPC_ID_SPE_EVMHOUSIANW: return "evmhousianw";
+ case PPC_ID_SPE_EVMR: return "evmr";
+ case PPC_ID_SPE_EVMRA: return "evmra";
+ case PPC_ID_SPE_EVMWHSMF: return "evmwhsmf";
+ case PPC_ID_SPE_EVMWHSMFA: return "evmwhsmfa";
+ case PPC_ID_SPE_EVMWHSMI: return "evmwhsmi";
+ case PPC_ID_SPE_EVMWHSMIA: return "evmwhsmia";
+ case PPC_ID_SPE_EVMWHSSF: return "evmwhssf";
+ case PPC_ID_SPE_EVMWHSSFA: return "evmwhssfa";
+ case PPC_ID_SPE_EVMWHUMI: return "evmwhumi";
+ case PPC_ID_SPE_EVMWHUMIA: return "evmwhumia";
+ case PPC_ID_SPE_EVMWHUSIAAW: return "evmwhusiaaw";
+ case PPC_ID_SPE_EVMWHUSIANW: return "evmwhusianw";
+ case PPC_ID_SPE_EVMWLSMIAAW: return "evmwlsmiaaw";
+ case PPC_ID_SPE_EVMWLSMIANW: return "evmwlsmianw";
+ case PPC_ID_SPE_EVMWLSSIANW: return "evmwlssianw";
+ case PPC_ID_SPE_EVMWLSSIAAW: return "evmwlssiaaw";
+ case PPC_ID_SPE_EVMWLUMI: return "evmwlumi";
+ case PPC_ID_SPE_EVMWLUMIA: return "evmwlumia";
+ case PPC_ID_SPE_EVMWLUMIAAW: return "evmwlumiaaw";
+ case PPC_ID_SPE_EVMWLUMIANW: return "evmwlumianw";
+ case PPC_ID_SPE_EVMWLUSIAAW: return "evmwlusiaaw";
+ case PPC_ID_SPE_EVMWLUSIANW: return "evmwlusianw";
+ case PPC_ID_SPE_EVMWSMF: return "evmwsmf";
+ case PPC_ID_SPE_EVMWSMFA: return "evmwsmfa";
+ case PPC_ID_SPE_EVMWSMFAA: return "evmwsmfaa";
+ case PPC_ID_SPE_EVMWSMFAN: return "evmwsmfan";
+ case PPC_ID_SPE_EVMWSMI: return "evmwsmi";
+ case PPC_ID_SPE_EVMWSMIA: return "evmwsmia";
+ case PPC_ID_SPE_EVMWSMIAA: return "evmwsmiaa";
+ case PPC_ID_SPE_EVMWSMIAN: return "evmwsmian";
+ case PPC_ID_SPE_EVMWSSF: return "evmwssf";
+ case PPC_ID_SPE_EVMWSSFA: return "evmwssfa";
+ case PPC_ID_SPE_EVMWSSFAA: return "evmwssfaa";
+ case PPC_ID_SPE_EVMWSSFAN: return "evmwssfan";
+ case PPC_ID_SPE_EVMWUMI: return "evmwumi";
+ case PPC_ID_SPE_EVMWUMIA: return "evmwumia";
+ case PPC_ID_SPE_EVMWUMIAA: return "evmwumiaa";
+ case PPC_ID_SPE_EVMWUMIAN: return "evmwumian";
+ case PPC_ID_SPE_EVNAND: return "evnand";
+ case PPC_ID_SPE_EVNEG: return "evneg";
+ case PPC_ID_SPE_EVNOR: return "evnor";
+ case PPC_ID_SPE_EVNOT: return "evnot";
+ case PPC_ID_SPE_EVOR: return "evor";
+ case PPC_ID_SPE_EVORC: return "evorc";
+ case PPC_ID_SPE_EVRLW: return "evrlw";
+ case PPC_ID_SPE_EVRLWI: return "evrlwi";
+ case PPC_ID_SPE_EVRNDW: return "evrndw";
+ case PPC_ID_SPE_EVSEL: return "evsel";
+ case PPC_ID_SPE_EVSLW: return "evslw";
+ case PPC_ID_SPE_EVSLWI: return "evslwi";
+ case PPC_ID_SPE_EVSPLATFI: return "evsplatfi";
+ case PPC_ID_SPE_EVSPLATI: return "evsplati";
+ case PPC_ID_SPE_EVSRWIS: return "evsrwis";
+ case PPC_ID_SPE_EVSRWIU: return "evsrwiu";
+ case PPC_ID_SPE_EVSRWS: return "evsrws";
+ case PPC_ID_SPE_EVSRWU: return "evsrwu";
+ case PPC_ID_SPE_EVSTDD: return "evstdd";
+ case PPC_ID_SPE_EVSTDDX: return "evstddx";
+ case PPC_ID_SPE_EVSTDH: return "evstdh";
+ case PPC_ID_SPE_EVSTDHX: return "evstdhx";
+ case PPC_ID_SPE_EVSTDW: return "evstdw";
+ case PPC_ID_SPE_EVSTDWX: return "evstdwx";
+ case PPC_ID_SPE_EVSTWHE: return "evstwhe";
+ case PPC_ID_SPE_EVSTWHEX: return "evstwhex";
+ case PPC_ID_SPE_EVSTWHO: return "evstwho";
+ case PPC_ID_SPE_EVSTWHOX: return "evstwhox";
+ case PPC_ID_SPE_EVSTWWE: return "evstwwe";
+ case PPC_ID_SPE_EVSTWWEX: return "evstwwex";
+ case PPC_ID_SPE_EVSTWWO: return "evstwwo";
+ case PPC_ID_SPE_EVSTWWOX: return "evstwwox";
+ case PPC_ID_SPE_EVSUBFSMIAAW: return "evsubfsmiaaw";
+ case PPC_ID_SPE_EVSUBFSSIAAW: return "evsubfssiaaw";
+ case PPC_ID_SPE_EVSUBFUMIAAW: return "evsubfumiaaw";
+ case PPC_ID_SPE_EVSUBFUSIAAW: return "evsubfusiaaw";
+ case PPC_ID_SPE_EVSUBFW: return "evsubfw";
+ case PPC_ID_SPE_EVSUBIFW: return "evsubifw";
+ case PPC_ID_SPE_EVXOR: return "evxor";
+
+ case PPC_ID_VLE_E_ADDIx: return RcMnemonic(instruction, SubMnemVle32ADDIx);
+ case PPC_ID_VLE_E_ADDICx: return RcMnemonic(instruction, SubMnemVle32ADDICx);
+ case PPC_ID_VLE_E_ADD2I: return "e_add2i";
+ case PPC_ID_VLE_E_ADD2IS: return "e_add2is";
+ case PPC_ID_VLE_E_ADD16I: return "e_add16i";
+ case PPC_ID_VLE_E_ANDIx: return RcMnemonic(instruction, SubMnemVle32ANDIx);
+ case PPC_ID_VLE_E_AND2I: return "e_and2i";
+ case PPC_ID_VLE_E_AND2IS: return "e_and2is";
+ case PPC_ID_VLE_E_Bx: return LkMnemonic(instruction, SubMnemVle32Bx);
+ case PPC_ID_VLE_E_BCx:
+ {
+ uint32_t bo = instruction->operands[0].uimm;
+ uint32_t bi = instruction->operands[1].uimm;
+
+ switch (bo)
+ {
+ // Branch if false
+ case 0:
+ switch (bi & 0x3)
+ {
+ case 0: return LkMnemonic(instruction, SubMnemVle32BGEx);
+ case 1: return LkMnemonic(instruction, SubMnemVle32BLEx);
+ case 2: return LkMnemonic(instruction, SubMnemVle32BNEx);
+ case 3: return LkMnemonic(instruction, SubMnemVle32BNSx);
+
+ default:
+ return NULL;
+ }
+
+ break;
+
+ // Branch if true
+ case 1:
+ switch (bi & 0x3)
+ {
+ case 0: return LkMnemonic(instruction, SubMnemVle32BLTx);
+ case 1: return LkMnemonic(instruction, SubMnemVle32BGTx);
+ case 2: return LkMnemonic(instruction, SubMnemVle32BEQx);
+ case 3: return LkMnemonic(instruction, SubMnemVle32BSOx);
+
+ default:
+ return NULL;
+ }
+
+ break;
+
+ // Decrement CTR, branch if zero/nonzero
+ // BI doesn't matter
+ case 2: return LkMnemonic(instruction, SubMnemVle32BDNZx);
+ case 3: return LkMnemonic(instruction, SubMnemVle32BDZx);
+
+ // Should be unreachable; bo only 2 bits
+ default:
+ return NULL;
+ }
+ }
+ case PPC_ID_VLE_E_CMP16I: return "e_cmp16i";
+ case PPC_ID_VLE_E_CMPH16I: return "e_cmph16i";
+ case PPC_ID_VLE_E_CMPHL: return "e_cmphl";
+ case PPC_ID_VLE_E_CMPHL16I: return "e_cmphl16i";
+ case PPC_ID_VLE_E_CMPI: return "e_cmpi";
+ case PPC_ID_VLE_E_CMPL16I: return "e_cmpl16i";
+ case PPC_ID_VLE_E_CMPLI: return "e_cmpli";
+ case PPC_ID_VLE_E_CRAND: return "e_crand";
+ case PPC_ID_VLE_E_CRANDC: return "e_crandc";
+ case PPC_ID_VLE_E_CREQV: return "e_creqv";
+ case PPC_ID_VLE_E_CRNAND: return "e_crnand";
+ case PPC_ID_VLE_E_CRNOR: return "e_crnor";
+ case PPC_ID_VLE_E_CROR: return "e_cror";
+ case PPC_ID_VLE_E_CRORC: return "e_crorc";
+ case PPC_ID_VLE_E_CRXOR: return "e_crxor";
+ case PPC_ID_VLE_E_LBZ: return "e_lbz";
+ case PPC_ID_VLE_E_LBZU: return "e_lbzu";
+ case PPC_ID_VLE_E_LHA: return "e_lha";
+ case PPC_ID_VLE_E_LHAU: return "e_lhau";
+ case PPC_ID_VLE_E_LHZ: return "e_lhz";
+ case PPC_ID_VLE_E_LHZU: return "e_lhzu";
+ case PPC_ID_VLE_E_LI: return "e_li";
+ case PPC_ID_VLE_E_LIS: return "e_lis";
+ case PPC_ID_VLE_E_LMW: return "e_lmw";
+ case PPC_ID_VLE_E_LWZ: return "e_lwz";
+ case PPC_ID_VLE_E_LWZU: return "e_lwzu";
+ case PPC_ID_VLE_E_MCRF: return "e_mcrf";
+ case PPC_ID_VLE_E_MULL2I: return "e_mull2i";
+ case PPC_ID_VLE_E_MULLI: return "e_mulli";
+ case PPC_ID_VLE_E_OR2I: return "e_or2i";
+ case PPC_ID_VLE_E_OR2IS: return "e_or2is";
+ case PPC_ID_VLE_E_ORIx: return RcMnemonic(instruction, SubMnemVle32ORIx);
+ case PPC_ID_VLE_E_RLWx: return RcMnemonic(instruction, SubMnemVle32RLWx);
+ case PPC_ID_VLE_E_RLWIx: return RcMnemonic(instruction, SubMnemVle32RLWIx);
+ case PPC_ID_VLE_E_RLWIMI: return "e_rlwimi";
+ case PPC_ID_VLE_E_RLWINM: return "e_rlwinm";
+ case PPC_ID_VLE_E_SLWIx: return RcMnemonic(instruction, SubMnemVle32SLWIx);
+ case PPC_ID_VLE_E_SRWIx: return RcMnemonic(instruction, SubMnemVle32SRWIx);
+ case PPC_ID_VLE_E_STB: return "e_stb";
+ case PPC_ID_VLE_E_STBU: return "e_stbu";
+ case PPC_ID_VLE_E_STH: return "e_sth";
+ case PPC_ID_VLE_E_STHU: return "e_sthu";
+ case PPC_ID_VLE_E_STMW: return "e_stmw";
+ case PPC_ID_VLE_E_STW: return "e_stw";
+ case PPC_ID_VLE_E_STWU: return "e_stwu";
+ case PPC_ID_VLE_E_SUBFICx: return RcMnemonic(instruction, SubMnemVle32SUBFICx);
+ case PPC_ID_VLE_E_XORIx: return RcMnemonic(instruction, SubMnemVle32XORIx);
+
+ case PPC_ID_VLE_E_LDVGPRW: return "e_ldvgprw";
+ case PPC_ID_VLE_E_LDVSPRW: return "e_ldvsprw";
+ case PPC_ID_VLE_E_LDVSRRW: return "e_ldvsrrw";
+ case PPC_ID_VLE_E_LDVCSRRW: return "e_ldvcsrrw";
+ case PPC_ID_VLE_E_LDVDSRRW: return "e_ldvdsrrw";
+ case PPC_ID_VLE_E_STMVGPRW: return "e_stmvgprw";
+ case PPC_ID_VLE_E_STMVSPRW: return "e_stmvsprw";
+ case PPC_ID_VLE_E_STMVSRRW: return "e_stmvsrrw";
+ case PPC_ID_VLE_E_STMVCSRRW: return "e_stmvcsrrw";
+ case PPC_ID_VLE_E_STMVDSRRW: return "e_stmvdsrrw";
+
+ case PPC_ID_VLE_SE_ADD: return "se_add";
+ case PPC_ID_VLE_SE_ADDI: return "se_addi";
+ case PPC_ID_VLE_SE_ANDx: return RcMnemonic(instruction, SubMnemVle16ANDx);
+ case PPC_ID_VLE_SE_ANDC: return "se_andc";
+ case PPC_ID_VLE_SE_ANDI: return "se_andi";
+ case PPC_ID_VLE_SE_Bx: return LkMnemonic(instruction, SubMnemVle16Bx);
+ case PPC_ID_VLE_SE_BC:
+ {
+ uint32_t bo = instruction->operands[0].uimm;
+ uint32_t bi = instruction->operands[1].uimm;
+
+ switch (bo)
+ {
+ // Branch if false
+ case 0:
+ switch (bi & 0x3)
+ {
+ case 0: return "bgex";
+ case 1: return "blex";
+ case 2: return "bnex";
+ case 3: return "bnsx";
+
+ default:
+ return NULL;
+ }
+
+ break;
+
+ // Branch if true
+ case 1:
+ switch (bi & 0x3)
+ {
+ case 0: return "bltx";
+ case 1: return "bgtx";
+ case 2: return "beqx";
+ case 3: return "bsox";
+
+ default:
+ return NULL;
+ }
+
+ break;
+
+ // Should be unreachable; bo only 1 bit
+ default:
+ return NULL;
+ }
+ }
+ case PPC_ID_VLE_SE_BCLRI: return "se_bclri";
+ case PPC_ID_VLE_SE_BCTRx: return LkMnemonic(instruction, SubMnemVle16BCTRx);
+ case PPC_ID_VLE_SE_BGENI: return "se_bgeni";
+ case PPC_ID_VLE_SE_BLRx: return LkMnemonic(instruction, SubMnemVle16BLRx);
+ case PPC_ID_VLE_SE_BMASKI: return "se_bmaski";
+ case PPC_ID_VLE_SE_BSETI: return "se_bseti";
+ case PPC_ID_VLE_SE_BTSTI: return "se_btsti";
+ case PPC_ID_VLE_SE_CMP: return "se_cmp";
+ case PPC_ID_VLE_SE_CMPH: return "se_cmph";
+ case PPC_ID_VLE_SE_CMPHL: return "se_cmphl";
+ case PPC_ID_VLE_SE_CMPI: return "se_cmpi";
+ case PPC_ID_VLE_SE_CMPL: return "se_cmpl";
+ case PPC_ID_VLE_SE_CMPLI: return "se_cmpli";
+ case PPC_ID_VLE_SE_EXTSB: return "se_extsb";
+ case PPC_ID_VLE_SE_EXTSH: return "se_extsh";
+ case PPC_ID_VLE_SE_EXTZB: return "se_extzb";
+ case PPC_ID_VLE_SE_EXTZH: return "se_extzh";
+ case PPC_ID_VLE_SE_ILLEGAL: return "se_illegal";
+ case PPC_ID_VLE_SE_ISYNC: return "se_isync";
+ case PPC_ID_VLE_SE_LBZ: return "se_lbz";
+ case PPC_ID_VLE_SE_LHZ: return "se_lhz";
+ case PPC_ID_VLE_SE_LI: return "se_li";
+ case PPC_ID_VLE_SE_LWZ: return "se_lwz";
+ case PPC_ID_VLE_SE_MFAR: return "se_mfar";
+ case PPC_ID_VLE_SE_MFCTR: return "se_mfctr";
+ case PPC_ID_VLE_SE_MFLR: return "se_mflr";
+ case PPC_ID_VLE_SE_MR: return "se_mr";
+ case PPC_ID_VLE_SE_MTAR: return "se_mtar";
+ case PPC_ID_VLE_SE_MTCTR: return "se_mtctr";
+ case PPC_ID_VLE_SE_MTLR: return "se_mtlr";
+ case PPC_ID_VLE_SE_MULLW: return "se_mullw";
+ case PPC_ID_VLE_SE_NEG: return "se_neg";
+ case PPC_ID_VLE_SE_NOP: return "se_nop";
+ case PPC_ID_VLE_SE_NOT: return "se_not";
+ case PPC_ID_VLE_SE_OR: return "se_or";
+ case PPC_ID_VLE_SE_RFCI: return "se_rfci";
+ case PPC_ID_VLE_SE_RFDI: return "se_rfdi";
+ case PPC_ID_VLE_SE_RFI: return "se_rfi";
+ case PPC_ID_VLE_SE_RFMCI: return "se_rfmci";
+ case PPC_ID_VLE_SE_SC: return "se_sc";
+ case PPC_ID_VLE_SE_SLW: return "se_slw";
+ case PPC_ID_VLE_SE_SLWI: return "se_slwi";
+ case PPC_ID_VLE_SE_SRAW: return "se_sraw";
+ case PPC_ID_VLE_SE_SRAWI: return "se_srawi";
+ case PPC_ID_VLE_SE_SRW: return "se_srw";
+ case PPC_ID_VLE_SE_SRWI: return "se_srwi";
+ case PPC_ID_VLE_SE_STB: return "se_stb";
+ case PPC_ID_VLE_SE_STH: return "se_sth";
+ case PPC_ID_VLE_SE_STW: return "se_stw";
+ case PPC_ID_VLE_SE_SUB: return "se_sub";
+ case PPC_ID_VLE_SE_SUBF: return "se_subf";
+ case PPC_ID_VLE_SE_SUBIx: return RcMnemonic(instruction, SubMnemVle16SUBIx);
+
+ default: return NULL;
+ }
+}
diff --git a/arch/powerpc/decode/names.c b/arch/powerpc/decode/names.c
new file mode 100644
index 00000000..40ca5b7f
--- /dev/null
+++ b/arch/powerpc/decode/names.c
@@ -0,0 +1,296 @@
+#include "decode.h"
+
+const char* PowerPCRegisterName(uint32_t regId)
+{
+ switch (regId)
+ {
+ case PPC_REG_GPR0: return "r0";
+ case PPC_REG_GPR1: return "r1";
+ case PPC_REG_GPR2: return "r2";
+ case PPC_REG_GPR3: return "r3";
+ case PPC_REG_GPR4: return "r4";
+ case PPC_REG_GPR5: return "r5";
+ case PPC_REG_GPR6: return "r6";
+ case PPC_REG_GPR7: return "r7";
+ case PPC_REG_GPR8: return "r8";
+ case PPC_REG_GPR9: return "r9";
+ case PPC_REG_GPR10: return "r10";
+ case PPC_REG_GPR11: return "r11";
+ case PPC_REG_GPR12: return "r12";
+ case PPC_REG_GPR13: return "r13";
+ case PPC_REG_GPR14: return "r14";
+ case PPC_REG_GPR15: return "r15";
+ case PPC_REG_GPR16: return "r16";
+ case PPC_REG_GPR17: return "r17";
+ case PPC_REG_GPR18: return "r18";
+ case PPC_REG_GPR19: return "r19";
+ case PPC_REG_GPR20: return "r20";
+ case PPC_REG_GPR21: return "r21";
+ case PPC_REG_GPR22: return "r22";
+ case PPC_REG_GPR23: return "r23";
+ case PPC_REG_GPR24: return "r24";
+ case PPC_REG_GPR25: return "r25";
+ case PPC_REG_GPR26: return "r26";
+ case PPC_REG_GPR27: return "r27";
+ case PPC_REG_GPR28: return "r28";
+ case PPC_REG_GPR29: return "r29";
+ case PPC_REG_GPR30: return "r30";
+ case PPC_REG_GPR31: return "r31";
+
+ case PPC_REG_XER: return "xer";
+ case PPC_REG_LR: return "lr";
+ case PPC_REG_CTR: return "ctr";
+ case PPC_REG_CARRY: return "ca";
+ case PPC_REG_ZERO: return "zero";
+ case PPC_REG_VRSAVE: return "vrsave";
+
+ case PPC_REG_FR0: return "f0";
+ case PPC_REG_FR1: return "f1";
+ case PPC_REG_FR2: return "f2";
+ case PPC_REG_FR3: return "f3";
+ case PPC_REG_FR4: return "f4";
+ case PPC_REG_FR5: return "f5";
+ case PPC_REG_FR6: return "f6";
+ case PPC_REG_FR7: return "f7";
+ case PPC_REG_FR8: return "f8";
+ case PPC_REG_FR9: return "f9";
+ case PPC_REG_FR10: return "f10";
+ case PPC_REG_FR11: return "f11";
+ case PPC_REG_FR12: return "f12";
+ case PPC_REG_FR13: return "f13";
+ case PPC_REG_FR14: return "f14";
+ case PPC_REG_FR15: return "f15";
+ case PPC_REG_FR16: return "f16";
+ case PPC_REG_FR17: return "f17";
+ case PPC_REG_FR18: return "f18";
+ case PPC_REG_FR19: return "f19";
+ case PPC_REG_FR20: return "f20";
+ case PPC_REG_FR21: return "f21";
+ case PPC_REG_FR22: return "f22";
+ case PPC_REG_FR23: return "f23";
+ case PPC_REG_FR24: return "f24";
+ case PPC_REG_FR25: return "f25";
+ case PPC_REG_FR26: return "f26";
+ case PPC_REG_FR27: return "f27";
+ case PPC_REG_FR28: return "f28";
+ case PPC_REG_FR29: return "f29";
+ case PPC_REG_FR30: return "f30";
+ case PPC_REG_FR31: return "f31";
+
+ case PPC_REG_CRF0: return "cr0";
+ case PPC_REG_CRF1: return "cr1";
+ case PPC_REG_CRF2: return "cr2";
+ case PPC_REG_CRF3: return "cr3";
+ case PPC_REG_CRF4: return "cr4";
+ case PPC_REG_CRF5: return "cr5";
+ case PPC_REG_CRF6: return "cr6";
+ case PPC_REG_CRF7: return "cr7";
+
+ case PPC_REG_AV_VR0: return "v0";
+ case PPC_REG_AV_VR1: return "v1";
+ case PPC_REG_AV_VR2: return "v2";
+ case PPC_REG_AV_VR3: return "v3";
+ case PPC_REG_AV_VR4: return "v4";
+ case PPC_REG_AV_VR5: return "v5";
+ case PPC_REG_AV_VR6: return "v6";
+ case PPC_REG_AV_VR7: return "v7";
+ case PPC_REG_AV_VR8: return "v8";
+ case PPC_REG_AV_VR9: return "v9";
+ case PPC_REG_AV_VR10: return "v10";
+ case PPC_REG_AV_VR11: return "v11";
+ case PPC_REG_AV_VR12: return "v12";
+ case PPC_REG_AV_VR13: return "v13";
+ case PPC_REG_AV_VR14: return "v14";
+ case PPC_REG_AV_VR15: return "v15";
+ case PPC_REG_AV_VR16: return "v16";
+ case PPC_REG_AV_VR17: return "v17";
+ case PPC_REG_AV_VR18: return "v18";
+ case PPC_REG_AV_VR19: return "v19";
+ case PPC_REG_AV_VR20: return "v20";
+ case PPC_REG_AV_VR21: return "v21";
+ case PPC_REG_AV_VR22: return "v22";
+ case PPC_REG_AV_VR23: return "v23";
+ case PPC_REG_AV_VR24: return "v24";
+ case PPC_REG_AV_VR25: return "v25";
+ case PPC_REG_AV_VR26: return "v26";
+ case PPC_REG_AV_VR27: return "v27";
+ case PPC_REG_AV_VR28: return "v28";
+ case PPC_REG_AV_VR29: return "v29";
+ case PPC_REG_AV_VR30: return "v30";
+ case PPC_REG_AV_VR31: return "v31";
+
+ case PPC_REG_VSX_VR0: return "vs0";
+ case PPC_REG_VSX_VR1: return "vs1";
+ case PPC_REG_VSX_VR2: return "vs2";
+ case PPC_REG_VSX_VR3: return "vs3";
+ case PPC_REG_VSX_VR4: return "vs4";
+ case PPC_REG_VSX_VR5: return "vs5";
+ case PPC_REG_VSX_VR6: return "vs6";
+ case PPC_REG_VSX_VR7: return "vs7";
+ case PPC_REG_VSX_VR8: return "vs8";
+ case PPC_REG_VSX_VR9: return "vs9";
+ case PPC_REG_VSX_VR10: return "vs10";
+ case PPC_REG_VSX_VR11: return "vs11";
+ case PPC_REG_VSX_VR12: return "vs12";
+ case PPC_REG_VSX_VR13: return "vs13";
+ case PPC_REG_VSX_VR14: return "vs14";
+ case PPC_REG_VSX_VR15: return "vs15";
+ case PPC_REG_VSX_VR16: return "vs16";
+ case PPC_REG_VSX_VR17: return "vs17";
+ case PPC_REG_VSX_VR18: return "vs18";
+ case PPC_REG_VSX_VR19: return "vs19";
+ case PPC_REG_VSX_VR20: return "vs20";
+ case PPC_REG_VSX_VR21: return "vs21";
+ case PPC_REG_VSX_VR22: return "vs22";
+ case PPC_REG_VSX_VR23: return "vs23";
+ case PPC_REG_VSX_VR24: return "vs24";
+ case PPC_REG_VSX_VR25: return "vs25";
+ case PPC_REG_VSX_VR26: return "vs26";
+ case PPC_REG_VSX_VR27: return "vs27";
+ case PPC_REG_VSX_VR28: return "vs28";
+ case PPC_REG_VSX_VR29: return "vs29";
+ case PPC_REG_VSX_VR30: return "vs30";
+ case PPC_REG_VSX_VR31: return "vs31";
+ case PPC_REG_VSX_VR32: return "vs32";
+ case PPC_REG_VSX_VR33: return "vs33";
+ case PPC_REG_VSX_VR34: return "vs34";
+ case PPC_REG_VSX_VR35: return "vs35";
+ case PPC_REG_VSX_VR36: return "vs36";
+ case PPC_REG_VSX_VR37: return "vs37";
+ case PPC_REG_VSX_VR38: return "vs38";
+ case PPC_REG_VSX_VR39: return "vs39";
+ case PPC_REG_VSX_VR40: return "vs40";
+ case PPC_REG_VSX_VR41: return "vs41";
+ case PPC_REG_VSX_VR42: return "vs42";
+ case PPC_REG_VSX_VR43: return "vs43";
+ case PPC_REG_VSX_VR44: return "vs44";
+ case PPC_REG_VSX_VR45: return "vs45";
+ case PPC_REG_VSX_VR46: return "vs46";
+ case PPC_REG_VSX_VR47: return "vs47";
+ case PPC_REG_VSX_VR48: return "vs48";
+ case PPC_REG_VSX_VR49: return "vs49";
+ case PPC_REG_VSX_VR50: return "vs50";
+ case PPC_REG_VSX_VR51: return "vs51";
+ case PPC_REG_VSX_VR52: return "vs52";
+ case PPC_REG_VSX_VR53: return "vs53";
+ case PPC_REG_VSX_VR54: return "vs54";
+ case PPC_REG_VSX_VR55: return "vs55";
+ case PPC_REG_VSX_VR56: return "vs56";
+ case PPC_REG_VSX_VR57: return "vs57";
+ case PPC_REG_VSX_VR58: return "vs58";
+ case PPC_REG_VSX_VR59: return "vs59";
+ case PPC_REG_VSX_VR60: return "vs60";
+ case PPC_REG_VSX_VR61: return "vs61";
+ case PPC_REG_VSX_VR62: return "vs62";
+ case PPC_REG_VSX_VR63: return "vs63";
+
+ case PPC_REG_GQR0: return "gqr0";
+ case PPC_REG_GQR1: return "gqr1";
+ case PPC_REG_GQR2: return "gqr2";
+ case PPC_REG_GQR3: return "gqr3";
+ case PPC_REG_GQR4: return "gqr4";
+ case PPC_REG_GQR5: return "gqr5";
+ case PPC_REG_GQR6: return "gqr6";
+ case PPC_REG_GQR7: return "gqr7";
+
+ default: return NULL;
+ }
+}
+
+const char* OperandClassName(uint32_t cls)
+{
+ switch (cls)
+ {
+ case PPC_OP_NONE: return "<none>";
+ case PPC_OP_UIMM: return "UIMM";
+ case PPC_OP_SIMM: return "SIMM";
+ case PPC_OP_LABEL: return "LABEL";
+ case PPC_OP_MEM_RA: return "MEM(RA)";
+
+ case PPC_OP_REG_RA: return "RA";
+ case PPC_OP_REG_RB: return "RB";
+ case PPC_OP_REG_RC: return "RC";
+ case PPC_OP_REG_RD: return "RD";
+ case PPC_OP_REG_RS: return "RS";
+
+ case PPC_OP_REG_FRA: return "FRA";
+ case PPC_OP_REG_FRB: return "FRB";
+ case PPC_OP_REG_FRC: return "FRC";
+ case PPC_OP_REG_FRD: return "FRD";
+ case PPC_OP_REG_FRS: return "FRS";
+
+ case PPC_OP_REG_CRFD: return "CRFD";
+ case PPC_OP_REG_CRFD_IMPLY0: return "CRFD";
+ case PPC_OP_REG_CRFS: return "CRFS";
+ case PPC_OP_CRBIT: return "CRBIT";
+ case PPC_OP_CRBIT_A: return "CRBIT_A";
+ case PPC_OP_CRBIT_B: return "CRBIT_B";
+ case PPC_OP_CRBIT_D: return "CRBIT_C";
+
+ case PPC_OP_REG_AV_VA: return "ALTIVEC_VA";
+ case PPC_OP_REG_AV_VB: return "ALTIVEC_VB";
+ case PPC_OP_REG_AV_VC: return "ALTIVEC_VC";
+ case PPC_OP_REG_AV_VD: return "ALTIVEC_VD";
+ case PPC_OP_REG_AV_VS: return "ALTIVEC_VS";
+
+ case PPC_OP_REG_VSX_RA: return "VSX_RA";
+ case PPC_OP_REG_VSX_RA_DWORD0: return "VSX_RA0";
+
+ case PPC_OP_REG_VSX_RB: return "VSX_RB";
+ case PPC_OP_REG_VSX_RB_DWORD0: return "VSX_RB0";
+
+ case PPC_OP_REG_VSX_RC: return "VSX_RC";
+ case PPC_OP_REG_VSX_RC_DWORD0: return "VSX_RC0";
+
+ case PPC_OP_REG_VSX_RD: return "VSX_RD";
+ case PPC_OP_REG_VSX_RD_DWORD0: return "VSX_RD0";
+
+ case PPC_OP_REG_VSX_RS: return "VSX_RS";
+ case PPC_OP_REG_VSX_RS_DWORD0: return "VSX_RS0";
+
+ default:
+ return "???";
+ }
+}
+
+// These match the names in the "Condition Register" section
+const char* GetCRBitName(uint32_t crbit)
+{
+ switch (crbit)
+ {
+ case 0: return "lt";
+ case 1: return "gt";
+ case 2: return "eq";
+ case 3: return "so";
+ case 4: return "cr1lt";
+ case 5: return "cr1gt";
+ case 6: return "cr1eq";
+ case 7: return "cr1so";
+ case 8: return "cr2lt";
+ case 9: return "cr2gt";
+ case 10: return "cr2eq";
+ case 11: return "cr2so";
+ case 12: return "cr3lt";
+ case 13: return "cr3gt";
+ case 14: return "cr3eq";
+ case 15: return "cr3so";
+ case 16: return "cr4lt";
+ case 17: return "cr4gt";
+ case 18: return "cr4eq";
+ case 19: return "cr4so";
+ case 20: return "cr5lt";
+ case 21: return "cr5gt";
+ case 22: return "cr5eq";
+ case 23: return "cr5so";
+ case 24: return "cr6lt";
+ case 25: return "cr6gt";
+ case 26: return "cr6eq";
+ case 27: return "cr6so";
+ case 28: return "cr7lt";
+ case 29: return "cr7gt";
+ case 30: return "cr7eq";
+ case 31: return "cr7so";
+ default:
+ return NULL;
+ }
+}
diff --git a/arch/powerpc/decode/operands.c b/arch/powerpc/decode/operands.c
new file mode 100644
index 00000000..15628049
--- /dev/null
+++ b/arch/powerpc/decode/operands.c
@@ -0,0 +1,3288 @@
+#include <string.h>
+
+#include "decode.h"
+#include "priv.h"
+
+// see stanford bit twiddling hacks
+int32_t sign_extend(uint32_t x, unsigned numBits)
+{
+ int32_t const m = 1U << (numBits - 1);
+
+ x = x & ((1U << numBits) - 1);
+ return (x ^ m) - m;
+}
+
+Register Gpr(uint32_t value)
+{
+ return PPC_REG_GPR0 + value;
+}
+
+Register Fr(uint32_t value)
+{
+ return PPC_REG_FR0 + value;
+}
+
+Register Crf(uint32_t value)
+{
+ return PPC_REG_CRF0 + value;
+}
+
+Register AltivecVr(uint32_t value)
+{
+ return PPC_REG_AV_VR0 + value;
+}
+
+Register VsxVr(uint32_t value)
+{
+ return PPC_REG_VSX_VR0 + value;
+}
+
+Register VsxVrHi(uint32_t value)
+{
+ return PPC_REG_VSX_VR0 + value + 32;
+}
+
+void PushUIMMValue(Instruction* instruction, uint64_t uimm)
+{
+ instruction->operands[instruction->numOperands].cls = PPC_OP_UIMM;
+ instruction->operands[instruction->numOperands].uimm = uimm;
+ ++instruction->numOperands;
+}
+
+void PushSIMMValue(Instruction* instruction, int32_t simm)
+{
+ instruction->operands[instruction->numOperands].cls = PPC_OP_SIMM;
+ instruction->operands[instruction->numOperands].simm = simm;
+ ++instruction->numOperands;
+}
+
+void PushRegister(Instruction* instruction, OperandClass cls, Register reg)
+{
+ instruction->operands[instruction->numOperands].cls = cls;
+ instruction->operands[instruction->numOperands].reg = reg;
+ ++instruction->numOperands;
+}
+
+uint64_t ComputeBranchTarget(Instruction* instruction, uint64_t address, uint32_t word32)
+{
+ int32_t bd = (int32_t)((int16_t)(word32 & 0xfffc));
+
+ return instruction->flags.aa ? bd : address + bd;
+}
+
+void PushLabel(Instruction* instruction, uint64_t address)
+{
+ instruction->operands[instruction->numOperands].cls = PPC_OP_LABEL;
+ instruction->operands[instruction->numOperands].label = address;
+ ++instruction->numOperands;
+}
+
+// this assumes that instruction->flags.aa has been properly set!
+void PushBranchTarget(Instruction* instruction, uint64_t address, uint32_t word32)
+{
+ PushLabel(instruction, ComputeBranchTarget(instruction, address, word32));
+}
+
+void PushRA(Instruction* instruction, uint32_t word32)
+{
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(GetA(word32)));
+}
+
+void PushRAor0(Instruction* instruction, uint32_t word32)
+{
+ uint32_t ra = GetA(word32);
+
+ if (ra == 0)
+ PushUIMMValue(instruction, 0);
+ else
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(ra));
+}
+
+void PushRB(Instruction* instruction, uint32_t word32)
+{
+ PushRegister(instruction, PPC_OP_REG_RB, Gpr(GetB(word32)));
+}
+
+void PushRC(Instruction* instruction, uint32_t word32)
+{
+ PushRegister(instruction, PPC_OP_REG_RC, Gpr(GetC(word32)));
+}
+
+void PushRD(Instruction* instruction, uint32_t word32)
+{
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(GetD(word32)));
+}
+
+void PushRS(Instruction* instruction, uint32_t word32)
+{
+ PushRegister(instruction, PPC_OP_REG_RS, Gpr(GetS(word32)));
+}
+
+void PushFRA(Instruction* instruction, uint32_t word32)
+{
+ PushRegister(instruction, PPC_OP_REG_FRA, Fr(GetA(word32)));
+}
+
+void PushFRB(Instruction* instruction, uint32_t word32)
+{
+ PushRegister(instruction, PPC_OP_REG_FRB, Fr(GetB(word32)));
+}
+
+void PushFRC(Instruction* instruction, uint32_t word32)
+{
+ PushRegister(instruction, PPC_OP_REG_FRC, Fr(GetC(word32)));
+}
+
+void PushFRD(Instruction* instruction, uint32_t word32)
+{
+ PushRegister(instruction, PPC_OP_REG_FRD, Fr(GetD(word32)));
+}
+
+void PushFRS(Instruction* instruction, uint32_t word32)
+{
+ PushRegister(instruction, PPC_OP_REG_FRS, Fr(GetS(word32)));
+}
+
+void PushCRFD(Instruction* instruction, uint32_t word32)
+{
+ uint32_t crfd = (word32 >> 23) & 0x7;
+ PushRegister(instruction, PPC_OP_REG_CRFD, Crf(crfd));
+}
+
+void PushCRFDImplyCR0(Instruction* instruction, uint32_t word32)
+{
+ uint32_t crfd = (word32 >> 23) & 0x7;
+
+ PushRegister(instruction, PPC_OP_REG_CRFD_IMPLY0, Crf(crfd));
+}
+
+void PushCRFS(Instruction* instruction, uint32_t word32)
+{
+ uint32_t crfs = (word32 >> 18) & 0x7;
+ PushRegister(instruction, PPC_OP_REG_CRFS, Crf(crfs));
+}
+
+void PushCRBitA(Instruction* instruction, uint32_t word32)
+{
+ instruction->operands[instruction->numOperands].cls = PPC_OP_CRBIT_A;
+ instruction->operands[instruction->numOperands].crbit = GetA(word32);
+ ++instruction->numOperands;
+}
+
+void PushCRBitB(Instruction* instruction, uint32_t word32)
+{
+ instruction->operands[instruction->numOperands].cls = PPC_OP_CRBIT_B;
+ instruction->operands[instruction->numOperands].crbit = GetB(word32);
+ ++instruction->numOperands;
+}
+
+void PushCRBitD(Instruction* instruction, uint32_t word32)
+{
+ instruction->operands[instruction->numOperands].cls = PPC_OP_CRBIT_D;
+ instruction->operands[instruction->numOperands].crbit = GetD(word32);
+ ++instruction->numOperands;
+}
+
+void PushMem(Instruction* instruction, OperandClass cls, Register reg, int32_t offset)
+{
+ instruction->operands[instruction->numOperands].cls = cls;
+ instruction->operands[instruction->numOperands].mem.reg = reg;
+ instruction->operands[instruction->numOperands].mem.offset = offset;
+ ++instruction->numOperands;
+}
+
+void FillBranchLikelyHint(Instruction* instruction, uint32_t word32)
+{
+ uint32_t bo = GetBO(word32);
+
+ switch (bo >> 2)
+ {
+ // 001at
+ // 011at
+ case 1:
+ case 3:
+ instruction->flags.branchLikelyHint = bo & 0x3;
+ break;
+
+ // 1a00t
+ // 1a01t
+ case 4:
+ case 6:
+ instruction->flags.branchLikelyHint = ((bo >> 2) & 0x2) | (bo & 0x1);
+ break;
+
+ // all others don't have hints
+ default:
+ instruction->flags.branchLikelyHint = 0;
+ }
+}
+
+void PushMemRAOffset(Instruction* instruction, uint32_t word32, int32_t offset)
+{
+ PushMem(instruction, PPC_OP_MEM_RA, Gpr(GetA(word32)), offset);
+}
+
+// Default of d=lower 16 bits
+void PushMemRA(Instruction* instruction, uint32_t word32)
+{
+ PushMemRAOffset(instruction, word32, (int32_t)((int16_t)(word32 & 0xffff)));
+}
+
+void PushVsxA(Instruction* instruction, uint32_t word32, VsxWidth width)
+{
+ PushRegister(instruction,
+ width == VSX_WIDTH_FULL ? PPC_OP_REG_VSX_RA : PPC_OP_REG_VSX_RA_DWORD0,
+ VsxVr(GetVsxA(word32)));
+}
+
+void PushVsxHiA(Instruction* instruction, uint32_t word32)
+{
+ PushRegister(instruction, PPC_OP_REG_VSX_RA, VsxVrHi(GetA(word32)));
+}
+
+void PushVsxB(Instruction* instruction, uint32_t word32, VsxWidth width)
+{
+ PushRegister(instruction,
+ width == VSX_WIDTH_FULL ? PPC_OP_REG_VSX_RB : PPC_OP_REG_VSX_RB_DWORD0,
+ VsxVr(GetVsxB(word32)));
+}
+
+void PushVsxHiB(Instruction* instruction, uint32_t word32)
+{
+ PushRegister(instruction, PPC_OP_REG_VSX_RB, VsxVrHi(GetB(word32)));
+}
+
+void PushVsxC(Instruction* instruction, uint32_t word32, VsxWidth width)
+{
+ PushRegister(instruction,
+ width == VSX_WIDTH_FULL ? PPC_OP_REG_VSX_RC : PPC_OP_REG_VSX_RC_DWORD0,
+ VsxVr(GetVsxC(word32)));
+}
+
+void PushVsxD(Instruction* instruction, uint32_t word32, VsxWidth width)
+{
+ PushRegister(instruction,
+ width == VSX_WIDTH_FULL ? PPC_OP_REG_VSX_RD : PPC_OP_REG_VSX_RD_DWORD0,
+ VsxVr(GetVsxD(word32)));
+}
+
+void PushVsxHiD(Instruction* instruction, uint32_t word32)
+{
+ PushRegister(instruction, PPC_OP_REG_VSX_RD, VsxVrHi(GetD(word32)));
+}
+
+void PushVsxS(Instruction* instruction, uint32_t word32, VsxWidth width)
+{
+ uint32_t sx = word32 & 0x1;
+ uint32_t s = (word32 >> 21) & 0x1f;
+ PushRegister(instruction,
+ width == VSX_WIDTH_FULL ? PPC_OP_REG_VSX_RS : PPC_OP_REG_VSX_RS_DWORD0,
+ VsxVr((sx << 5) | s));
+}
+
+void PushVsxHiS(Instruction* instruction, uint32_t word32)
+{
+ PushRegister(instruction, PPC_OP_REG_VSX_RS, VsxVrHi(GetS(word32)));
+}
+
+void PushAltivecVA(Instruction* instruction, uint32_t word32)
+{
+ uint32_t va = (word32 >> 16) & 0x1f;
+ PushRegister(instruction, PPC_OP_REG_AV_VA, AltivecVr(va));
+}
+
+void PushAltivecVB(Instruction* instruction, uint32_t word32)
+{
+ uint32_t vb = (word32 >> 11) & 0x1f;
+ PushRegister(instruction, PPC_OP_REG_AV_VB, AltivecVr(vb));
+}
+
+void PushAltivecVC(Instruction* instruction, uint32_t word32)
+{
+ uint32_t vc = (word32 >> 6) & 0x1f;
+ PushRegister(instruction, PPC_OP_REG_AV_VC, AltivecVr(vc));
+}
+
+void PushAltivecVD(Instruction* instruction, uint32_t word32)
+{
+ uint32_t vd = (word32 >> 21) & 0x1f;
+ PushRegister(instruction, PPC_OP_REG_AV_VD, AltivecVr(vd));
+}
+
+void PushAltivecVS(Instruction* instruction, uint32_t word32)
+{
+ uint32_t vs = (word32 >> 21) & 0x1f;
+ PushRegister(instruction, PPC_OP_REG_AV_VS, AltivecVr(vs));
+}
+
+void FillOperands32(Instruction* instruction, uint32_t word32, uint64_t address)
+{
+ switch (instruction->id)
+ {
+ // instructions with no operands
+ case PPC_ID_ATTN:
+ case PPC_ID_CP_ABORT:
+ case PPC_ID_DCCCI:
+ case PPC_ID_HRFID:
+ case PPC_ID_ICCCI:
+ case PPC_ID_ISYNC:
+ case PPC_ID_LWSYNC:
+ case PPC_ID_MSGSYNC:
+ case PPC_ID_NAP:
+ case PPC_ID_NOP:
+ case PPC_ID_PTESYNC:
+ case PPC_ID_RFCI:
+ case PPC_ID_RFDI:
+ case PPC_ID_RFI:
+ case PPC_ID_RFID:
+ case PPC_ID_RFMCI:
+ case PPC_ID_STOP:
+ case PPC_ID_SYNC:
+ case PPC_ID_TLBIA:
+ case PPC_ID_TLBSYNC:
+ case PPC_ID_TRAP:
+ case PPC_ID_TRECHKPT:
+ case PPC_ID_SLBIA:
+ case PPC_ID_SLBSYNC:
+ case PPC_ID_XNOP:
+ case PPC_ID_WAITIMPL:
+ case PPC_ID_WAITRSV:
+ case PPC_ID_AV_DSSALL:
+ break;
+
+ // <op> rD
+ case PPC_ID_LNIA:
+ case PPC_ID_MFBR0:
+ case PPC_ID_MFBR1:
+ case PPC_ID_MFBR2:
+ case PPC_ID_MFBR3:
+ case PPC_ID_MFBR4:
+ case PPC_ID_MFBR5:
+ case PPC_ID_MFBR6:
+ case PPC_ID_MFBR7:
+ case PPC_ID_MFCR:
+ case PPC_ID_MFCTR:
+ case PPC_ID_MFLR:
+ case PPC_ID_MFMSR:
+ case PPC_ID_MFTBU:
+ case PPC_ID_MFXER:
+ PushRD(instruction, word32);
+ break;
+
+ // <op> rS
+ case PPC_ID_MTBR0:
+ case PPC_ID_MTBR1:
+ case PPC_ID_MTBR2:
+ case PPC_ID_MTBR3:
+ case PPC_ID_MTBR4:
+ case PPC_ID_MTBR5:
+ case PPC_ID_MTBR6:
+ case PPC_ID_MTBR7:
+ case PPC_ID_MTCTR:
+ case PPC_ID_MTLR:
+ case PPC_ID_MTMSR:
+ case PPC_ID_MTMSRD:
+ case PPC_ID_MTXER:
+ case PPC_ID_WRTEE:
+ PushRS(instruction, word32);
+ break;
+
+ // <op> rA
+ case PPC_ID_TABORT:
+ case PPC_ID_TRECLAIM:
+ PushRA(instruction, word32);
+ break;
+
+ // <op> rB
+ case PPC_ID_TLBIEL:
+ case PPC_ID_TLBLI:
+ case PPC_ID_SLBIE:
+ PushRB(instruction, word32);
+ break;
+
+ // <op>[.] rD, rA (arithmetic)
+ case PPC_ID_NEGx:
+ case PPC_ID_SUBFZEx:
+ case PPC_ID_ADDZEx:
+ case PPC_ID_SUBFMEx:
+ case PPC_ID_ADDMEx:
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+
+ // some of these instructions don't have an "oe" flag,
+ // but we rely on the fact that those instructions have
+ // bitmask 0x400 clear in the switch statement on the
+ instruction->flags.rc = word32 & 0x1;
+ instruction->flags.oe = (word32 & 0x400) != 0;
+ break;
+
+ // <op>[.] rD, rA, rB (arithmetic)
+ case PPC_ID_ADDx:
+ case PPC_ID_ADDCx:
+ case PPC_ID_ADDEx:
+ case PPC_ID_DIVDx:
+ case PPC_ID_DIVDEx:
+ case PPC_ID_DIVDEUx:
+ case PPC_ID_DIVDUx:
+ case PPC_ID_DIVWx:
+ case PPC_ID_DIVWEx:
+ case PPC_ID_DIVWEUx:
+ case PPC_ID_DIVWUx:
+ case PPC_ID_MODSD:
+ case PPC_ID_MODSW:
+ case PPC_ID_MODUD:
+ case PPC_ID_MODUW:
+ case PPC_ID_MULHDx:
+ case PPC_ID_MULHDUx:
+ case PPC_ID_MULHWx:
+ case PPC_ID_MULHWUx:
+ case PPC_ID_MULLDx:
+ case PPC_ID_MULLWx:
+ case PPC_ID_SUBFx:
+ case PPC_ID_SUBFCx:
+ case PPC_ID_SUBFEx:
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+
+ // some of these instructions don't have an "oe" flag,
+ // but we rely on the fact that those instructions have
+ // bitmask 0x400 clear in the switch statement on the
+ // 0x7ff mask
+ instruction->flags.rc = word32 & 0x1;
+ instruction->flags.oe = (word32 & 0x400) != 0;
+ break;
+
+
+ // <op>[.] rA, rS (logical)
+ case PPC_ID_CNTLZWx:
+ case PPC_ID_CNTLZDx:
+ case PPC_ID_CNTTZWx:
+ case PPC_ID_CNTTZDx:
+ case PPC_ID_POPCNTB:
+ case PPC_ID_POPCNTD:
+ case PPC_ID_POPCNTW:
+ case PPC_ID_EXTSHx:
+ case PPC_ID_EXTSBx:
+ case PPC_ID_EXTSWx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+
+ // not all of these have RC bits, but it gets filtered
+ // at subop decode step
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ // <op>[.] rA, rS, rB
+ case PPC_ID_ANDx:
+ case PPC_ID_ANDCx:
+ case PPC_ID_BPERMD:
+ case PPC_ID_CMPB:
+ case PPC_ID_ECIWX:
+ case PPC_ID_ECOWX:
+ case PPC_ID_EQVx:
+ case PPC_ID_NANDx:
+ case PPC_ID_NORx:
+ case PPC_ID_ORx:
+ case PPC_ID_ORCx:
+ case PPC_ID_ROTLWx:
+ case PPC_ID_ROTLDx:
+ case PPC_ID_SLDx:
+ case PPC_ID_SLWx:
+ case PPC_ID_SRADx:
+ case PPC_ID_SRAWx:
+ case PPC_ID_SRDx:
+ case PPC_ID_SRWx:
+ case PPC_ID_XORx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushRB(instruction, word32);
+
+ // not all of these have an rc bit, but they just don't
+ // get recognized at the switch statement with &0x7ff
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_ROTLWIx:
+ case PPC_ID_SLWIx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, GetSH(word32));
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_CLRLWIx:
+ case PPC_ID_SRWIx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, GetMB(word32));
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_CLRRWIx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+
+ // me = 31 - n --> n = 31 - me
+ PushUIMMValue(instruction, 31 - GetME(word32));
+ // PushUIMMValue(instruction, GetME(word32));
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_RLDCLx:
+ case PPC_ID_RLDCRx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushRB(instruction, word32);
+ PushUIMMValue(instruction, GetMX64(word32));
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_EXTLDIx:
+ // Decoder will never generate this extended mnemonic, but handle its operands anyway
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+
+ // extldi ra,rs,n,b (n>0) --> rldicr ra,rs,b,n−1
+ PushUIMMValue(instruction, GetMX64(word32));
+ PushUIMMValue(instruction, GetSH64(word32) - 1);
+ // PushUIMMValue(instruction, GetSH64(word32));
+ // PushUIMMValue(instruction, GetMX64(word32));
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_EXTRDIx:
+ // Decoder will never generate this extended mnemonic, but handle its operands anyway
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+
+ // extrdi ra,rs,n,b (n>0) --> rldicl ra,rs,b+n,64−n
+ PushUIMMValue(instruction, GetMX64(word32) + GetSH64(word32));
+ PushUIMMValue(instruction, 64 - GetSH64(word32));
+ // PushUIMMValue(instruction, GetSH64(word32));
+ // PushUIMMValue(instruction, GetMX64(word32));
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+
+ case PPC_ID_RLDICx:
+ case PPC_ID_RLDICLx:
+ case PPC_ID_RLDICRx:
+ case PPC_ID_RLDIMIx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, GetSH64(word32));
+ PushUIMMValue(instruction, GetMX64(word32));
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_CLRLDIx:
+ case PPC_ID_CLRRDIx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ if (instruction->id == PPC_ID_CLRRDIx)
+ PushUIMMValue(instruction, 63 - GetMX64(word32));
+ // PushUIMMValue(instruction, GetMX64(word32));
+ else
+ PushUIMMValue(instruction, GetMX64(word32));
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_ROTLDIx:
+ case PPC_ID_ROTRDIx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ if (instruction->id == PPC_ID_ROTRDIx)
+ PushUIMMValue(instruction, 64 - GetSH64(word32));
+ // PushUIMMValue(instruction, GetSH64(word32));
+ else
+ PushUIMMValue(instruction, GetSH64(word32));
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_SLDIx:
+ case PPC_ID_SRDIx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, GetSH64(word32));
+ // if (instruction->id == PPC_ID_SRDIx)
+ // PushUIMMValue(instruction, 64 - GetSH64(word32));
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_BCx:
+ {
+ uint32_t bo = GetBO(word32);
+ uint32_t bi = GetBI(word32);
+
+ instruction->flags.lk = word32 & 0x1;
+ instruction->flags.aa = (word32 & 0x2) != 0;
+
+ // not all BCx have hints, but if they don't, then those
+ // hints won't be read by anything anyways
+ FillBranchLikelyHint(instruction, word32);
+
+ PushUIMMValue(instruction, bo);
+ PushUIMMValue(instruction, bi);
+ PushBranchTarget(instruction, address, word32);
+
+ break;
+ }
+
+ // <op> crfD, rA, rB
+ case PPC_ID_CMPD:
+ case PPC_ID_CMPEQB:
+ case PPC_ID_CMPW:
+ case PPC_ID_CMPLD:
+ case PPC_ID_CMPLW:
+ PushCRFDImplyCR0(instruction, word32);
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ // <op> crfD, rA, SIMM
+ case PPC_ID_CMPDI:
+ case PPC_ID_CMPWI:
+ {
+ int32_t simm = (int32_t)((int16_t)(word32 & 0xffff));
+
+ PushCRFDImplyCR0(instruction, word32);
+ PushRA(instruction, word32);
+ PushSIMMValue(instruction, simm);
+ break;
+ }
+
+ // <op> crfD, rA, UIMM
+ case PPC_ID_CMPLDI:
+ case PPC_ID_CMPLWI:
+ {
+ uint32_t uimm = word32 & 0xffff;
+
+ PushCRFDImplyCR0(instruction, word32);
+ PushRA(instruction, word32);
+ PushUIMMValue(instruction, uimm);
+ break;
+ }
+
+ // <op> rA, rB
+ case PPC_ID_COPY:
+ case PPC_ID_PASTE:
+ case PPC_ID_TDEQ:
+ case PPC_ID_TDGT:
+ case PPC_ID_TDLGT:
+ case PPC_ID_TDLLT:
+ case PPC_ID_TDLT:
+ case PPC_ID_TDNE:
+ case PPC_ID_TDU:
+ case PPC_ID_TLBSX:
+ case PPC_ID_TWEQ:
+ case PPC_ID_TWGT:
+ case PPC_ID_TWLGT:
+ case PPC_ID_TWLLT:
+ case PPC_ID_TWLT:
+ case PPC_ID_TWNE:
+ case PPC_ID_TWU:
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ // <trap> TO, rA, rB
+ case PPC_ID_TD:
+ case PPC_ID_TW:
+ case PPC_ID_TABORTDC:
+ case PPC_ID_TABORTWC:
+ {
+ uint32_t to = (word32 >> 21) & 0x1f;
+
+ PushUIMMValue(instruction, to);
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+ }
+
+ // <trap> rA, SIMM
+ case PPC_ID_TDEQI:
+ case PPC_ID_TDGTI:
+ case PPC_ID_TDLGTI:
+ case PPC_ID_TDLLTI:
+ case PPC_ID_TDLTI:
+ case PPC_ID_TDNEI:
+ case PPC_ID_TDUI:
+ case PPC_ID_TWEQI:
+ case PPC_ID_TWGTI:
+ case PPC_ID_TWLGTI:
+ case PPC_ID_TWLLTI:
+ case PPC_ID_TWLTI:
+ case PPC_ID_TWNEI:
+ case PPC_ID_TWUI:
+ {
+ int32_t simm = (int32_t)((int16_t)(word32 & 0xffff));
+
+ PushRA(instruction, word32);
+ PushSIMMValue(instruction, simm);
+ break;
+ }
+
+ // <trap> TO, rA, SIMM
+ case PPC_ID_TDI:
+ case PPC_ID_TWI:
+ {
+ uint32_t to = (word32 >> 21) & 0x1f;
+ int32_t simm = (int32_t)((int16_t)(word32 & 0xffff));
+
+ PushUIMMValue(instruction, to);
+ PushRA(instruction, word32);
+ PushSIMMValue(instruction, simm);
+ break;
+ }
+
+ // <tabort> TO, rA, SIMM
+ case PPC_ID_TABORTDCI:
+ case PPC_ID_TABORTWCI:
+ {
+ uint32_t to = (word32 >> 21) & 0x1f;
+ int32_t simm = sign_extend((word32 >> 11) & 0x1f, 5);
+
+ PushUIMMValue(instruction, to);
+ PushRA(instruction, word32);
+ PushSIMMValue(instruction, simm);
+ break;
+ }
+
+ // <op> rD, rA, SIMM
+ case PPC_ID_ADDIx:
+ case PPC_ID_MULLI:
+ case PPC_ID_SUBFICx:
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushSIMMValue(instruction, (int32_t)((int16_t)(word32 & 0xffff)));
+ break;
+
+ // <op> rA, rS, UIMM
+ case PPC_ID_ORIx:
+ case PPC_ID_XORIx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, word32 & 0xffff);
+
+ instruction->flags.rc = false;
+ break;
+
+ // differentiated in case it makes sense to use the shifted value as an operand
+ // (which we do for now since it matches capstone)
+ // <op> rA, rS, UIMM
+ case PPC_ID_ORIS:
+ case PPC_ID_XORIS:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, word32 & 0xffff);
+ break;
+
+ // <op> rD, d(rA)
+ case PPC_ID_LBZ:
+ case PPC_ID_LBZU:
+ case PPC_ID_LHA:
+ case PPC_ID_LHAU:
+ case PPC_ID_LHZ:
+ case PPC_ID_LHZU:
+ case PPC_ID_LMW:
+ case PPC_ID_LWZ:
+ case PPC_ID_LWZU:
+ PushRD(instruction, word32);
+ PushMemRA(instruction, word32);
+ break;
+
+ // <op> rD, d(rA) (64-bit)
+ case PPC_ID_LD:
+ case PPC_ID_LDU:
+ case PPC_ID_LWA:
+ {
+ PushRD(instruction, word32);
+
+ int32_t ds = (int32_t)((int16_t)(word32 & 0xfffc));
+ PushMem(instruction, PPC_OP_MEM_RA, Gpr(GetA(word32)), ds);
+ break;
+ }
+
+ // <op> rD, rA, rB (indexed load)
+ case PPC_ID_LBEPX:
+ case PPC_ID_LBZCIX:
+ case PPC_ID_LBZUX:
+ case PPC_ID_LBZX:
+ case PPC_ID_LDBRX:
+ case PPC_ID_LDCIX:
+ case PPC_ID_LDUX:
+ case PPC_ID_LDX:
+ case PPC_ID_LHAUX:
+ case PPC_ID_LHAX:
+ case PPC_ID_LHBRX:
+ case PPC_ID_LHEPX:
+ case PPC_ID_LHZCIX:
+ case PPC_ID_LHZX:
+ case PPC_ID_LHZUX:
+ case PPC_ID_LSWX:
+ case PPC_ID_LWAX:
+ case PPC_ID_LWAUX:
+ case PPC_ID_LWBRX:
+ case PPC_ID_LWEPX:
+ case PPC_ID_LWZCIX:
+ case PPC_ID_LWZUX:
+ case PPC_ID_LWZX:
+ PushRD(instruction, word32);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ // <op> rD, rA, rB, [EH if nonzero] (indexed load)
+ case PPC_ID_LBARX:
+ case PPC_ID_LDARX:
+ case PPC_ID_LHARX:
+ case PPC_ID_LWARX:
+ {
+ PushRD(instruction, word32);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ uint32_t eh = word32 & 0x1;
+ // NOTE: this breaks with convention by only
+ // conditionally including EH
+ if (eh)
+ PushUIMMValue(instruction, word32 & 0x1);
+ break;
+ }
+
+ // <op> rD, rA, FC
+ case PPC_ID_LDAT:
+ case PPC_ID_LWAT:
+ {
+ uint32_t fc = (word32 >> 11) & 0x1f;
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushUIMMValue(instruction, fc);
+ break;
+ }
+
+ // <op> rS, rA, FC
+ case PPC_ID_STDAT:
+ case PPC_ID_STWAT:
+ {
+ uint32_t fc = (word32 >> 11) & 0x1f;
+ PushRS(instruction, word32);
+ PushRA(instruction, word32);
+ PushUIMMValue(instruction, fc);
+ break;
+ }
+
+
+ // <op> rS, d(RA)
+ case PPC_ID_STB:
+ case PPC_ID_STBU:
+ case PPC_ID_STH:
+ case PPC_ID_STHU:
+ case PPC_ID_STMW:
+ case PPC_ID_STW:
+ case PPC_ID_STWU:
+ PushRS(instruction, word32);
+ PushMemRA(instruction, word32);
+ break;
+
+ // <op> rS, d(RA) (64-bit)
+ case PPC_ID_STD:
+ case PPC_ID_STDU:
+ {
+ PushRS(instruction, word32);
+
+ int32_t ds = (int32_t)((int16_t)(word32 & 0xfffc));
+ PushMem(instruction, PPC_OP_MEM_RA, Gpr(GetA(word32)), ds);
+ break;
+ }
+
+ // <op> rS, rA, rB (indexed store)
+ case PPC_ID_STBCX:
+ case PPC_ID_STBCIX:
+ case PPC_ID_STBEPX:
+ case PPC_ID_STBUX:
+ case PPC_ID_STBX:
+ case PPC_ID_STDBRX:
+ case PPC_ID_STDCIX:
+ case PPC_ID_STDEPX:
+ case PPC_ID_STDUX:
+ case PPC_ID_STDX:
+ case PPC_ID_STHBRX:
+ case PPC_ID_STHCIX:
+ case PPC_ID_STHCX:
+ case PPC_ID_STHEPX:
+ case PPC_ID_STHUX:
+ case PPC_ID_STHX:
+ case PPC_ID_STSWX:
+ case PPC_ID_STWBRX:
+ case PPC_ID_STWCIX:
+ case PPC_ID_STWEPX:
+ case PPC_ID_STWUX:
+ case PPC_ID_STWX:
+ PushRS(instruction, word32);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ // <op>. rS, rA, rB (indexed store with reserve)
+ case PPC_ID_STDCX:
+ case PPC_ID_STWCX:
+ PushRS(instruction, word32);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ instruction->flags.rc = 1;
+ break;
+
+ // <op> frD, d(rA)
+ case PPC_ID_LFD:
+ case PPC_ID_LFDU:
+ case PPC_ID_LFS:
+ case PPC_ID_LFSU:
+ PushFRD(instruction, word32);
+ PushMemRA(instruction, word32);
+ break;
+
+ // <op> frD, rA, rB
+ case PPC_ID_LFDEPX:
+ case PPC_ID_LFDUX:
+ case PPC_ID_LFDX:
+ case PPC_ID_LFIWAX:
+ case PPC_ID_LFIWZX:
+ case PPC_ID_LFSUX:
+ case PPC_ID_LFSX:
+ PushFRD(instruction, word32);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ // <op> frS, d(rA)
+ case PPC_ID_STFD:
+ case PPC_ID_STFDU:
+ case PPC_ID_STFS:
+ case PPC_ID_STFSU:
+ PushFRS(instruction, word32);
+ PushMemRA(instruction, word32);
+ break;
+
+ // <op> frS, rA, rB
+ case PPC_ID_STFDEPX:
+ case PPC_ID_STFDUX:
+ case PPC_ID_STFDX:
+ case PPC_ID_STFIWX:
+ case PPC_ID_STFSUX:
+ case PPC_ID_STFSX:
+ PushFRS(instruction, word32);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ // <op> crfD, crfS
+ case PPC_ID_MCRF:
+ case PPC_ID_MCRFS:
+ PushCRFD(instruction, word32);
+ PushCRFS(instruction, word32);
+ break;
+
+ // <op> crbD, crbA
+ case PPC_ID_CRMOVE:
+ case PPC_ID_CRNOT:
+ PushCRBitD(instruction, word32);
+ PushCRBitA(instruction, word32);
+ break;
+
+ // <op> crbD, crbA, crbB
+ case PPC_ID_CRAND:
+ case PPC_ID_CRANDC:
+ case PPC_ID_CREQV:
+ case PPC_ID_CRNAND:
+ case PPC_ID_CRNOR:
+ case PPC_ID_CROR:
+ case PPC_ID_CRORC:
+ case PPC_ID_CRXOR:
+ PushCRBitD(instruction, word32);
+ PushCRBitA(instruction, word32);
+ PushCRBitB(instruction, word32);
+ break;
+
+ // <op> crbD
+ case PPC_ID_CRCLR:
+ case PPC_ID_CRSET:
+ PushCRBitD(instruction, word32);
+ break;
+
+ // <op> crfS
+ case PPC_ID_MCRXRX:
+ case PPC_ID_TCHECK:
+ PushCRFD(instruction, word32);
+ break;
+
+ // conditional branches to registers
+ case PPC_ID_BCLRx:
+ case PPC_ID_BCCTRx:
+ // not all BC<reg>x have hints, but if they don't, then those
+ // hints won't be read by anything anyways
+ FillBranchLikelyHint(instruction, word32);
+
+ PushUIMMValue(instruction, GetBO(word32));
+ PushUIMMValue(instruction, GetBI(word32));
+
+ instruction->flags.lk = word32 & 0x1;
+ break;
+
+ // <op> frD, frA, frB
+ case PPC_ID_FADDx:
+ case PPC_ID_FADDSx:
+ case PPC_ID_FCPSGNx:
+ case PPC_ID_FDIVx:
+ case PPC_ID_FDIVSx:
+ case PPC_ID_FSUBx:
+ case PPC_ID_FSUBSx:
+ PushFRD(instruction, word32);
+ PushFRA(instruction, word32);
+ PushFRB(instruction, word32);
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ // <op>[.] frD, frA, frC
+ case PPC_ID_FMULx:
+ case PPC_ID_FMULSx:
+ PushFRD(instruction, word32);
+ PushFRA(instruction, word32);
+ PushFRC(instruction, word32);
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ // <op>[.] frD, frA, frC, frB
+ case PPC_ID_FMADDx:
+ case PPC_ID_FMADDSx:
+ case PPC_ID_FMSUBx:
+ case PPC_ID_FMSUBSx:
+ case PPC_ID_FNMADDx:
+ case PPC_ID_FNMADDSx:
+ case PPC_ID_FNMSUBx:
+ case PPC_ID_FNMSUBSx:
+ case PPC_ID_FSELx:
+ PushFRD(instruction, word32);
+ PushFRA(instruction, word32);
+ PushFRC(instruction, word32);
+ PushFRB(instruction, word32);
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ // <op>[.] frD, frB
+ case PPC_ID_FABSx:
+ case PPC_ID_FCFIDx:
+ case PPC_ID_FCFIDSx:
+ case PPC_ID_FCFIDUx:
+ case PPC_ID_FCFIDUSx:
+ case PPC_ID_FCTIDx:
+ case PPC_ID_FCTIDUx:
+ case PPC_ID_FCTIDUZx:
+ case PPC_ID_FCTIDZx:
+ case PPC_ID_FCTIWx:
+ case PPC_ID_FCTIWUx:
+ case PPC_ID_FCTIWUZx:
+ case PPC_ID_FCTIWZx:
+ case PPC_ID_FMRx:
+ case PPC_ID_FNABSx:
+ case PPC_ID_FNEGx:
+ case PPC_ID_FREx:
+ case PPC_ID_FRESx:
+ case PPC_ID_FRIMx:
+ case PPC_ID_FRINx:
+ case PPC_ID_FRIPx:
+ case PPC_ID_FRIZx:
+ case PPC_ID_FRSPx:
+ case PPC_ID_FRSQRTEx:
+ case PPC_ID_FRSQRTESx:
+ case PPC_ID_FSQRTx:
+ case PPC_ID_FSQRTSx:
+ PushFRD(instruction, word32);
+ PushFRB(instruction, word32);
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+
+ case PPC_ID_FCMPO:
+ case PPC_ID_FCMPU:
+ PushCRFD(instruction, word32);
+ PushFRA(instruction, word32);
+ PushFRB(instruction, word32);
+ break;
+
+ // <op> rD, UIMM (special register)
+ case PPC_ID_MFDCR:
+ case PPC_ID_MFPMR:
+ case PPC_ID_MFSPR:
+ case PPC_ID_MFTB:
+ {
+ uint32_t special = GetSpecialRegisterCommon(word32);
+
+ PushRD(instruction, word32);
+ PushUIMMValue(instruction, special);
+ break;
+ }
+
+ // <op> UIMM, rS (special register)
+ case PPC_ID_MTDCR:
+ case PPC_ID_MTPMR:
+ case PPC_ID_MTSPR:
+ {
+ uint32_t special = GetSpecialRegisterCommon(word32);
+
+ PushUIMMValue(instruction, special);
+ PushRS(instruction, word32);
+ break;
+ }
+
+ // <op> rA, rB (cache-related)
+ case PPC_ID_DCBA:
+ case PPC_ID_DCBST:
+ case PPC_ID_DCBSTEP:
+ case PPC_ID_DCBFL:
+ case PPC_ID_DCBFLP:
+ case PPC_ID_DCBI:
+ case PPC_ID_DCBTSTT:
+ case PPC_ID_DCBTT:
+ case PPC_ID_DCBZ:
+ case PPC_ID_DCBZEP:
+ case PPC_ID_DCBZL:
+ case PPC_ID_ICBI:
+ case PPC_ID_ICBIEP:
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ // <op> CT (cache-related)
+ case PPC_ID_DCI:
+ case PPC_ID_ICI:
+ {
+ uint32_t ct = (word32 >> 21) & 0xf;
+
+ PushUIMMValue(instruction, ct);
+ break;
+ }
+
+ // <op> CT, rA, rB (cache-related)
+ case PPC_ID_ICBLC:
+ case PPC_ID_ICBLQ:
+ case PPC_ID_ICBTLS:
+ {
+ uint32_t ct = (word32 >> 21) & 0xf;
+
+ PushUIMMValue(instruction, ct);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+ }
+
+ // <op> TH, rA, rB (cache-related)
+ case PPC_ID_DCBTEP:
+ case PPC_ID_DCBTSTEP:
+ {
+ uint32_t th = (word32 >> 21) & 0x1f;
+ PushUIMMValue(instruction, th);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+ }
+
+ // <op> rA, rB, TH
+ case PPC_ID_DCBT:
+ {
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ uint32_t th = (word32 >> 21) & 0x1f;
+ if (th != 0)
+ PushUIMMValue(instruction, th);
+ break;
+ }
+
+ case PPC_ID_DCBTST:
+ {
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ uint32_t th = (word32 >> 21) & 0x1f;
+ if (th != 0)
+ PushUIMMValue(instruction, th);
+ break;
+ }
+
+ case PPC_ID_MTFSB0x:
+ case PPC_ID_MTFSB1x:
+ {
+ uint32_t bt = (word32 >> 21) & 0x1f;
+
+ PushUIMMValue(instruction, bt);
+ instruction->flags.rc = word32 & 0x1;
+ break;
+ }
+
+ case PPC_ID_TLBREHI:
+ case PPC_ID_TLBRELO:
+ // TODO: this is how capstone disassembles these
+ // instructions, but some architectures have no
+ // operands and this is just "tlbre"
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+
+ break;
+
+ case PPC_ID_TLBWEHI:
+ case PPC_ID_TLBWELO:
+ // TODO: this is how capstone disassembles these
+ // instructions, but some architectures have no
+ // operands and this is just "tlbwe"
+ PushRS(instruction, word32);
+ PushRA(instruction, word32);
+
+ break;
+
+ // one-off instructions
+ case PPC_ID_ADDICx:
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushSIMMValue(instruction, (int32_t)((int16_t)(word32 & 0xffff)));
+
+ instruction->flags.rc = (word32 >> 26) == 0x0d;
+ break;
+
+ case PPC_ID_ADDIS:
+ // different from other shifted immediates because signed imm
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushSIMMValue(instruction, (int32_t)((int16_t)(word32 & 0xffff)));
+ break;
+
+ case PPC_ID_ADDPCIS:
+ {
+ PushRD(instruction, word32);
+ uint64_t d1 = (word32 >> 16) & 0x1f;
+ uint64_t d0 = (word32 >> 6) & 0x3ff;
+ uint64_t d2 = word32 & 0x1;
+ uint64_t d = (d0 << 6) | (d1 << 1) | d2;
+ PushUIMMValue(instruction, d);
+ break;
+ }
+
+ case PPC_ID_ANDIx:
+ // different from other logical immediates because of rc bit
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, word32 & 0xffff);
+ instruction->flags.rc = 1;
+ break;
+
+ case PPC_ID_ANDIS:
+ // different from other logical shifted immediates because of rc bit
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, word32 & 0xffff);
+
+ instruction->flags.rc = 1;
+ break;
+
+ case PPC_ID_Bx:
+ {
+ instruction->flags.lk = word32 & 0x1;
+ instruction->flags.aa = (word32 & 0x2) != 0;
+
+ uint64_t li = word32 & 0x03fffffc;
+ li = (uint64_t)(int64_t)sign_extend(li, 26);
+ uint64_t target = instruction->flags.aa ? li : address + li;
+
+ PushLabel(instruction, target);
+
+ break;
+ }
+
+ case PPC_ID_CMPRB:
+ {
+ PushCRFD(instruction, word32);
+
+ uint32_t l = (word32 >> 21) & 0x1;
+ PushUIMMValue(instruction, l);
+
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+ }
+
+ case PPC_ID_DARN:
+ {
+ uint32_t l = (word32 >> 16) & 0x3;
+ PushRD(instruction, word32);
+ PushUIMMValue(instruction, l);
+ break;
+ }
+
+ case PPC_ID_DCBF:
+ case PPC_ID_DCBFEP:
+ {
+ uint32_t l = (word32 >> 21) & 0x3;
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ if (l != 0)
+ PushUIMMValue(instruction, l);
+
+ break;
+ }
+
+ case PPC_ID_EXTSWSLIx:
+ {
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ uint32_t sh5 = (word32 >> 1) & 0x1;
+ uint32_t sh0_4 = (word32 >> 11) & 0x1f;
+ PushUIMMValue(instruction, (sh5 << 5) | sh0_4);
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+ }
+
+ case PPC_ID_FTDIV:
+ PushCRFD(instruction, word32);
+ PushFRA(instruction, word32);
+ PushFRB(instruction, word32);
+ break;
+
+ case PPC_ID_FTSQRT:
+ PushCRFD(instruction, word32);
+ PushFRB(instruction, word32);
+ break;
+
+ case PPC_ID_MFBHRBE:
+ {
+ uint32_t bhrbe = (word32 >> 11) & 0x3ff;
+ PushRD(instruction, word32);
+ PushUIMMValue(instruction, bhrbe);
+ break;
+ }
+
+ case PPC_ID_MFOCRF:
+ {
+ uint32_t fxm = (word32 >> 12) & 0xff;
+
+ PushRD(instruction, word32);
+ PushUIMMValue(instruction, fxm);
+ break;
+ }
+
+
+ case PPC_ID_ICBT:
+ {
+ uint32_t ct = (word32 >> 21) & 0xf;
+
+ PushUIMMValue(instruction, ct);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+
+ break;
+ }
+
+ case PPC_ID_ISEL:
+ {
+ uint32_t bc = (word32 >> 6) & 0x1f;
+
+ PushRD(instruction, word32);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ PushUIMMValue(instruction, bc);
+ break;
+ }
+
+ case PPC_ID_LI:
+ PushRD(instruction, word32);
+ PushSIMMValue(instruction, (int32_t)((int16_t)(word32 & 0xffff)));
+ break;
+
+ case PPC_ID_LIS:
+ {
+ PushRD(instruction, word32);
+ PushSIMMValue(instruction, (int32_t)(word32 & 0xffff));
+ break;
+ }
+
+ case PPC_ID_LSWI:
+ {
+ uint32_t nb = (word32 >> 11) & 0x1f;
+
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushUIMMValue(instruction, nb);
+ break;
+ }
+
+ case PPC_ID_MBAR:
+ {
+ uint32_t mo = (word32 >> 21) & 0x1f;
+ PushUIMMValue(instruction, mo);
+ break;
+ }
+
+ case PPC_ID_MFFSx:
+ case PPC_ID_MFFSCE:
+ case PPC_ID_MFFSL:
+ PushFRD(instruction, word32);
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_MFFSCDRN:
+ case PPC_ID_MFFSCRN:
+ PushFRD(instruction, word32);
+ PushFRB(instruction, word32);
+ break;
+
+ case PPC_ID_MFFSCDRNI:
+ {
+ uint32_t drm = (word32 >> 11) & 0x7;
+ PushFRD(instruction, word32);
+ PushUIMMValue(instruction, drm);
+ break;
+ }
+
+ case PPC_ID_MFFSCRNI:
+ {
+ uint32_t rm = (word32 >> 11) & 0x3;
+ PushFRD(instruction, word32);
+ PushUIMMValue(instruction, rm);
+ break;
+ }
+
+ case PPC_ID_MFSR:
+ {
+ uint32_t sr = (word32 >> 16) & 0xf;
+
+ PushRD(instruction, word32);
+ PushUIMMValue(instruction, sr);
+ break;
+ }
+
+ case PPC_ID_MFSRIN:
+ PushRD(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+
+ case PPC_ID_MRx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_MTCRF:
+ {
+ uint32_t crm = (word32 >> 12) & 0xff;
+
+ PushUIMMValue(instruction, crm);
+ PushRS(instruction, word32);
+ break;
+ }
+
+ case PPC_ID_MTFSFx:
+ {
+ uint32_t w = (word32 >> 16) & 0x1;
+ uint32_t l = (word32 >> 25) & 0x1;
+ uint32_t flm = (word32 >> 17) & 0xff;
+
+ PushUIMMValue(instruction, flm);
+ PushFRB(instruction, word32);
+
+ if (w != 0 || l != 0)
+ {
+ PushUIMMValue(instruction, l);
+ PushUIMMValue(instruction, w);
+ }
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+ }
+
+ case PPC_ID_MTFSFIx:
+ {
+ uint32_t u = (word32 >> 12) & 0xf;
+ uint32_t w = (word32 >> 16) & 0x1;
+
+ PushCRFD(instruction, word32);
+ PushUIMMValue(instruction, u);
+ if (w != 0)
+ PushUIMMValue(instruction, w);
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+ }
+
+ case PPC_ID_MTOCRF:
+ {
+ uint32_t fxm = (word32 >> 12) & 0xff;
+
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, fxm);
+ break;
+ }
+
+ case PPC_ID_MTSR:
+ {
+ uint32_t sr = (word32 >> 16) & 0xf;
+
+ PushUIMMValue(instruction, sr);
+ PushRS(instruction, word32);
+
+ break;
+ }
+
+ case PPC_ID_MTSRIN:
+ PushRS(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ case PPC_ID_RFEBB:
+ PushUIMMValue(instruction, (word32 >> 11) & 0x1);
+ break;
+
+ case PPC_ID_RLWIMIx:
+ case PPC_ID_RLWINMx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, GetSH(word32));
+ PushUIMMValue(instruction, GetMB(word32));
+ PushUIMMValue(instruction, GetME(word32));
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_RLWNMx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushRB(instruction, word32);
+ PushUIMMValue(instruction, GetMB(word32));
+ PushUIMMValue(instruction, GetME(word32));
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_SC:
+ {
+ uint32_t lev = (word32 >> 5) & 0x7f;
+ if (lev != 0)
+ PushUIMMValue(instruction, lev);
+
+ break;
+ }
+
+ case PPC_ID_SETB:
+ PushRD(instruction, word32);
+ PushCRFS(instruction, word32);
+ break;
+
+ case PPC_ID_SLBMFEE:
+ case PPC_ID_SLBMFEV:
+ PushRD(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ case PPC_ID_SLBMTE:
+ case PPC_ID_SLBIEG:
+ PushRS(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ case PPC_ID_SRADIx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, GetSH64(word32));
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_SRAWIx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, GetSH(word32));
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ case PPC_ID_STSWI:
+ {
+ uint32_t nb = (word32 >> 11) & 0x1f;
+
+ PushRS(instruction, word32);
+ PushRA(instruction, word32);
+ PushUIMMValue(instruction, nb);
+ break;
+ }
+
+ case PPC_ID_TBEGIN:
+ {
+ uint32_t r = (word32 >> 21) & 0x1;
+
+ PushUIMMValue(instruction, r);
+ break;
+ }
+
+ case PPC_ID_TEND:
+ {
+ uint32_t a = (word32 >> 25) & 0x1;
+
+ PushUIMMValue(instruction, a);
+ break;
+ }
+
+ case PPC_ID_TLBIE:
+ PushRB(instruction, word32);
+ PushRS(instruction, word32);
+ break;
+
+ case PPC_ID_TLBIVAX:
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ case PPC_ID_TSR:
+ {
+ uint32_t l = (word32 >> 21) & 0x1;
+
+ PushUIMMValue(instruction, l);
+ break;
+ }
+
+ case PPC_ID_WAIT:
+ {
+ uint32_t wc = (word32 >> 21) & 0x3;
+
+ if (wc != 0)
+ PushUIMMValue(instruction, wc);
+
+ break;
+ }
+
+ case PPC_ID_WRTEEI:
+ {
+ uint32_t e = (word32 & 0x00008000) != 0;
+
+ PushUIMMValue(instruction, e);
+ break;
+ }
+
+ // ALTIVEC INSTRUCTIONS
+
+ // <op> vD, vA, vB, vC
+ case PPC_ID_AV_VADDECUQ:
+ case PPC_ID_AV_VADDEUQM:
+ case PPC_ID_AV_VMHADDSHS:
+ case PPC_ID_AV_VMHRADDSHS:
+ case PPC_ID_AV_VMLADDUHM:
+ case PPC_ID_AV_VSUBECUQ:
+ case PPC_ID_AV_VSUBEUQM:
+ case PPC_ID_AV_VMSUMMBM:
+ case PPC_ID_AV_VMSUMUBM:
+ case PPC_ID_AV_VMSUMSHM:
+ case PPC_ID_AV_VMSUMSHS:
+ case PPC_ID_AV_VMSUMUHM:
+ case PPC_ID_AV_VMSUMUHS:
+ case PPC_ID_AV_VPERM:
+ case PPC_ID_AV_VPERMR:
+ case PPC_ID_AV_VPERMXOR:
+ case PPC_ID_AV_VSEL:
+ PushAltivecVD(instruction, word32);
+ PushAltivecVA(instruction, word32);
+ PushAltivecVB(instruction, word32);
+ PushAltivecVC(instruction, word32);
+ break;
+
+ // <op> vD, vA, vC, vB (note swapped vC, vB)
+ case PPC_ID_AV_VMADDFP:
+ case PPC_ID_AV_VNMSUBFP:
+ PushAltivecVD(instruction, word32);
+ PushAltivecVA(instruction, word32);
+ PushAltivecVC(instruction, word32);
+ PushAltivecVB(instruction, word32);
+ break;
+
+ // <op> vD, vA, vB
+ case PPC_ID_AV_VABSDUB:
+ case PPC_ID_AV_VABSDUH:
+ case PPC_ID_AV_VABSDUW:
+ case PPC_ID_AV_VADDUQM:
+ case PPC_ID_AV_VADDCUQ:
+ case PPC_ID_AV_BCDUS:
+ case PPC_ID_AV_BCDUTRUNC:
+ case PPC_ID_AV_BCDCPSGN:
+ case PPC_ID_AV_VADDCUW:
+ case PPC_ID_AV_VADDFP:
+ case PPC_ID_AV_VADDSBS:
+ case PPC_ID_AV_VADDSHS:
+ case PPC_ID_AV_VADDSWS:
+ case PPC_ID_AV_VADDUBM:
+ case PPC_ID_AV_VADDUBS:
+ case PPC_ID_AV_VADDUDM:
+ case PPC_ID_AV_VADDUHM:
+ case PPC_ID_AV_VADDUHS:
+ case PPC_ID_AV_VADDUWM:
+ case PPC_ID_AV_VADDUWS:
+ case PPC_ID_AV_VAND:
+ case PPC_ID_AV_VANDC:
+ case PPC_ID_AV_VAVGSB:
+ case PPC_ID_AV_VAVGSH:
+ case PPC_ID_AV_VAVGSW:
+ case PPC_ID_AV_VAVGUB:
+ case PPC_ID_AV_VAVGUH:
+ case PPC_ID_AV_VAVGUW:
+ case PPC_ID_AV_VBPERMD:
+ case PPC_ID_AV_VBPERMQ:
+ case PPC_ID_AV_VCIPHER:
+ case PPC_ID_AV_VCIPHERLAST:
+ case PPC_ID_AV_VEQV:
+ case PPC_ID_AV_VMAXFP:
+ case PPC_ID_AV_VMAXSB:
+ case PPC_ID_AV_VMAXSD:
+ case PPC_ID_AV_VMAXSH:
+ case PPC_ID_AV_VMAXSW:
+ case PPC_ID_AV_VMAXUB:
+ case PPC_ID_AV_VMAXUD:
+ case PPC_ID_AV_VMAXUH:
+ case PPC_ID_AV_VMAXUW:
+ case PPC_ID_AV_VMINFP:
+ case PPC_ID_AV_VMINUB:
+ case PPC_ID_AV_VMINUD:
+ case PPC_ID_AV_VMINUH:
+ case PPC_ID_AV_VMINUW:
+ case PPC_ID_AV_VMINSB:
+ case PPC_ID_AV_VMINSD:
+ case PPC_ID_AV_VMINSH:
+ case PPC_ID_AV_VMINSW:
+ case PPC_ID_AV_VMRGEW:
+ case PPC_ID_AV_VMRGHB:
+ case PPC_ID_AV_VMRGHH:
+ case PPC_ID_AV_VMRGHW:
+ case PPC_ID_AV_VMRGLB:
+ case PPC_ID_AV_VMRGLH:
+ case PPC_ID_AV_VMRGLW:
+ case PPC_ID_AV_VMRGOW:
+ case PPC_ID_AV_VMUL10EUQ:
+ case PPC_ID_AV_VMUL10ECUQ:
+ case PPC_ID_AV_VMULESB:
+ case PPC_ID_AV_VMULESH:
+ case PPC_ID_AV_VMULESW:
+ case PPC_ID_AV_VMULEUB:
+ case PPC_ID_AV_VMULEUH:
+ case PPC_ID_AV_VMULEUW:
+ case PPC_ID_AV_VMULOSB:
+ case PPC_ID_AV_VMULOSH:
+ case PPC_ID_AV_VMULOSW:
+ case PPC_ID_AV_VMULOUB:
+ case PPC_ID_AV_VMULOUH:
+ case PPC_ID_AV_VMULOUW:
+ case PPC_ID_AV_VMULUWM:
+ case PPC_ID_AV_VNAND:
+ case PPC_ID_AV_VNCIPHER:
+ case PPC_ID_AV_VNCIPHERLAST:
+ case PPC_ID_AV_VNOR:
+ case PPC_ID_AV_VOR:
+ case PPC_ID_AV_VORC:
+ case PPC_ID_AV_VPKPX:
+ case PPC_ID_AV_VPKSDSS:
+ case PPC_ID_AV_VPKSDUS:
+ case PPC_ID_AV_VPKSHSS:
+ case PPC_ID_AV_VPKSHUS:
+ case PPC_ID_AV_VPKSWSS:
+ case PPC_ID_AV_VPKSWUS:
+ case PPC_ID_AV_VPKUDUM:
+ case PPC_ID_AV_VPKUDUS:
+ case PPC_ID_AV_VPKUHUM:
+ case PPC_ID_AV_VPKUHUS:
+ case PPC_ID_AV_VPKUWUM:
+ case PPC_ID_AV_VPKUWUS:
+ case PPC_ID_AV_VPMSUMB:
+ case PPC_ID_AV_VPMSUMD:
+ case PPC_ID_AV_VPMSUMH:
+ case PPC_ID_AV_VPMSUMW:
+ case PPC_ID_AV_VRLB:
+ case PPC_ID_AV_VRLD:
+ case PPC_ID_AV_VRLDMI:
+ case PPC_ID_AV_VRLDNM:
+ case PPC_ID_AV_VRLH:
+ case PPC_ID_AV_VRLW:
+ case PPC_ID_AV_VRLWMI:
+ case PPC_ID_AV_VRLWNM:
+ case PPC_ID_AV_VSL:
+ case PPC_ID_AV_VSLB:
+ case PPC_ID_AV_VSLD:
+ case PPC_ID_AV_VSLH:
+ case PPC_ID_AV_VSLO:
+ case PPC_ID_AV_VSLV:
+ case PPC_ID_AV_VSLW:
+ case PPC_ID_AV_VSR:
+ case PPC_ID_AV_VSRAB:
+ case PPC_ID_AV_VSRAD:
+ case PPC_ID_AV_VSRAH:
+ case PPC_ID_AV_VSRAW:
+ case PPC_ID_AV_VSRB:
+ case PPC_ID_AV_VSRD:
+ case PPC_ID_AV_VSRH:
+ case PPC_ID_AV_VSRO:
+ case PPC_ID_AV_VSRV:
+ case PPC_ID_AV_VSRW:
+ case PPC_ID_AV_VSUBCUQ:
+ case PPC_ID_AV_VSUBCUW:
+ case PPC_ID_AV_VSUBFP:
+ case PPC_ID_AV_VSUBSBS:
+ case PPC_ID_AV_VSUBSHS:
+ case PPC_ID_AV_VSUBSWS:
+ case PPC_ID_AV_VSUBUBS:
+ case PPC_ID_AV_VSUBUHS:
+ case PPC_ID_AV_VSUBUQM:
+ case PPC_ID_AV_VSUBUWS:
+ case PPC_ID_AV_VSUBUBM:
+ case PPC_ID_AV_VSUBUDM:
+ case PPC_ID_AV_VSUBUHM:
+ case PPC_ID_AV_VSUBUWM:
+ case PPC_ID_AV_VSUM2SWS:
+ case PPC_ID_AV_VSUM4SBS:
+ case PPC_ID_AV_VSUM4SHS:
+ case PPC_ID_AV_VSUM4UBS:
+ case PPC_ID_AV_VSUMSWS:
+ case PPC_ID_AV_VXOR:
+ PushAltivecVD(instruction, word32);
+ PushAltivecVA(instruction, word32);
+ PushAltivecVB(instruction, word32);
+ break;
+
+ // <op>[.] vD, vA, vB
+ case PPC_ID_AV_VCMPBFPx:
+ case PPC_ID_AV_VCMPEQFPx:
+ case PPC_ID_AV_VCMPGEFPx:
+ case PPC_ID_AV_VCMPEQUBx:
+ case PPC_ID_AV_VCMPEQUDx:
+ case PPC_ID_AV_VCMPEQUHx:
+ case PPC_ID_AV_VCMPEQUWx:
+ case PPC_ID_AV_VCMPGTFPx:
+ case PPC_ID_AV_VCMPGTSBx:
+ case PPC_ID_AV_VCMPGTSDx:
+ case PPC_ID_AV_VCMPGTSHx:
+ case PPC_ID_AV_VCMPGTSWx:
+ case PPC_ID_AV_VCMPGTUBx:
+ case PPC_ID_AV_VCMPGTUDx:
+ case PPC_ID_AV_VCMPGTUHx:
+ case PPC_ID_AV_VCMPGTUWx:
+ case PPC_ID_AV_VCMPNEBx:
+ case PPC_ID_AV_VCMPNEHx:
+ case PPC_ID_AV_VCMPNEWx:
+ case PPC_ID_AV_VCMPNEZBx:
+ case PPC_ID_AV_VCMPNEZHx:
+ case PPC_ID_AV_VCMPNEZWx:
+ PushAltivecVD(instruction, word32);
+ PushAltivecVA(instruction, word32);
+ PushAltivecVB(instruction, word32);
+
+ instruction->flags.rc = (word32 >> 10) & 0x1;
+ break;
+
+ // <op> vD, vA
+ case PPC_ID_AV_VMUL10CUQ:
+ case PPC_ID_AV_VMUL10UQ:
+ case PPC_ID_AV_VSBOX:
+ PushAltivecVD(instruction, word32);
+ PushAltivecVA(instruction, word32);
+ break;
+
+ // <op> vD, vB
+ case PPC_ID_AV_BCDCTN:
+ case PPC_ID_AV_BCDCTSQ:
+ case PPC_ID_AV_VCLZB:
+ case PPC_ID_AV_VCLZD:
+ case PPC_ID_AV_VCLZH:
+ case PPC_ID_AV_VCLZW:
+ case PPC_ID_AV_VCTZB:
+ case PPC_ID_AV_VCTZD:
+ case PPC_ID_AV_VCTZH:
+ case PPC_ID_AV_VCTZW:
+ case PPC_ID_AV_VEXPTEFP:
+ case PPC_ID_AV_VEXTSB2D:
+ case PPC_ID_AV_VEXTSB2W:
+ case PPC_ID_AV_VEXTSH2D:
+ case PPC_ID_AV_VEXTSH2W:
+ case PPC_ID_AV_VEXTSW2D:
+ case PPC_ID_AV_VGBBD:
+ case PPC_ID_AV_VLOGEFP:
+ case PPC_ID_AV_VMR:
+ case PPC_ID_AV_VNEGD:
+ case PPC_ID_AV_VNEGW:
+ case PPC_ID_AV_VNOT:
+ case PPC_ID_AV_VPOPCNTB:
+ case PPC_ID_AV_VPOPCNTD:
+ case PPC_ID_AV_VPOPCNTH:
+ case PPC_ID_AV_VPOPCNTW:
+ case PPC_ID_AV_VPRTYBD:
+ case PPC_ID_AV_VPRTYBQ:
+ case PPC_ID_AV_VPRTYBW:
+ case PPC_ID_AV_VREFP:
+ case PPC_ID_AV_VRFIM:
+ case PPC_ID_AV_VRFIN:
+ case PPC_ID_AV_VRFIP:
+ case PPC_ID_AV_VRFIZ:
+ case PPC_ID_AV_VRSQRTEFP:
+ case PPC_ID_AV_VUPKHPX:
+ case PPC_ID_AV_VUPKHSB:
+ case PPC_ID_AV_VUPKHSH:
+ case PPC_ID_AV_VUPKHSW:
+ case PPC_ID_AV_VUPKLPX:
+ case PPC_ID_AV_VUPKLSB:
+ case PPC_ID_AV_VUPKLSH:
+ case PPC_ID_AV_VUPKLSW:
+ PushAltivecVD(instruction, word32);
+ PushAltivecVB(instruction, word32);
+ break;
+
+ // <op> vD, vB, UIMM
+ case PPC_ID_AV_VCFSX:
+ case PPC_ID_AV_VCFUX:
+ case PPC_ID_AV_VCTSXS:
+ case PPC_ID_AV_VCTUXS:
+ case PPC_ID_AV_VSPLTB:
+ case PPC_ID_AV_VSPLTH:
+ case PPC_ID_AV_VSPLTW:
+ PushAltivecVD(instruction, word32);
+ PushAltivecVB(instruction, word32);
+ PushUIMMValue(instruction, (word32 >> 16) & 0x1f);
+ break;
+
+ // <op> vD, SIMM
+ case PPC_ID_AV_VSPLTISB:
+ case PPC_ID_AV_VSPLTISH:
+ case PPC_ID_AV_VSPLTISW:
+ {
+ PushAltivecVD(instruction, word32);
+
+ int32_t simm = sign_extend((word32 >> 16) & 0x1f, 5);
+ PushSIMMValue(instruction, simm);
+ break;
+ }
+
+ // <op> vD, d(rA)
+ case PPC_ID_AV_LVEBX:
+ case PPC_ID_AV_LVEHX:
+ case PPC_ID_AV_LVEWX:
+ case PPC_ID_AV_LVSL:
+ case PPC_ID_AV_LVSR:
+ case PPC_ID_AV_LVX:
+ case PPC_ID_AV_LVXL:
+ PushAltivecVD(instruction, word32);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ // <op> vS, d(rA)
+ case PPC_ID_AV_STVEBX:
+ case PPC_ID_AV_STVEHX:
+ case PPC_ID_AV_STVEWX:
+ case PPC_ID_AV_STVX:
+ case PPC_ID_AV_STVXL:
+ PushAltivecVS(instruction, word32);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ case PPC_ID_AV_DST:
+ case PPC_ID_AV_DSTST:
+ case PPC_ID_AV_DSTSTT:
+ case PPC_ID_AV_DSTT:
+ {
+ uint32_t strm = (word32 >> 21) & 0x3;
+
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+ PushUIMMValue(instruction, strm);
+ break;
+ }
+
+ case PPC_ID_AV_DSS:
+ {
+ uint32_t strm = (word32 >> 21) & 0x3;
+ PushUIMMValue(instruction, strm);
+ break;
+ }
+
+ case PPC_ID_AV_MFVSCR:
+ // mfvscr vD
+ PushAltivecVD(instruction, word32);
+ break;
+
+ case PPC_ID_AV_MTVSCR:
+ // mtvscr vB
+ PushAltivecVB(instruction, word32);
+ break;
+
+ case PPC_ID_AV_VSLDOI:
+ // vsldoi vD, vA, vB, UIMM
+ PushAltivecVD(instruction, word32);
+ PushAltivecVA(instruction, word32);
+ PushAltivecVB(instruction, word32);
+ PushUIMMValue(instruction, (word32 >> 6) & 0xf);
+ break;
+
+ // rD, rA, rB, rC (normal registers)
+ case PPC_ID_AV_MADDHD:
+ case PPC_ID_AV_MADDHDU:
+ case PPC_ID_AV_MADDLD:
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+ PushRC(instruction, word32);
+ break;
+
+ // vrD, vrA, vrB, ps
+ case PPC_ID_AV_BCDADD:
+ case PPC_ID_AV_BCDSUB:
+ case PPC_ID_AV_BCDS:
+ case PPC_ID_AV_BCDSR:
+ case PPC_ID_AV_BCDTRUNC:
+ {
+ PushAltivecVD(instruction, word32);
+ PushAltivecVA(instruction, word32);
+ PushAltivecVB(instruction, word32);
+ uint32_t ps = (word32 & 0x200) != 0;
+ PushUIMMValue(instruction, ps);
+ break;
+ }
+
+
+ // vrD, vrB, ps
+ case PPC_ID_AV_BCDCFN:
+ case PPC_ID_AV_BCDCFZ:
+ case PPC_ID_AV_BCDCTZ:
+ case PPC_ID_AV_BCDCFSQ:
+ case PPC_ID_AV_BCDSETSGN:
+ // PS isn't in all of these instructions, but it gets
+ // filtered out in subop decode
+ PushAltivecVD(instruction, word32);
+ PushAltivecVB(instruction, word32);
+ uint32_t ps = (word32 & 0x200) != 0;
+ PushUIMMValue(instruction, ps);
+ break;
+
+
+ // vrD, vrB, UIM
+ case PPC_ID_AV_VEXTRACTD:
+ case PPC_ID_AV_VEXTRACTUB:
+ case PPC_ID_AV_VEXTRACTUH:
+ case PPC_ID_AV_VEXTRACTUW:
+ case PPC_ID_AV_VINSERTB:
+ case PPC_ID_AV_VINSERTD:
+ case PPC_ID_AV_VINSERTH:
+ case PPC_ID_AV_VINSERTW:
+ PushAltivecVD(instruction, word32);
+ PushAltivecVB(instruction, word32);
+ PushUIMMValue(instruction, (word32 >> 16) & 0xf);
+ break;
+
+ // <op> rD, rA, vB
+ case PPC_ID_AV_VEXTUBLX:
+ case PPC_ID_AV_VEXTUHLX:
+ case PPC_ID_AV_VEXTUWLX:
+ case PPC_ID_AV_VEXTUBRX:
+ case PPC_ID_AV_VEXTUHRX:
+ case PPC_ID_AV_VEXTUWRX:
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushAltivecVB(instruction, word32);
+ break;
+
+ // <op> vD, vA, ST, SIX
+ case PPC_ID_AV_VSHASIGMAD:
+ case PPC_ID_AV_VSHASIGMAW:
+ PushAltivecVD(instruction, word32);
+ PushAltivecVA(instruction, word32);
+ PushUIMMValue(instruction, (word32 >> 15) & 0x1);
+ PushUIMMValue(instruction, (word32 >> 11) & 0xf);
+ break;
+
+ // <op> rD, vB
+ case PPC_ID_AV_VCLZLSBB:
+ case PPC_ID_AV_VCTZLSBB:
+ PushRD(instruction, word32);
+ PushAltivecVB(instruction, word32);
+ break;
+
+ // VSX INSTRUCTIONS
+
+ // <op> vrD, vrA, vrB <full width>
+ case PPC_ID_VSX_XVADDDP:
+ case PPC_ID_VSX_XVADDSP:
+ case PPC_ID_VSX_XVCPSGNDP:
+ case PPC_ID_VSX_XVCPSGNSP:
+ case PPC_ID_VSX_XVDIVDP:
+ case PPC_ID_VSX_XVDIVSP:
+ case PPC_ID_VSX_XVIEXPDP:
+ case PPC_ID_VSX_XVIEXPSP:
+ case PPC_ID_VSX_XVMADDADP:
+ case PPC_ID_VSX_XVMADDASP:
+ case PPC_ID_VSX_XVMADDMDP:
+ case PPC_ID_VSX_XVMADDMSP:
+ case PPC_ID_VSX_XVMAXDP:
+ case PPC_ID_VSX_XVMAXSP:
+ case PPC_ID_VSX_XVMINDP:
+ case PPC_ID_VSX_XVMINSP:
+ case PPC_ID_VSX_XVMSUBADP:
+ case PPC_ID_VSX_XVMSUBMDP:
+ case PPC_ID_VSX_XVMSUBASP:
+ case PPC_ID_VSX_XVMSUBMSP:
+ case PPC_ID_VSX_XVMULDP:
+ case PPC_ID_VSX_XVMULSP:
+ case PPC_ID_VSX_XVNMADDADP:
+ case PPC_ID_VSX_XVNMADDASP:
+ case PPC_ID_VSX_XVNMADDMDP:
+ case PPC_ID_VSX_XVNMADDMSP:
+ case PPC_ID_VSX_XVNMSUBADP:
+ case PPC_ID_VSX_XVNMSUBASP:
+ case PPC_ID_VSX_XVNMSUBMDP:
+ case PPC_ID_VSX_XVNMSUBMSP:
+ case PPC_ID_VSX_XVSUBDP:
+ case PPC_ID_VSX_XVSUBSP:
+ case PPC_ID_VSX_XXLAND:
+ case PPC_ID_VSX_XXLANDC:
+ case PPC_ID_VSX_XXLEQV:
+ case PPC_ID_VSX_XXLOR:
+ case PPC_ID_VSX_XXLNAND:
+ case PPC_ID_VSX_XXLNOR:
+ case PPC_ID_VSX_XXLORC:
+ case PPC_ID_VSX_XXLXOR:
+ case PPC_ID_VSX_XXMRGHD:
+ case PPC_ID_VSX_XXMRGHW:
+ case PPC_ID_VSX_XXMRGLD:
+ case PPC_ID_VSX_XXMRGLW:
+ case PPC_ID_VSX_XXPERM:
+ case PPC_ID_VSX_XXPERMR:
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxA(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxB(instruction, word32, VSX_WIDTH_FULL);
+ break;
+
+ // <op>[.] vrD, rA, vrB <full>
+ case PPC_ID_VSX_XVCMPEQDPx:
+ case PPC_ID_VSX_XVCMPEQSPx:
+ case PPC_ID_VSX_XVCMPGEDPx:
+ case PPC_ID_VSX_XVCMPGESPx:
+ case PPC_ID_VSX_XVCMPGTDPx:
+ case PPC_ID_VSX_XVCMPGTSPx:
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxA(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxB(instruction, word32, VSX_WIDTH_FULL);
+ instruction->flags.rc = (word32 & 0x400) != 0;
+ break;
+
+ // <op> vrD, vrA, vrB <dword0>
+ case PPC_ID_VSX_XSADDSP:
+ case PPC_ID_VSX_XSADDDP:
+ case PPC_ID_VSX_XSCMPEQDP:
+ case PPC_ID_VSX_XSCMPGEDP:
+ case PPC_ID_VSX_XSCMPGTDP:
+ case PPC_ID_VSX_XSCPSGNDP:
+ case PPC_ID_VSX_XSDIVDP:
+ case PPC_ID_VSX_XSDIVSP:
+ case PPC_ID_VSX_XSMADDADP:
+ case PPC_ID_VSX_XSMADDMDP:
+ case PPC_ID_VSX_XSMADDASP:
+ case PPC_ID_VSX_XSMADDMSP:
+ case PPC_ID_VSX_XSMAXCDP:
+ case PPC_ID_VSX_XSMAXDP:
+ case PPC_ID_VSX_XSMAXJDP:
+ case PPC_ID_VSX_XSMINCDP:
+ case PPC_ID_VSX_XSMINDP:
+ case PPC_ID_VSX_XSMINJDP:
+ case PPC_ID_VSX_XSMSUBADP:
+ case PPC_ID_VSX_XSMSUBASP:
+ case PPC_ID_VSX_XSMSUBMDP:
+ case PPC_ID_VSX_XSMSUBMSP:
+ case PPC_ID_VSX_XSMULDP:
+ case PPC_ID_VSX_XSMULSP:
+ case PPC_ID_VSX_XSNMADDADP:
+ case PPC_ID_VSX_XSNMADDASP:
+ case PPC_ID_VSX_XSNMADDMDP:
+ case PPC_ID_VSX_XSNMADDMSP:
+ case PPC_ID_VSX_XSNMSUBADP:
+ case PPC_ID_VSX_XSNMSUBASP:
+ case PPC_ID_VSX_XSNMSUBMDP:
+ case PPC_ID_VSX_XSNMSUBMSP:
+ case PPC_ID_VSX_XSSUBDP:
+ case PPC_ID_VSX_XSSUBSP:
+ PushVsxD(instruction, word32, VSX_WIDTH_DWORD0);
+ PushVsxA(instruction, word32, VSX_WIDTH_DWORD0);
+ PushVsxB(instruction, word32, VSX_WIDTH_DWORD0);
+ break;
+
+ // <op> vrD, vrB
+ case PPC_ID_VSX_XVABSDP:
+ case PPC_ID_VSX_XVABSSP:
+ case PPC_ID_VSX_XVCVDPSP:
+ case PPC_ID_VSX_XVCVDPSXDS:
+ case PPC_ID_VSX_XVCVDPSXWS:
+ case PPC_ID_VSX_XVCVDPUXDS:
+ case PPC_ID_VSX_XVCVDPUXWS:
+ case PPC_ID_VSX_XVCVSPDP:
+ case PPC_ID_VSX_XVCVSPSXDS:
+ case PPC_ID_VSX_XVCVSPSXWS:
+ case PPC_ID_VSX_XVCVSPUXDS:
+ case PPC_ID_VSX_XVCVSPUXWS:
+ case PPC_ID_VSX_XVCVSXDDP:
+ case PPC_ID_VSX_XVCVSXDSP:
+ case PPC_ID_VSX_XVCVSXWDP:
+ case PPC_ID_VSX_XVCVSXWSP:
+ case PPC_ID_VSX_XVCVUXDDP:
+ case PPC_ID_VSX_XVCVUXDSP:
+ case PPC_ID_VSX_XVCVUXWDP:
+ case PPC_ID_VSX_XVCVUXWSP:
+ case PPC_ID_VSX_XVNABSDP:
+ case PPC_ID_VSX_XVNABSSP:
+ case PPC_ID_VSX_XVNEGDP:
+ case PPC_ID_VSX_XVNEGSP:
+ case PPC_ID_VSX_XVRDPI:
+ case PPC_ID_VSX_XVRDPIC:
+ case PPC_ID_VSX_XVRDPIM:
+ case PPC_ID_VSX_XVRDPIP:
+ case PPC_ID_VSX_XVRDPIZ:
+ case PPC_ID_VSX_XVREDP:
+ case PPC_ID_VSX_XVRESP:
+ case PPC_ID_VSX_XVRSPI:
+ case PPC_ID_VSX_XVRSPIC:
+ case PPC_ID_VSX_XVRSPIM:
+ case PPC_ID_VSX_XVRSPIP:
+ case PPC_ID_VSX_XVRSPIZ:
+ case PPC_ID_VSX_XVRSQRTEDP:
+ case PPC_ID_VSX_XVRSQRTESP:
+ case PPC_ID_VSX_XVSQRTSP:
+ case PPC_ID_VSX_XVSQRTDP:
+ case PPC_ID_VSX_XVMOVDP:
+ case PPC_ID_VSX_XVMOVSP:
+ case PPC_ID_VSX_XVXEXPDP:
+ case PPC_ID_VSX_XVXEXPSP:
+ case PPC_ID_VSX_XVXSIGDP:
+ case PPC_ID_VSX_XVXSIGSP:
+ case PPC_ID_VSX_XXBRD:
+ case PPC_ID_VSX_XXBRH:
+ case PPC_ID_VSX_XXBRQ:
+ case PPC_ID_VSX_XXBRW:
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxB(instruction, word32, VSX_WIDTH_FULL);
+ break;
+
+ // <op> vrD, vrB
+ case PPC_ID_VSX_XSABSDP:
+ case PPC_ID_VSX_XSCVDPHP:
+ case PPC_ID_VSX_XSCVDPSXDS:
+ case PPC_ID_VSX_XSCVDPSP:
+ case PPC_ID_VSX_XSCVDPSPN:
+ case PPC_ID_VSX_XSCVDPSXWS:
+ case PPC_ID_VSX_XSCVDPUXDS:
+ case PPC_ID_VSX_XSCVDPUXWS:
+ case PPC_ID_VSX_XSCVSPDP:
+ case PPC_ID_VSX_XSCVHPDP:
+ case PPC_ID_VSX_XSCVSPDPN:
+ case PPC_ID_VSX_XSCVSXDDP:
+ case PPC_ID_VSX_XSCVSXDSP:
+ case PPC_ID_VSX_XSCVUXDDP:
+ case PPC_ID_VSX_XSCVUXDSP:
+ case PPC_ID_VSX_XSNABSDP:
+ case PPC_ID_VSX_XSNEGDP:
+ case PPC_ID_VSX_XSRDPI:
+ case PPC_ID_VSX_XSRDPIC:
+ case PPC_ID_VSX_XSRDPIM:
+ case PPC_ID_VSX_XSRDPIP:
+ case PPC_ID_VSX_XSRDPIZ:
+ case PPC_ID_VSX_XSREDP:
+ case PPC_ID_VSX_XSRESP:
+ case PPC_ID_VSX_XSRSP:
+ case PPC_ID_VSX_XSRSQRTESP:
+ case PPC_ID_VSX_XSRSQRTEDP:
+ case PPC_ID_VSX_XSSQRTDP:
+ case PPC_ID_VSX_XSSQRTSP:
+ case PPC_ID_VSX_XVCVHPSP:
+ case PPC_ID_VSX_XVCVSPHP:
+ PushVsxD(instruction, word32, VSX_WIDTH_DWORD0);
+ PushVsxB(instruction, word32, VSX_WIDTH_DWORD0);
+ break;
+
+ // <op> vrD, vrA, vrB, <UIMM>
+ case PPC_ID_VSX_XXPERMDI:
+ case PPC_ID_VSX_XXSLDWI:
+ {
+ uint32_t uimm = (word32 >> 8) & 0x3;
+
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxA(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxB(instruction, word32, VSX_WIDTH_FULL);
+ PushUIMMValue(instruction, uimm);
+ break;
+ }
+
+ // <op> vrD, rA, rB
+ case PPC_ID_VSX_MTVSRDD:
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ // <op> vrD, rA, rB (load indexed)
+ case PPC_ID_VSX_LXVB16X:
+ case PPC_ID_VSX_LXVD2X:
+ case PPC_ID_VSX_LXVDSX:
+ case PPC_ID_VSX_LXVH8X:
+ case PPC_ID_VSX_LXVL:
+ case PPC_ID_VSX_LXVLL:
+ case PPC_ID_VSX_LXVW4X:
+ case PPC_ID_VSX_LXVWSX:
+ case PPC_ID_VSX_LXVX:
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ case PPC_ID_VSX_LXSDX:
+ case PPC_ID_VSX_LXSIBZX:
+ case PPC_ID_VSX_LXSIHZX:
+ case PPC_ID_VSX_LXSIWAX:
+ case PPC_ID_VSX_LXSIWZX:
+ case PPC_ID_VSX_LXSSPX:
+ PushVsxD(instruction, word32, VSX_WIDTH_DWORD0);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ // <op> vrS, rA, rB (store indexed)
+ case PPC_ID_VSX_STXVB16X:
+ case PPC_ID_VSX_STXVD2X:
+ case PPC_ID_VSX_STXVH8X:
+ case PPC_ID_VSX_STXVL:
+ case PPC_ID_VSX_STXVLL:
+ case PPC_ID_VSX_STXVW4X:
+ case PPC_ID_VSX_STXVX:
+ PushVsxS(instruction, word32, VSX_WIDTH_FULL);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ case PPC_ID_VSX_STXSDX:
+ case PPC_ID_VSX_STXSIBX:
+ case PPC_ID_VSX_STXSIHX:
+ case PPC_ID_VSX_STXSIWX:
+ case PPC_ID_VSX_STXSSPX:
+ PushVsxS(instruction, word32, VSX_WIDTH_DWORD0);
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ // <op> crfD, vrA, vrB <dword0>
+ case PPC_ID_VSX_XSCMPEXPDP:
+ case PPC_ID_VSX_XSCMPODP:
+ case PPC_ID_VSX_XSCMPUDP:
+ case PPC_ID_VSX_XSTDIVDP:
+ PushCRFD(instruction, word32);
+ PushVsxA(instruction, word32, VSX_WIDTH_DWORD0);
+ PushVsxB(instruction, word32, VSX_WIDTH_DWORD0);
+ break;
+
+ // <op> crfD, vrA, vrB <full>
+ case PPC_ID_VSX_XVTDIVDP:
+ case PPC_ID_VSX_XVTDIVSP:
+ PushCRFD(instruction, word32);
+ PushVsxA(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxB(instruction, word32, VSX_WIDTH_FULL);
+ break;
+
+ // <op> crfD, vrB
+ case PPC_ID_VSX_XVTSQRTSP:
+ case PPC_ID_VSX_XVTSQRTDP:
+ PushCRFD(instruction, word32);
+ PushVsxB(instruction, word32, VSX_WIDTH_FULL);
+ break;
+
+ case PPC_ID_VSX_XSTSQRTDP:
+ PushCRFD(instruction, word32);
+ PushVsxB(instruction, word32, VSX_WIDTH_DWORD0);
+ break;
+
+ // <op> vrD, rA
+ case PPC_ID_VSX_MTVSRWS:
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushRA(instruction, word32);
+ break;
+
+ case PPC_ID_VSX_MTVSRD:
+ case PPC_ID_VSX_MTVSRWA:
+ case PPC_ID_VSX_MTVSRWZ:
+ PushVsxD(instruction, word32, VSX_WIDTH_DWORD0);
+ PushRA(instruction, word32);
+ break;
+
+ // <op> rA, vrS
+ case PPC_ID_VSX_MFVSRLD:
+ PushRA(instruction, word32);
+ PushVsxS(instruction, word32, VSX_WIDTH_FULL);
+ break;
+
+ case PPC_ID_VSX_MFFPRD:
+ case PPC_ID_VSX_MFVSRWZ:
+ case PPC_ID_VSX_MFVSRD:
+ PushRA(instruction, word32);
+ PushVsxS(instruction, word32, VSX_WIDTH_DWORD0);
+ break;
+
+ // <op> vrD, vrB, UIM
+ case PPC_ID_VSX_XXINSERTW:
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxB(instruction, word32, VSX_WIDTH_FULL);
+ PushUIMMValue(instruction, (word32 >> 16) & 0xf);
+ break;
+
+ case PPC_ID_VSX_XXEXTRACTUW:
+ PushVsxD(instruction, word32, VSX_WIDTH_DWORD0);
+ PushVsxB(instruction, word32, VSX_WIDTH_DWORD0);
+ PushUIMMValue(instruction, (word32 >> 16) & 0xf);
+ break;
+
+ case PPC_ID_VSX_LXSD:
+ case PPC_ID_VSX_LXSSP:
+ {
+ PushVsxHiD(instruction, word32);
+
+ int32_t ds = (int32_t)((int16_t)(word32 & 0xfffc));
+ PushMem(instruction, PPC_OP_MEM_RA, Gpr(GetA(word32)), ds);
+ break;
+ }
+
+ case PPC_ID_VSX_LXV:
+ {
+ uint32_t dx = (word32 >> 3) & 0x1;
+ uint32_t d = GetD(word32);
+ uint32_t vsxd = (dx << 5) | d;
+
+ PushRegister(instruction, PPC_OP_REG_VSX_RD, VsxVr(vsxd));
+
+ uint32_t dq = (int32_t)((int16_t)(word32 & 0xfff0));
+ PushMem(instruction, PPC_OP_MEM_RA, Gpr(GetA(word32)), dq);
+
+ break;
+ }
+
+ case PPC_ID_VSX_STXV:
+ {
+ uint32_t sx = (word32 >> 3) & 0x1;
+ uint32_t s = GetS(word32);
+ uint32_t vsxs = (sx << 5) | s;
+
+ PushRegister(instruction, PPC_OP_REG_VSX_RS, VsxVr(vsxs));
+
+ int32_t dq = (int32_t)((int16_t)(word32 & 0xfff0));
+ PushMem(instruction, PPC_OP_MEM_RA, Gpr(GetA(word32)), dq);
+
+ break;
+ }
+
+ case PPC_ID_VSX_STXSD:
+ case PPC_ID_VSX_STXSSP:
+ {
+ PushVsxHiS(instruction, word32);
+
+ int32_t ds = (int32_t)((int16_t)(word32 & 0xfffc));
+ PushMem(instruction, PPC_OP_MEM_RA, Gpr(GetA(word32)), ds);
+ break;
+ }
+
+ // <op>[o] vrdHi, vraHi, vrbHi
+ case PPC_ID_VSX_XSADDQPx:
+ case PPC_ID_VSX_XSCPSGNQP:
+ case PPC_ID_VSX_XSDIVQPx:
+ case PPC_ID_VSX_XSIEXPQP:
+ case PPC_ID_VSX_XSMADDQPx:
+ case PPC_ID_VSX_XSMSUBQPx:
+ case PPC_ID_VSX_XSMULQPx:
+ case PPC_ID_VSX_XSNMADDQPx:
+ case PPC_ID_VSX_XSNMSUBQPx:
+ case PPC_ID_VSX_XSSUBQPx:
+ {
+ PushVsxHiD(instruction, word32);
+ PushVsxHiA(instruction, word32);
+ PushVsxHiB(instruction, word32);
+
+ instruction->flags.round2odd = word32 & 0x1;
+ break;
+ }
+
+ case PPC_ID_VSX_XSABSQP:
+ case PPC_ID_VSX_XSCVQPUWZ:
+ case PPC_ID_VSX_XSCVUDQP:
+ case PPC_ID_VSX_XSNABSQP:
+ case PPC_ID_VSX_XSCVDPQP:
+ case PPC_ID_VSX_XSCVQPDPx:
+ case PPC_ID_VSX_XSCVQPSDZ:
+ case PPC_ID_VSX_XSCVQPSWZ:
+ case PPC_ID_VSX_XSCVQPUDZ:
+ case PPC_ID_VSX_XSCVSDQP:
+ case PPC_ID_VSX_XSNEGQP:
+ case PPC_ID_VSX_XSSQRTQPx:
+ case PPC_ID_VSX_XSXEXPQP:
+ case PPC_ID_VSX_XSXSIGQP:
+ {
+ PushVsxHiD(instruction, word32);
+ PushVsxHiB(instruction, word32);
+
+ instruction->flags.round2odd = word32 & 0x1;
+ break;
+ }
+
+ case PPC_ID_VSX_XSCMPEXPQP:
+ case PPC_ID_VSX_XSCMPOQP:
+ case PPC_ID_VSX_XSCMPUQP:
+ PushCRFD(instruction, word32);
+ PushVsxHiA(instruction, word32);
+ PushVsxHiB(instruction, word32);
+
+ break;
+
+ case PPC_ID_VSX_XSTSTDCQP:
+ {
+ uint32_t dcmx = (word32 >> 16) & 0x7f;
+ PushCRFD(instruction, word32);
+ PushVsxHiB(instruction, word32);
+ PushUIMMValue(instruction, dcmx);
+ break;
+ }
+
+ // one-off VSX instructions
+ case PPC_ID_VSX_XSIEXPDP:
+ {
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+ }
+
+ case PPC_ID_VSX_XSRQPIx:
+ case PPC_ID_VSX_XSRQPXP:
+ {
+ uint32_t r = (word32 >> 16) & 0x1;
+ PushUIMMValue(instruction, r);
+ PushVsxHiD(instruction, word32);
+ PushVsxHiB(instruction, word32);
+
+ uint32_t rmc = (word32 >> 9) & 0x3;
+ PushUIMMValue(instruction, rmc);
+
+ instruction->flags.inexact = word32 & 0x1;
+ break;
+ }
+
+ case PPC_ID_VSX_XSTSTDCDP:
+ case PPC_ID_VSX_XSTSTDCSP:
+ {
+ uint32_t dcmx = (word32 >> 16) & 0x7f;
+ PushCRFD(instruction, word32);
+ PushVsxB(instruction, word32, VSX_WIDTH_DWORD0);
+ PushUIMMValue(instruction, dcmx);
+ break;
+ }
+
+ case PPC_ID_VSX_XSXEXPDP:
+ case PPC_ID_VSX_XSXSIGDP:
+ PushRD(instruction, word32);
+ PushVsxB(instruction, word32, VSX_WIDTH_DWORD0);
+ break;
+
+ case PPC_ID_VSX_XVTSTDCDP:
+ case PPC_ID_VSX_XVTSTDCSP:
+ {
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxB(instruction, word32, VSX_WIDTH_FULL);
+ uint32_t dm = (word32 >> 2) & 0x1;
+ uint32_t dc = (word32 >> 6) & 0x1;
+ uint32_t dx = (word32 >> 16) & 0x1f;
+ uint32_t dcmx = (dc << 6) | (dm << 5) | dx;
+ PushUIMMValue(instruction, dcmx);
+ break;
+ }
+
+
+ case PPC_ID_VSX_XXSPLTD:
+ {
+ uint32_t uimm = (word32 >> 8) & 0x3;
+
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxA(instruction, word32, VSX_WIDTH_FULL);
+
+ if (uimm == 3)
+ PushUIMMValue(instruction, 1);
+ else
+ PushUIMMValue(instruction, 0);
+
+ break;
+ }
+
+ case PPC_ID_VSX_XXSPLTIB:
+ {
+ uint32_t uimm8 = (word32 >> 11) & 0xff;
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushUIMMValue(instruction, uimm8);
+ break;
+ }
+
+ case PPC_ID_VSX_XXSPLTW:
+ {
+ uint32_t um = (word32 >> 16) & 0x3;
+
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxB(instruction, word32, VSX_WIDTH_FULL);
+ PushUIMMValue(instruction, um);
+ break;
+ }
+
+ case PPC_ID_VSX_XXSWAPD:
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxA(instruction, word32, VSX_WIDTH_FULL);
+ break;
+
+ case PPC_ID_VSX_XXSEL:
+ PushVsxD(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxA(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxB(instruction, word32, VSX_WIDTH_FULL);
+ PushVsxC(instruction, word32, VSX_WIDTH_FULL);
+ break;
+
+ // SPE INSTRUCTIONS
+
+ // SPE rD, rA, rB
+ case PPC_ID_SPE_BRINC:
+ case PPC_ID_SPE_EFDADD:
+ case PPC_ID_SPE_EFDDIV:
+ case PPC_ID_SPE_EFDMUL:
+ case PPC_ID_SPE_EFDSUB:
+ case PPC_ID_SPE_EFSADD:
+ case PPC_ID_SPE_EFSDIV:
+ case PPC_ID_SPE_EFSMUL:
+ case PPC_ID_SPE_EFSSUB:
+ case PPC_ID_SPE_EVADDW:
+ case PPC_ID_SPE_EVAND:
+ case PPC_ID_SPE_EVANDC:
+ case PPC_ID_SPE_EVDIVWS:
+ case PPC_ID_SPE_EVDIVWU:
+ case PPC_ID_SPE_EVEQV:
+ case PPC_ID_SPE_EVFSADD:
+ case PPC_ID_SPE_EVFSDIV:
+ case PPC_ID_SPE_EVFSMUL:
+ case PPC_ID_SPE_EVFSSUB:
+ case PPC_ID_SPE_EVLDDX:
+ case PPC_ID_SPE_EVLDHX:
+ case PPC_ID_SPE_EVLDWX:
+ case PPC_ID_SPE_EVLHHESPLATX:
+ case PPC_ID_SPE_EVLHHOSSPLATX:
+ case PPC_ID_SPE_EVLHHOUSPLATX:
+ case PPC_ID_SPE_EVLWHEX:
+ case PPC_ID_SPE_EVLWHOSX:
+ case PPC_ID_SPE_EVLWHOUX:
+ case PPC_ID_SPE_EVLWHSPLATX:
+ case PPC_ID_SPE_EVLWWSPLATX:
+ case PPC_ID_SPE_EVMERGEHI:
+ case PPC_ID_SPE_EVMERGEHILO:
+ case PPC_ID_SPE_EVMERGELO:
+ case PPC_ID_SPE_EVMERGELOHI:
+ case PPC_ID_SPE_EVMHEGSMFAA:
+ case PPC_ID_SPE_EVMHEGSMFAN:
+ case PPC_ID_SPE_EVMHEGSMIAA:
+ case PPC_ID_SPE_EVMHEGSMIAN:
+ case PPC_ID_SPE_EVMHEGUMIAA:
+ case PPC_ID_SPE_EVMHEGUMIAN:
+ case PPC_ID_SPE_EVMHESMF:
+ case PPC_ID_SPE_EVMHESMFA:
+ case PPC_ID_SPE_EVMHESMFAAW:
+ case PPC_ID_SPE_EVMHESMFANW:
+ case PPC_ID_SPE_EVMHESMI:
+ case PPC_ID_SPE_EVMHESMIA:
+ case PPC_ID_SPE_EVMHESMIAAW:
+ case PPC_ID_SPE_EVMHESMIANW:
+ case PPC_ID_SPE_EVMHESSF:
+ case PPC_ID_SPE_EVMHESSFA:
+ case PPC_ID_SPE_EVMHESSFAAW:
+ case PPC_ID_SPE_EVMHESSFANW:
+ case PPC_ID_SPE_EVMHESSIAAW:
+ case PPC_ID_SPE_EVMHESSIANW:
+ case PPC_ID_SPE_EVMHEUMI:
+ case PPC_ID_SPE_EVMHEUMIA:
+ case PPC_ID_SPE_EVMHEUMIAAW:
+ case PPC_ID_SPE_EVMHEUMIANW:
+ case PPC_ID_SPE_EVMHEUSIAAW:
+ case PPC_ID_SPE_EVMHEUSIANW:
+ case PPC_ID_SPE_EVMHOGSMFAA:
+ case PPC_ID_SPE_EVMHOGSMFAN:
+ case PPC_ID_SPE_EVMHOGSMIAA:
+ case PPC_ID_SPE_EVMHOGSMIAN:
+ case PPC_ID_SPE_EVMHOGUMIAA:
+ case PPC_ID_SPE_EVMHOGUMIAN:
+ case PPC_ID_SPE_EVMHOSMF:
+ case PPC_ID_SPE_EVMHOSMFA:
+ case PPC_ID_SPE_EVMHOSMFAAW:
+ case PPC_ID_SPE_EVMHOSMFANW:
+ case PPC_ID_SPE_EVMHOSMI:
+ case PPC_ID_SPE_EVMHOSMIA:
+ case PPC_ID_SPE_EVMHOSMIAAW:
+ case PPC_ID_SPE_EVMHOSMIANW:
+ case PPC_ID_SPE_EVMHOSSF:
+ case PPC_ID_SPE_EVMHOSSFA:
+ case PPC_ID_SPE_EVMHOSSFAAW:
+ case PPC_ID_SPE_EVMHOSSFANW:
+ case PPC_ID_SPE_EVMHOSSIAAW:
+ case PPC_ID_SPE_EVMHOSSIANW:
+ case PPC_ID_SPE_EVMHOUMI:
+ case PPC_ID_SPE_EVMHOUMIA:
+ case PPC_ID_SPE_EVMHOUMIAAW:
+ case PPC_ID_SPE_EVMHOUMIANW:
+ case PPC_ID_SPE_EVMHOUSIAAW:
+ case PPC_ID_SPE_EVMHOUSIANW:
+ case PPC_ID_SPE_EVMWHSMF:
+ case PPC_ID_SPE_EVMWHSMFA:
+ case PPC_ID_SPE_EVMWHSMI:
+ case PPC_ID_SPE_EVMWHSMIA:
+ case PPC_ID_SPE_EVMWHSSF:
+ case PPC_ID_SPE_EVMWHSSFA:
+ case PPC_ID_SPE_EVMWLSMIAAW:
+ case PPC_ID_SPE_EVMWLSMIANW:
+ case PPC_ID_SPE_EVMWLSSIAAW:
+ case PPC_ID_SPE_EVMWLSSIANW:
+ case PPC_ID_SPE_EVMWHUMI:
+ case PPC_ID_SPE_EVMWHUMIA:
+ case PPC_ID_SPE_EVMWHUSIAAW:
+ case PPC_ID_SPE_EVMWHUSIANW:
+ case PPC_ID_SPE_EVMWLUMI:
+ case PPC_ID_SPE_EVMWLUMIA:
+ case PPC_ID_SPE_EVMWLUMIAAW:
+ case PPC_ID_SPE_EVMWLUMIANW:
+ case PPC_ID_SPE_EVMWLUSIAAW:
+ case PPC_ID_SPE_EVMWLUSIANW:
+ case PPC_ID_SPE_EVMWSMF:
+ case PPC_ID_SPE_EVMWSMFA:
+ case PPC_ID_SPE_EVMWSMFAA:
+ case PPC_ID_SPE_EVMWSMFAN:
+ case PPC_ID_SPE_EVMWSMI:
+ case PPC_ID_SPE_EVMWSMIA:
+ case PPC_ID_SPE_EVMWSMIAA:
+ case PPC_ID_SPE_EVMWSMIAN:
+ case PPC_ID_SPE_EVMWSSF:
+ case PPC_ID_SPE_EVMWSSFA:
+ case PPC_ID_SPE_EVMWSSFAA:
+ case PPC_ID_SPE_EVMWSSFAN:
+ case PPC_ID_SPE_EVMWUMI:
+ case PPC_ID_SPE_EVMWUMIA:
+ case PPC_ID_SPE_EVMWUMIAA:
+ case PPC_ID_SPE_EVMWUMIAN:
+ case PPC_ID_SPE_EVNAND:
+ case PPC_ID_SPE_EVNOR:
+ case PPC_ID_SPE_EVOR:
+ case PPC_ID_SPE_EVORC:
+ case PPC_ID_SPE_EVRLW:
+ case PPC_ID_SPE_EVSLW:
+ case PPC_ID_SPE_EVSRWS:
+ case PPC_ID_SPE_EVSRWU:
+ case PPC_ID_SPE_EVSUBFW:
+ case PPC_ID_SPE_EVXOR:
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ // rD, rA, ///
+ case PPC_ID_SPE_EFDABS:
+ case PPC_ID_SPE_EFDNABS:
+ case PPC_ID_SPE_EFDNEG:
+ case PPC_ID_SPE_EFSABS:
+ case PPC_ID_SPE_EFSNABS:
+ case PPC_ID_SPE_EFSNEG:
+ case PPC_ID_SPE_EVABS:
+ case PPC_ID_SPE_EVADDSMIAAW:
+ case PPC_ID_SPE_EVADDSSIAAW:
+ case PPC_ID_SPE_EVADDUMIAAW:
+ case PPC_ID_SPE_EVADDUSIAAW:
+ case PPC_ID_SPE_EVCNTLSW:
+ case PPC_ID_SPE_EVCNTLZW:
+ case PPC_ID_SPE_EVEXTSB:
+ case PPC_ID_SPE_EVEXTSH:
+ case PPC_ID_SPE_EVFSABS:
+ case PPC_ID_SPE_EVFSNABS:
+ case PPC_ID_SPE_EVFSNEG:
+ case PPC_ID_SPE_EVMRA:
+ case PPC_ID_SPE_EVNEG:
+ case PPC_ID_SPE_EVSUBFSMIAAW:
+ case PPC_ID_SPE_EVSUBFSSIAAW:
+ case PPC_ID_SPE_EVSUBFUMIAAW:
+ case PPC_ID_SPE_EVSUBFUSIAAW:
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ break;
+
+ // rD, ///, rB
+ case PPC_ID_SPE_EFDCFS:
+ case PPC_ID_SPE_EFDCFSF:
+ case PPC_ID_SPE_EFDCFSI:
+ case PPC_ID_SPE_EFDCFSID:
+ case PPC_ID_SPE_EFDCFUF:
+ case PPC_ID_SPE_EFDCFUI:
+ case PPC_ID_SPE_EFDCFUID:
+ case PPC_ID_SPE_EFDCTSF:
+ case PPC_ID_SPE_EFDCTSI:
+ case PPC_ID_SPE_EFDCTSIDZ:
+ case PPC_ID_SPE_EFDCTSIZ:
+ case PPC_ID_SPE_EFDCTUF:
+ case PPC_ID_SPE_EFDCTUI:
+ case PPC_ID_SPE_EFDCTUIDZ:
+ case PPC_ID_SPE_EFDCTUIZ:
+ case PPC_ID_SPE_EFSCFD:
+ case PPC_ID_SPE_EFSCFSF:
+ case PPC_ID_SPE_EFSCFSI:
+ case PPC_ID_SPE_EFSCFUF:
+ case PPC_ID_SPE_EFSCFUI:
+ case PPC_ID_SPE_EFSCTSF:
+ case PPC_ID_SPE_EFSCTSI:
+ case PPC_ID_SPE_EFSCTSIZ:
+ case PPC_ID_SPE_EFSCTUF:
+ case PPC_ID_SPE_EFSCTUI:
+ case PPC_ID_SPE_EFSCTUIZ:
+ case PPC_ID_SPE_EVFSCFSF:
+ case PPC_ID_SPE_EVFSCFSI:
+ case PPC_ID_SPE_EVFSCFUF:
+ case PPC_ID_SPE_EVFSCFUI:
+ case PPC_ID_SPE_EVFSCTSF:
+ case PPC_ID_SPE_EVFSCTSI:
+ case PPC_ID_SPE_EVFSCTSIZ:
+ case PPC_ID_SPE_EVFSCTUF:
+ case PPC_ID_SPE_EVFSCTUI:
+ case PPC_ID_SPE_EVFSCTUIZ:
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ break;
+
+ // crfD//, rA, rB
+ case PPC_ID_SPE_EFDCMPEQ:
+ case PPC_ID_SPE_EFDCMPGT:
+ case PPC_ID_SPE_EFDCMPLT:
+ case PPC_ID_SPE_EFDTSTEQ:
+ case PPC_ID_SPE_EFDTSTGT:
+ case PPC_ID_SPE_EFDTSTLT:
+ case PPC_ID_SPE_EFSCMPEQ:
+ case PPC_ID_SPE_EFSCMPGT:
+ case PPC_ID_SPE_EFSCMPLT:
+ case PPC_ID_SPE_EFSTSTEQ:
+ case PPC_ID_SPE_EFSTSTGT:
+ case PPC_ID_SPE_EFSTSTLT:
+ case PPC_ID_SPE_EVCMPEQ:
+ case PPC_ID_SPE_EVCMPGTS:
+ case PPC_ID_SPE_EVCMPGTU:
+ case PPC_ID_SPE_EVCMPLTS:
+ case PPC_ID_SPE_EVCMPLTU:
+ case PPC_ID_SPE_EVFSCMPEQ:
+ case PPC_ID_SPE_EVFSCMPGT:
+ case PPC_ID_SPE_EVFSCMPLT:
+ case PPC_ID_SPE_EVFSTSTEQ:
+ case PPC_ID_SPE_EVFSTSTGT:
+ case PPC_ID_SPE_EVFSTSTLT:
+ PushCRFDImplyCR0(instruction, word32);
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ // rD, UIMM, rB
+ case PPC_ID_SPE_EVADDIW:
+ case PPC_ID_SPE_EVSUBIFW:
+ PushRD(instruction, word32);
+ PushUIMMValue(instruction, (word32 >> 16) & 0x1f);
+ PushRB(instruction, word32);
+ break;
+
+ // rD, SIMM, ///
+ case PPC_ID_SPE_EVSPLATFI:
+ case PPC_ID_SPE_EVSPLATI:
+ {
+ int32_t simm = sign_extend((word32 >> 16) & 0x1f, 5);
+ PushRD(instruction, word32);
+ PushSIMMValue(instruction, simm);
+ break;
+ }
+
+ // rD, rA, UIMM (SPE)
+ case PPC_ID_SPE_EVRLWI:
+ case PPC_ID_SPE_EVSLWI:
+ case PPC_ID_SPE_EVSRWIS:
+ case PPC_ID_SPE_EVSRWIU:
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushUIMMValue(instruction, (word32 >> 11) & 0x1f);
+ break;
+
+ // rD, rA, UIMM (SPE loads)
+ case PPC_ID_SPE_EVLDD:
+ case PPC_ID_SPE_EVLDH:
+ case PPC_ID_SPE_EVLDW:
+ case PPC_ID_SPE_EVLHHESPLAT:
+ case PPC_ID_SPE_EVLHHOSSPLAT:
+ case PPC_ID_SPE_EVLHHOUSPLAT:
+ case PPC_ID_SPE_EVLWHE:
+ case PPC_ID_SPE_EVLWHOS:
+ case PPC_ID_SPE_EVLWHOU:
+ case PPC_ID_SPE_EVLWHSPLAT:
+ case PPC_ID_SPE_EVLWWSPLAT:
+ PushRD(instruction, word32);
+ PushRAor0(instruction, word32);
+ PushUIMMValue(instruction, (word32 >> 11) & 0x1f);
+ break;
+
+ // rS, rA, UIMM (SPE)
+ case PPC_ID_SPE_EVSTDD:
+ case PPC_ID_SPE_EVSTDH:
+ case PPC_ID_SPE_EVSTDW:
+ case PPC_ID_SPE_EVSTWHE:
+ case PPC_ID_SPE_EVSTWHO:
+ case PPC_ID_SPE_EVSTWWE:
+ case PPC_ID_SPE_EVSTWWO:
+ PushRS(instruction, word32);
+ PushRAor0(instruction, word32);
+ PushUIMMValue(instruction, (word32 >> 11) & 0x1f);
+ break;
+
+ // rS, rA, rB (SPE store-indexed)
+ case PPC_ID_SPE_EVSTDDX:
+ case PPC_ID_SPE_EVSTDHX:
+ case PPC_ID_SPE_EVSTDWX:
+ case PPC_ID_SPE_EVSTWHEX:
+ case PPC_ID_SPE_EVSTWHOX:
+ case PPC_ID_SPE_EVSTWWEX:
+ case PPC_ID_SPE_EVSTWWOX:
+ PushRS(instruction, word32);
+ PushRA(instruction, word32);
+ PushUIMMValue(instruction, (word32 >> 11) & 0x1f);
+ break;
+
+ // rD, rA
+ case PPC_ID_SPE_EVMR:
+ case PPC_ID_SPE_EVNOT:
+ case PPC_ID_SPE_EVRNDW:
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ break;
+
+ // rD, rA, rB, crfS
+ case PPC_ID_SPE_EVSEL:
+ {
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+ uint32_t crfs = word32 & 0x7;
+ PushRegister(instruction, PPC_OP_REG_CRFS, Crf(crfs));
+ break;
+ }
+
+ // PAIRED-SINGLE INSTRUCTIONS
+
+ // op[.] frD, frA, frB
+ case PPC_ID_PAIREDSINGLE_PS_ADDx:
+ case PPC_ID_PAIREDSINGLE_PS_DIVx:
+ case PPC_ID_PAIREDSINGLE_PS_MERGE00x:
+ case PPC_ID_PAIREDSINGLE_PS_MERGE01x:
+ case PPC_ID_PAIREDSINGLE_PS_MERGE10x:
+ case PPC_ID_PAIREDSINGLE_PS_MERGE11x:
+ case PPC_ID_PAIREDSINGLE_PS_SUBx:
+ PushFRD(instruction, word32);
+ PushFRA(instruction, word32);
+ PushFRB(instruction, word32);
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ // op[.] frD, frA, frC
+ case PPC_ID_PAIREDSINGLE_PS_MULx:
+ case PPC_ID_PAIREDSINGLE_PS_MULS0x:
+ case PPC_ID_PAIREDSINGLE_PS_MULS1x:
+ PushFRD(instruction, word32);
+ PushFRA(instruction, word32);
+ PushFRC(instruction, word32);
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ // op[.] frD, frB
+ case PPC_ID_PAIREDSINGLE_PS_ABSx:
+ case PPC_ID_PAIREDSINGLE_PS_MRx:
+ case PPC_ID_PAIREDSINGLE_PS_NABSx:
+ case PPC_ID_PAIREDSINGLE_PS_NEGx:
+ case PPC_ID_PAIREDSINGLE_PS_RESx:
+ case PPC_ID_PAIREDSINGLE_PS_RSQRTEx:
+ PushFRD(instruction, word32);
+ PushFRB(instruction, word32);
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ // op[.] frD, frA, frC, frB
+ // (take care not to use frD, frA, frB, frC)
+ case PPC_ID_PAIREDSINGLE_PS_MADDx:
+ case PPC_ID_PAIREDSINGLE_PS_MADDS0x:
+ case PPC_ID_PAIREDSINGLE_PS_MADDS1x:
+ case PPC_ID_PAIREDSINGLE_PS_MSUBx:
+ case PPC_ID_PAIREDSINGLE_PS_NMADDx:
+ case PPC_ID_PAIREDSINGLE_PS_NMSUBx:
+ case PPC_ID_PAIREDSINGLE_PS_SELx:
+ case PPC_ID_PAIREDSINGLE_PS_SUM0x:
+ case PPC_ID_PAIREDSINGLE_PS_SUM1x:
+ PushFRD(instruction, word32);
+ PushFRA(instruction, word32);
+ PushFRC(instruction, word32);
+ PushFRB(instruction, word32);
+
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ // op crfD, frA, frB
+ case PPC_ID_PAIREDSINGLE_PS_CMPO0:
+ case PPC_ID_PAIREDSINGLE_PS_CMPO1:
+ case PPC_ID_PAIREDSINGLE_PS_CMPU0:
+ case PPC_ID_PAIREDSINGLE_PS_CMPU1:
+ PushCRFDImplyCR0(instruction, word32);
+ PushFRA(instruction, word32);
+ PushFRB(instruction, word32);
+ break;
+
+ // load-stores
+ case PPC_ID_PAIREDSINGLE_PSQ_L:
+ case PPC_ID_PAIREDSINGLE_PSQ_LU:
+ {
+ uint32_t w = (word32 >> 15) & 0x1;
+ uint32_t i = (word32 >> 12) & 0x7;
+ uint32_t d = word32 & 0xfff;
+
+ PushFRD(instruction, word32);
+ PushMemRAOffset(instruction, word32, sign_extend(d, 12));
+ PushUIMMValue(instruction, w);
+ PushUIMMValue(instruction, i);
+ break;
+ }
+
+ case PPC_ID_PAIREDSINGLE_PSQ_LUX:
+ case PPC_ID_PAIREDSINGLE_PSQ_LX:
+ {
+ uint32_t w = (word32 >> 10) & 0x1;
+ uint32_t i = (word32 >> 7) & 0x7;
+
+ PushFRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+ PushUIMMValue(instruction, w);
+ PushUIMMValue(instruction, i);
+ break;
+ }
+
+ case PPC_ID_PAIREDSINGLE_PSQ_ST:
+ case PPC_ID_PAIREDSINGLE_PSQ_STU:
+ {
+ uint32_t w = (word32 >> 15) & 0x1;
+ uint32_t i = (word32 >> 12) & 0x7;
+ uint32_t d = word32 & 0xfff;
+
+ PushFRS(instruction, word32);
+ PushMemRAOffset(instruction, word32, sign_extend(d, 12));
+ PushUIMMValue(instruction, w);
+ PushUIMMValue(instruction, i);
+ break;
+ }
+
+ case PPC_ID_PAIREDSINGLE_PSQ_STX:
+ case PPC_ID_PAIREDSINGLE_PSQ_STUX:
+ {
+ uint32_t w = (word32 >> 10) & 0x1;
+ uint32_t i = (word32 >> 7) & 0x7;
+
+ PushFRS(instruction, word32);
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+ PushUIMMValue(instruction, w);
+ PushUIMMValue(instruction, i);
+ break;
+ }
+
+ // dcbz_l rA, rB
+ case PPC_ID_PAIREDSINGLE_DCBZ_L:
+ PushRAor0(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void FillBcxOperands(OperandsList* bcx, const Instruction* instruction)
+{
+ memset(bcx, 0, sizeof *bcx);
+
+ if (instruction->id != PPC_ID_BCx)
+ return;
+
+ uint32_t bo = instruction->operands[0].uimm;
+ uint32_t bi = instruction->operands[1].uimm;
+
+ switch (bo & 0x1e)
+ {
+ // copy BI, target
+ case 0:
+ case 2:
+ case 8:
+ case 10:
+ CopyOperand(&bcx->operands[0], &instruction->operands[1]);
+ CopyOperand(&bcx->operands[1], &instruction->operands[2]);
+ bcx->numOperands = 2;
+ break;
+
+ // use BI, copy target
+ case 4:
+ case 6:
+ case 12:
+ case 14:
+ {
+ uint32_t crn = bi >> 2;
+
+ bcx->operands[0].cls = PPC_OP_REG_CRFS_IMPLY0;
+ bcx->operands[0].reg = Crf(crn);
+ CopyOperand(&bcx->operands[1], &instruction->operands[2]);
+ bcx->numOperands = 2;
+ break;
+ }
+
+ // just copy target
+ case 16:
+ case 18:
+ case 20:
+ case 22:
+ case 24:
+ case 26:
+ case 28:
+ case 30:
+ CopyOperand(&bcx->operands[0], &instruction->operands[2]);
+ bcx->numOperands = 1;
+ break;
+
+ // copy BO, BI, target
+ default:
+ CopyOperand(&bcx->operands[0], &instruction->operands[0]);
+ CopyOperand(&bcx->operands[1], &instruction->operands[1]);
+ CopyOperand(&bcx->operands[2], &instruction->operands[2]);
+ bcx->numOperands = 3;
+
+ break;
+ }
+}
+
+void FillBcctrxOperands(OperandsList* bcctrx, const Instruction* instruction)
+{
+ memset(bcctrx, 0, sizeof *bcctrx);
+
+ if (instruction->id != PPC_ID_BCCTRx)
+ return;
+
+ uint32_t bo = instruction->operands[0].uimm;
+ uint32_t bi = instruction->operands[1].uimm;
+
+ switch (bo & 0x1e)
+ {
+ // copy BI --> crn
+ case 4:
+ case 6:
+ case 12:
+ case 14:
+ {
+ uint32_t crn = bi >> 2;
+
+ bcctrx->operands[0].cls = PPC_OP_REG_CRFS_IMPLY0;
+ bcctrx->operands[0].reg = Crf(crn);
+ bcctrx->numOperands = 1;
+ break;
+ }
+
+ // no ops (BCTR, BCTRL)
+ case 20:
+ break;
+
+ // copy BO, BI
+ default:
+ CopyOperand(&bcctrx->operands[0], &instruction->operands[0]);
+ CopyOperand(&bcctrx->operands[1], &instruction->operands[1]);
+ bcctrx->numOperands = 2;
+
+ break;
+ }
+
+}
+
+void FillBclrxOperands(OperandsList* bclrx, const Instruction* instruction)
+{
+ memset(bclrx, 0, sizeof *bclrx);
+
+ if (instruction->id != PPC_ID_BCLRx)
+ return;
+
+ uint32_t bo = instruction->operands[0].uimm;
+ uint32_t bi = instruction->operands[1].uimm;
+
+ switch (bo & 0x1e)
+ {
+ // copy BI
+ case 0:
+ case 2:
+ case 8:
+ case 10:
+ CopyOperand(&bclrx->operands[0], &instruction->operands[1]);
+ bclrx->operands[0].cls = PPC_OP_CRBIT;
+ bclrx->operands[0].crbit = (uint32_t)instruction->operands[1].uimm;
+ bclrx->numOperands = 1;
+ break;
+
+ // copy BI --> crn
+ case 4:
+ case 6:
+ case 12:
+ case 14:
+ {
+ uint32_t crn = bi >> 2;
+
+ bclrx->operands[0].cls = PPC_OP_REG_CRFS_IMPLY0;
+ bclrx->operands[0].reg = Crf(crn);
+ bclrx->numOperands = 1;
+ break;
+ }
+
+ // no ops (decrement CTR, compare to 0, but no condition check)
+ case 16:
+ case 18:
+ case 24:
+ case 26:
+
+ // no ops (BLR, BLRL)
+ case 20:
+ break;
+
+ // copy BO, BI
+ default:
+ CopyOperand(&bclrx->operands[0], &instruction->operands[0]);
+ CopyOperand(&bclrx->operands[1], &instruction->operands[1]);
+ bclrx->numOperands = 2;
+
+ break;
+ }
+}
diff --git a/arch/powerpc/decode/priv.c b/arch/powerpc/decode/priv.c
new file mode 100644
index 00000000..2db5c839
--- /dev/null
+++ b/arch/powerpc/decode/priv.c
@@ -0,0 +1,251 @@
+#include <string.h>
+
+#include "priv.h"
+
+uint32_t GetA(uint32_t word32)
+{
+ return (word32 >> 16) & 0x1f;
+}
+
+uint32_t GetB(uint32_t word32)
+{
+ return (word32 >> 11) & 0x1f;
+}
+
+uint32_t GetC(uint32_t word32)
+{
+ return (word32 >> 6) & 0x1f;
+}
+
+uint32_t GetD(uint32_t word32)
+{
+ return (word32 >> 21) & 0x1f;
+}
+
+uint32_t GetS(uint32_t word32)
+{
+ return (word32 >> 21) & 0x1f;
+}
+
+uint32_t GetBI(uint32_t word32)
+{
+ return (word32 >> 16) & 0x1f;
+}
+
+uint32_t GetBO(uint32_t word32)
+{
+ return (word32 >> 21) & 0x1f;
+}
+
+uint32_t GetVsxA(uint32_t word32)
+{
+ uint32_t ax = (word32 >> 2) & 0x1;
+ uint32_t a = (word32 >> 16) & 0x1f;
+
+ return (ax << 5) | a;
+}
+
+uint32_t GetVsxB(uint32_t word32)
+{
+ uint32_t bx = (word32 >> 1) & 0x1;
+ uint32_t b = (word32 >> 11) & 0x1f;
+
+ return (bx << 5) | b;
+}
+
+uint32_t GetVsxC(uint32_t word32)
+{
+ uint32_t cx = (word32 >> 3) & 0x1;
+ uint32_t c = (word32 >> 6) & 0x1f;
+
+ return (cx << 5) | c;
+}
+
+uint32_t GetVsxD(uint32_t word32)
+{
+ uint32_t dx = word32 & 0x1;
+ uint32_t d = (word32 >> 21) & 0x1f;
+
+ return (dx << 5) | d;
+}
+
+uint32_t GetSpecialRegisterCommon(uint32_t word32)
+{
+ uint32_t xr5_9 = (word32 >> 16) & 0x1f;
+ uint32_t xr0_4 = (word32 >> 11) & 0x1f;
+ uint32_t xr = (xr0_4 << 5) | xr5_9;
+
+ return xr;
+}
+
+uint32_t GetME(uint32_t word32)
+{
+ return (word32 >> 1) & 0x1f;
+}
+
+uint32_t GetMB(uint32_t word32)
+{
+ return (word32 >> 6) & 0x1f;
+}
+
+uint32_t GetSH(uint32_t word32)
+{
+ return (word32 >> 11) & 0x1f;
+}
+
+uint32_t GetSH64(uint32_t word32)
+{
+ uint32_t sh5 = (word32 >> 1) & 0x1;
+ uint32_t sh4_0 = (word32 >> 11) & 0x1f;
+
+ return (sh5 << 5) | sh4_0;
+}
+
+uint32_t GetMX64(uint32_t word32)
+{
+ uint32_t mx = (word32 >> 5) & 0x3f;
+
+ // x <- mx5 || mx[0:5] in powerpc's bit order
+ return ((mx & 0x1) << 5) | (mx >> 1);
+}
+
+void CopyOperand(Operand* dst, const Operand* src)
+{
+ memcpy(dst, src, sizeof *dst);
+}
+
+InstructionId VleTranslateMnemonic(InstructionId id)
+{
+ switch (id)
+ {
+ case PPC_ID_VLE_E_ADDIx: return PPC_ID_ADDIx;
+ case PPC_ID_VLE_E_ADDICx: return PPC_ID_ADDICx;
+ case PPC_ID_VLE_E_ADD2I: return PPC_ID_ADDIx;
+ case PPC_ID_VLE_E_ADD2IS: return PPC_ID_ADDIS;
+ case PPC_ID_VLE_E_ADD16I: return PPC_ID_ADDIx;
+ case PPC_ID_VLE_E_ANDIx: return PPC_ID_ANDIx;
+ case PPC_ID_VLE_E_AND2I: return PPC_ID_ANDIx;
+ case PPC_ID_VLE_E_AND2IS: return PPC_ID_ANDIS;
+ case PPC_ID_VLE_E_Bx: return PPC_ID_Bx;
+ case PPC_ID_VLE_E_CMP16I: return PPC_ID_CMPWI;
+ case PPC_ID_VLE_E_CMPI: return PPC_ID_CMPWI;
+ case PPC_ID_VLE_E_CMPL16I: return PPC_ID_CMPLWI;
+ case PPC_ID_VLE_E_CMPLI: return PPC_ID_CMPLWI;
+ case PPC_ID_VLE_E_CRAND: return PPC_ID_CRAND;
+ case PPC_ID_VLE_E_CRANDC: return PPC_ID_CRANDC;
+ case PPC_ID_VLE_E_CREQV: return PPC_ID_CREQV;
+ case PPC_ID_VLE_E_CRNAND: return PPC_ID_CRNAND;
+ case PPC_ID_VLE_E_CRNOR: return PPC_ID_CRNOR;
+ case PPC_ID_VLE_E_CROR: return PPC_ID_CROR;
+ case PPC_ID_VLE_E_CRORC: return PPC_ID_CRORC;
+ case PPC_ID_VLE_E_CRXOR: return PPC_ID_CRXOR;
+ case PPC_ID_VLE_E_LBZ: return PPC_ID_LBZ;
+ case PPC_ID_VLE_E_LBZU: return PPC_ID_LBZU;
+ case PPC_ID_VLE_E_LHA: return PPC_ID_LHA;
+ case PPC_ID_VLE_E_LHAU: return PPC_ID_LHAU;
+ case PPC_ID_VLE_E_LHZ: return PPC_ID_LHZ;
+ case PPC_ID_VLE_E_LHZU: return PPC_ID_LHZU;
+ case PPC_ID_VLE_E_LI: return PPC_ID_LI;
+ case PPC_ID_VLE_E_LIS: return PPC_ID_LIS;
+ case PPC_ID_VLE_E_LMW: return PPC_ID_LMW;
+ case PPC_ID_VLE_E_LWZ: return PPC_ID_LWZ;
+ case PPC_ID_VLE_E_LWZU: return PPC_ID_LWZU;
+ case PPC_ID_VLE_E_MCRF: return PPC_ID_MCRF;
+ case PPC_ID_VLE_E_MULL2I: return PPC_ID_MULLI;
+ case PPC_ID_VLE_E_MULLI: return PPC_ID_MULLI;
+ case PPC_ID_VLE_E_OR2I: return PPC_ID_ORIx;
+ case PPC_ID_VLE_E_OR2IS: return PPC_ID_ORIS;
+ case PPC_ID_VLE_E_ORIx: return PPC_ID_ORIx;
+ case PPC_ID_VLE_E_RLWIMI: return PPC_ID_RLWIMIx;
+ case PPC_ID_VLE_E_RLWINM: return PPC_ID_RLWINMx;
+ case PPC_ID_VLE_E_SLWIx: return PPC_ID_SLWIx;
+ case PPC_ID_VLE_E_SRWIx: return PPC_ID_SRWIx;
+ case PPC_ID_VLE_E_STB: return PPC_ID_STB;
+ case PPC_ID_VLE_E_STBU: return PPC_ID_STBU;
+ case PPC_ID_VLE_E_STH: return PPC_ID_STH;
+ case PPC_ID_VLE_E_STHU: return PPC_ID_STHU;
+ case PPC_ID_VLE_E_STMW: return PPC_ID_STMW;
+ case PPC_ID_VLE_E_STW: return PPC_ID_STW;
+ case PPC_ID_VLE_E_STWU: return PPC_ID_STWU;
+ case PPC_ID_VLE_E_SUBFICx: return PPC_ID_SUBFICx;
+ case PPC_ID_VLE_E_XORIx: return PPC_ID_XORIx;
+
+ // 16-bit VLE instructions
+ case PPC_ID_VLE_SE_ADD: return PPC_ID_ADDx;
+ case PPC_ID_VLE_SE_ADDI: return PPC_ID_ADDIx;
+ case PPC_ID_VLE_SE_ANDx: return PPC_ID_ANDx;
+ case PPC_ID_VLE_SE_ANDC: return PPC_ID_ANDCx;
+ case PPC_ID_VLE_SE_ANDI: return PPC_ID_ANDIx;
+ case PPC_ID_VLE_SE_Bx: return PPC_ID_Bx;
+ case PPC_ID_VLE_SE_BCLRI: return PPC_ID_ANDIx;
+ case PPC_ID_VLE_SE_BGENI: return PPC_ID_LI;
+ case PPC_ID_VLE_SE_BMASKI: return PPC_ID_LI;
+ case PPC_ID_VLE_SE_BSETI: return PPC_ID_ORIx;
+ case PPC_ID_VLE_SE_CMP: return PPC_ID_CMPW;
+ case PPC_ID_VLE_SE_CMPI: return PPC_ID_CMPWI;
+ case PPC_ID_VLE_SE_CMPL: return PPC_ID_CMPLW;
+ case PPC_ID_VLE_SE_CMPLI: return PPC_ID_CMPLWI;
+ case PPC_ID_VLE_SE_EXTSB: return PPC_ID_EXTSBx;
+ case PPC_ID_VLE_SE_EXTSH: return PPC_ID_EXTSHx;
+ case PPC_ID_VLE_SE_EXTZB: return PPC_ID_ANDIx;
+ case PPC_ID_VLE_SE_EXTZH: return PPC_ID_ANDIx;
+ case PPC_ID_VLE_SE_ISYNC: return PPC_ID_ISYNC;
+ case PPC_ID_VLE_SE_LI: return PPC_ID_LI;
+ case PPC_ID_VLE_SE_MFAR: return PPC_ID_MRx;
+ case PPC_ID_VLE_SE_MFCTR: return PPC_ID_MFCTR;
+ case PPC_ID_VLE_SE_MFLR: return PPC_ID_MFLR;
+ case PPC_ID_VLE_SE_MR: return PPC_ID_MRx;
+ case PPC_ID_VLE_SE_MTAR: return PPC_ID_MRx;
+ case PPC_ID_VLE_SE_MTCTR: return PPC_ID_MTCTR;
+ case PPC_ID_VLE_SE_MTLR: return PPC_ID_MTLR;
+ case PPC_ID_VLE_SE_MULLW: return PPC_ID_MULLWx;
+ case PPC_ID_VLE_SE_NEG: return PPC_ID_NEGx;
+ case PPC_ID_VLE_SE_NOP: return PPC_ID_NOP;
+ case PPC_ID_VLE_SE_NOT: return PPC_ID_NORx;
+ case PPC_ID_VLE_SE_OR: return PPC_ID_ORx;
+ case PPC_ID_VLE_SE_RFCI: return PPC_ID_RFCI;
+ case PPC_ID_VLE_SE_RFDI: return PPC_ID_RFDI;
+ case PPC_ID_VLE_SE_RFI: return PPC_ID_RFI;
+ case PPC_ID_VLE_SE_RFMCI: return PPC_ID_RFMCI;
+ case PPC_ID_VLE_SE_SC: return PPC_ID_SC;
+ case PPC_ID_VLE_SE_SLW: return PPC_ID_SLWx;
+ case PPC_ID_VLE_SE_SLWI: return PPC_ID_SLWIx;
+ case PPC_ID_VLE_SE_SRAW: return PPC_ID_SRAWx;
+ case PPC_ID_VLE_SE_SRAWI: return PPC_ID_SRAWIx;
+ case PPC_ID_VLE_SE_SRW: return PPC_ID_SRWx;
+ case PPC_ID_VLE_SE_SRWI: return PPC_ID_SRWIx;
+ case PPC_ID_VLE_SE_SUB: return PPC_ID_SUBFx;
+ case PPC_ID_VLE_SE_SUBF: return PPC_ID_SUBFx;
+ case PPC_ID_VLE_SE_SUBIx: return PPC_ID_ADDIx;
+
+ // We purposefully keep some branch instructions as VLE
+ // instructions, for translating their operand lists as
+ // a special case
+ case PPC_ID_VLE_E_BCx:
+ case PPC_ID_VLE_SE_BC:
+ case PPC_ID_VLE_SE_BCTRx:
+ case PPC_ID_VLE_SE_BLRx:
+ return id;
+
+ // These instructions don't have a non-VLE equivalent
+ case PPC_ID_VLE_E_CMPH16I:
+ case PPC_ID_VLE_E_CMPHL:
+ case PPC_ID_VLE_E_CMPHL16I:
+ case PPC_ID_VLE_E_RLWx:
+ case PPC_ID_VLE_E_RLWIx:
+ case PPC_ID_VLE_SE_BTSTI:
+ case PPC_ID_VLE_SE_CMPH:
+ case PPC_ID_VLE_SE_CMPHL:
+ case PPC_ID_VLE_SE_ILLEGAL:
+ case PPC_ID_VLE_SE_LBZ: // VLE treats rA=0 as valid base
+ case PPC_ID_VLE_SE_LHZ: // VLE treats rA=0 as valid base
+ case PPC_ID_VLE_SE_LWZ: // VLE treats rA=0 as valid base
+ case PPC_ID_VLE_SE_STB: // VLE treats rA=0 as valid base
+ case PPC_ID_VLE_SE_STH: // VLE treats rA=0 as valid base
+ case PPC_ID_VLE_SE_STW: // VLE treats rA=0 as valid base
+ return id;
+
+ default:
+ return id;
+ }
+}
diff --git a/arch/powerpc/decode/priv.h b/arch/powerpc/decode/priv.h
new file mode 100644
index 00000000..8cc8b297
--- /dev/null
+++ b/arch/powerpc/decode/priv.h
@@ -0,0 +1,54 @@
+#include <inttypes.h>
+
+#include "decode.h"
+
+int32_t sign_extend(uint32_t x, unsigned numBits);
+
+uint32_t GetA(uint32_t word32);
+uint32_t GetB(uint32_t word32);
+uint32_t GetC(uint32_t word32);
+uint32_t GetD(uint32_t word32);
+uint32_t GetS(uint32_t word32);
+
+uint32_t GetBI(uint32_t word32);
+uint32_t GetBO(uint32_t word32);
+
+uint32_t GetVsxA(uint32_t word32);
+uint32_t GetVsxB(uint32_t word32);
+uint32_t GetVsxC(uint32_t word32);
+uint32_t GetVsxD(uint32_t word32);
+
+uint32_t GetSpecialRegisterCommon(uint32_t word32);
+
+uint32_t GetME(uint32_t word32);
+uint32_t GetMB(uint32_t word32);
+uint32_t GetSH(uint32_t word32);
+uint32_t GetSH64(uint32_t word32);
+uint32_t GetMX64(uint32_t word32);
+
+void FillOperands32(Instruction* instruction, uint32_t word32, uint64_t address);
+
+Register Gpr(uint32_t value);
+Register Crf(uint32_t value);
+void PushUIMMValue(Instruction* instruction, uint64_t uimm);
+void PushSIMMValue(Instruction* instruction, int32_t simm);
+void PushRegister(Instruction* instruction, OperandClass cls, Register reg);
+void PushRA(Instruction* instruction, uint32_t word32);
+void PushRB(Instruction* instruction, uint32_t word32);
+void PushRD(Instruction* instruction, uint32_t word32);
+void PushRS(Instruction* instruction, uint32_t word32);
+void PushCRBitA(Instruction* instruction, uint32_t word32);
+void PushCRBitB(Instruction* instruction, uint32_t word32);
+void PushCRBitD(Instruction* instruction, uint32_t word32);
+void PushCRFD(Instruction* instruction, uint32_t word32);
+void PushCRFDImplyCR0(Instruction* instruction, uint32_t word32);
+void PushCRFS(Instruction* instruction, uint32_t word32);
+void PushMem(Instruction* instruction, OperandClass cls, Register reg, int32_t offset);
+void PushMemRA(Instruction* instruction, uint32_t word32);
+void PushLabel(Instruction* instruction, uint64_t address);
+
+void CopyOperand(Operand* dst, const Operand* src);
+
+InstructionId Decode0x04(uint32_t word32, uint32_t decodeFlags);
+InstructionId Decode0x1F(uint32_t word32, uint32_t decodeFlags);
+InstructionId VleTranslateMnemonic(InstructionId id);
diff --git a/arch/powerpc/decode/vle16.c b/arch/powerpc/decode/vle16.c
new file mode 100644
index 00000000..7500e6ba
--- /dev/null
+++ b/arch/powerpc/decode/vle16.c
@@ -0,0 +1,790 @@
+#include <string.h>
+
+#include "decode.h"
+#include "priv.h"
+
+static InstructionId Decode16Vle0x00(uint16_t word16, uint32_t decodeFlags)
+{
+ switch (word16) {
+ case 0x0000:
+ return PPC_ID_VLE_SE_ILLEGAL;
+
+ case 0x0001:
+ return PPC_ID_VLE_SE_ISYNC;
+
+ case 0x0002:
+ return PPC_ID_VLE_SE_SC;
+
+ case 0x0004:
+ case 0x0005:
+ return PPC_ID_VLE_SE_BLRx;
+
+ case 0x0006:
+ case 0x0007:
+ return PPC_ID_VLE_SE_BCTRx;
+
+ case 0x0008:
+ return PPC_ID_VLE_SE_RFI;
+
+ case 0x0009:
+ return PPC_ID_VLE_SE_RFCI;
+
+ case 0x000a:
+ return PPC_ID_VLE_SE_RFDI;
+
+ case 0x000b:
+ return PPC_ID_VLE_SE_RFMCI;
+
+ default:
+ ;
+ }
+
+ uint32_t subop = (word16 >> 4) & 0xfff;
+ switch (subop) {
+ case 0x002:
+ return PPC_ID_VLE_SE_NOT;
+
+ case 0x003:
+ return PPC_ID_VLE_SE_NEG;
+
+ case 0x008:
+ return PPC_ID_VLE_SE_MFLR;
+
+ case 0x009:
+ return PPC_ID_VLE_SE_MTLR;
+
+ case 0x00a:
+ return PPC_ID_VLE_SE_MFCTR;
+
+ case 0x00b:
+ return PPC_ID_VLE_SE_MTCTR;
+
+ case 0x00c:
+ return PPC_ID_VLE_SE_EXTZB;
+
+ case 0x00d:
+ return PPC_ID_VLE_SE_EXTSB;
+
+ case 0x00e:
+ return PPC_ID_VLE_SE_EXTZH;
+
+ case 0x00f:
+ return PPC_ID_VLE_SE_EXTSH;
+
+ default:
+ return PPC_ID_INVALID;;
+ }
+}
+static InstructionId Decode16Vle(uint16_t word16, uint32_t decodeFlags)
+{
+ uint8_t hi = (word16 >> 8) & 0xff;
+ switch (hi) {
+ case 0x00:
+ return Decode16Vle0x00(word16, decodeFlags);
+
+ case 0x01:
+ return PPC_ID_VLE_SE_MR;
+
+ case 0x02:
+ return PPC_ID_VLE_SE_MTAR;
+
+ case 0x03:
+ return PPC_ID_VLE_SE_MFAR;
+
+ case 0x04:
+ return PPC_ID_VLE_SE_ADD;
+
+ case 0x05:
+ return PPC_ID_VLE_SE_MULLW;
+
+ case 0x06:
+ return PPC_ID_VLE_SE_SUB;
+
+ case 0x07:
+ return PPC_ID_VLE_SE_SUBF;
+
+ case 0x0c:
+ return PPC_ID_VLE_SE_CMP;
+
+ case 0x0d:
+ return PPC_ID_VLE_SE_CMPL;
+
+ case 0x0e:
+ return PPC_ID_VLE_SE_CMPH;
+
+ case 0x0f:
+ return PPC_ID_VLE_SE_CMPHL;
+
+ case 0x20:
+ case 0x21:
+ return PPC_ID_VLE_SE_ADDI;
+
+ case 0x22:
+ case 0x23:
+ return PPC_ID_VLE_SE_CMPLI;
+
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ return PPC_ID_VLE_SE_SUBIx;
+
+ case 0x2a:
+ case 0x2b:
+ return PPC_ID_VLE_SE_CMPI;
+
+ case 0x2c:
+ case 0x2d:
+ return PPC_ID_VLE_SE_BMASKI;
+
+ case 0x2e:
+ case 0x2f:
+ return PPC_ID_VLE_SE_ANDI;
+
+ case 0x40:
+ return PPC_ID_VLE_SE_SRW;
+
+ case 0x41:
+ return PPC_ID_VLE_SE_SRAW;
+
+ case 0x42:
+ return PPC_ID_VLE_SE_SLW;
+
+ case 0x44:
+ {
+ // rY = 0, rX = 0
+ // Not technically documented, but compiler
+ // occasionally emits `or, r0, r0`, which are NOPs in
+ // 32-bit land
+ if ((word16 & 0xff) == 0x00)
+ return PPC_ID_VLE_SE_NOP;
+ else
+ return PPC_ID_VLE_SE_OR;
+ }
+
+ case 0x45:
+ return PPC_ID_VLE_SE_ANDC;
+
+ case 0x46:
+ case 0x47:
+ return PPC_ID_VLE_SE_ANDx;
+
+ case 0x48:
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ case 0x4e:
+ case 0x4f:
+ return PPC_ID_VLE_SE_LI;
+
+ case 0x60:
+ case 0x61:
+ return PPC_ID_VLE_SE_BCLRI;
+
+ case 0x62:
+ case 0x63:
+ return PPC_ID_VLE_SE_BGENI;
+
+ case 0x64:
+ case 0x65:
+ return PPC_ID_VLE_SE_BSETI;
+
+ case 0x66:
+ case 0x67:
+ return PPC_ID_VLE_SE_BTSTI;
+
+ case 0x68:
+ case 0x69:
+ return PPC_ID_VLE_SE_SRWI;
+
+ case 0x6a:
+ case 0x6b:
+ return PPC_ID_VLE_SE_SRAWI;
+
+ case 0x6c:
+ case 0x6d:
+ return PPC_ID_VLE_SE_SLWI;
+
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f:
+ return PPC_ID_VLE_SE_LBZ;
+
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f:
+ return PPC_ID_VLE_SE_STB;
+
+ case 0xa0:
+ case 0xa1:
+ case 0xa2:
+ case 0xa3:
+ case 0xa4:
+ case 0xa5:
+ case 0xa6:
+ case 0xa7:
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+ return PPC_ID_VLE_SE_LHZ;
+
+ case 0xb0:
+ case 0xb1:
+ case 0xb2:
+ case 0xb3:
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ return PPC_ID_VLE_SE_STH;
+
+ case 0xc0:
+ case 0xc1:
+ case 0xc2:
+ case 0xc3:
+ case 0xc4:
+ case 0xc5:
+ case 0xc6:
+ case 0xc7:
+ case 0xc8:
+ case 0xc9:
+ case 0xca:
+ case 0xcb:
+ case 0xcc:
+ case 0xcd:
+ case 0xce:
+ case 0xcf:
+ return PPC_ID_VLE_SE_LWZ;
+
+ case 0xd0:
+ case 0xd1:
+ case 0xd2:
+ case 0xd3:
+ case 0xd4:
+ case 0xd5:
+ case 0xd6:
+ case 0xd7:
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+ return PPC_ID_VLE_SE_STW;
+
+ case 0xe0:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xe4:
+ case 0xe5:
+ case 0xe6:
+ case 0xe7:
+ return PPC_ID_VLE_SE_BC;
+
+ case 0xe8:
+ case 0xe9:
+ return PPC_ID_VLE_SE_Bx;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+}
+static uint16_t Get16Rx(uint16_t word16)
+{
+ return word16 & 0xf;
+}
+
+static uint16_t Get16Ry(uint16_t word16)
+{
+ return (word16 >> 4) & 0xf;
+}
+
+static uint16_t Get16Rz(uint16_t word16)
+{
+ return (word16 >> 4) & 0xf;
+}
+
+static void FillOperands16Vle(Instruction* instruction, uint16_t word16, uint64_t address, bool translate)
+{
+ uint16_t rx = Get16Rx(word16);
+ uint16_t ry = Get16Ry(word16);
+ uint16_t rz = Get16Rz(word16);
+
+ switch (instruction->id)
+ {
+ // <op>
+ case PPC_ID_VLE_SE_ILLEGAL:
+ case PPC_ID_VLE_SE_ISYNC:
+ case PPC_ID_VLE_SE_NOP:
+ case PPC_ID_VLE_SE_RFCI:
+ case PPC_ID_VLE_SE_RFDI:
+ case PPC_ID_VLE_SE_RFI:
+ case PPC_ID_VLE_SE_RFMCI:
+ case PPC_ID_VLE_SE_SC:
+ return;
+
+ // <op> rX, rY (4-bit) no rc
+ case PPC_ID_VLE_SE_ADD:
+ case PPC_ID_VLE_SE_ANDC:
+ case PPC_ID_VLE_SE_MR:
+ case PPC_ID_VLE_SE_MULLW:
+ case PPC_ID_VLE_SE_OR:
+ case PPC_ID_VLE_SE_SLW:
+ case PPC_ID_VLE_SE_SRAW:
+ case PPC_ID_VLE_SE_SRW:
+ case PPC_ID_VLE_SE_SUB:
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(rx));
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(ry));
+ if (translate)
+ PushRegister(instruction, PPC_OP_REG_RB, Gpr(rx));
+
+ break;
+
+ case PPC_ID_VLE_SE_SUBF:
+ // Subtle difference between this and SE_SUB:
+ // SUB rX, rY --> SUBF rX, rY, rX (rX := rX - rY)
+ // SUBF rX, rY --> SUBF rX, rX, rY (rX := rY - rX)
+ if (translate)
+ {
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(rx));
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(rx));
+ PushRegister(instruction, PPC_OP_REG_RB, Gpr(ry));
+ }
+ else
+ {
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(rx));
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(ry));
+ }
+
+ break;
+
+ // <op> rX, rY, comparisons
+ case PPC_ID_VLE_SE_CMP:
+ case PPC_ID_VLE_SE_CMPH:
+ case PPC_ID_VLE_SE_CMPHL:
+ case PPC_ID_VLE_SE_CMPL:
+ if (translate)
+ PushRegister(instruction, PPC_OP_REG_CRFD_IMPLY0, Crf(0));
+
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(rx));
+ PushRegister(instruction, PPC_OP_REG_RB, Gpr(ry));
+ break;
+
+ // <op> rX, rY (4-bit) with rc
+ case PPC_ID_VLE_SE_ANDx:
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(rx));
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(ry));
+ if (translate)
+ PushRegister(instruction, PPC_OP_REG_RB, Gpr(rx));
+
+ instruction->flags.rc = (word16 & 0x100) != 0;
+ break;
+
+ // <op> rX (4-bit)
+ case PPC_ID_VLE_SE_EXTSB:
+ case PPC_ID_VLE_SE_EXTSH:
+ PushRegister(instruction, PPC_OP_REG_RS, Gpr(rx));
+ if (translate)
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(rx));
+
+ break;
+
+ // There aren't any non-VLE instructions that correspond
+ // directly to these, but they can be mimicked by
+ // ANDI'ing with 0xff and 0xffff directly
+ // <op> rX (4-bit)
+ case PPC_ID_VLE_SE_EXTZB:
+ case PPC_ID_VLE_SE_EXTZH:
+ if (translate)
+ {
+ // ANDI rX, rX, 0xff
+ PushRegister(instruction, PPC_OP_REG_RS, Gpr(rx));
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(rx));
+ if (instruction->id == PPC_ID_VLE_SE_EXTZB)
+ PushUIMMValue(instruction, 0xff);
+ else
+ PushUIMMValue(instruction, 0xffff);
+ }
+ else
+ {
+ PushRegister(instruction, PPC_OP_REG_RS, Gpr(rx));
+ }
+
+ break;
+
+ case PPC_ID_VLE_SE_NEG:
+ case PPC_ID_VLE_SE_NOT:
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(rx));
+ if (translate)
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(rx));
+
+ break;
+
+ case PPC_ID_VLE_SE_MFCTR:
+ case PPC_ID_VLE_SE_MFLR:
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(rx));
+ break;
+
+ case PPC_ID_VLE_SE_MTCTR:
+ case PPC_ID_VLE_SE_MTLR:
+ PushRegister(instruction, PPC_OP_REG_RS, Gpr(rx));
+ break;
+
+ // <op> rX,UI5
+ case PPC_ID_VLE_SE_ANDI:
+ case PPC_ID_VLE_SE_SLWI:
+ case PPC_ID_VLE_SE_SRAWI:
+ case PPC_ID_VLE_SE_SRWI:
+ {
+ uint16_t ui5 = (word16 >> 4) & 0x1f;
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(rx));
+ if (translate)
+ PushRegister(instruction, PPC_OP_REG_RS, Gpr(rx));
+
+ PushUIMMValue(instruction, ui5);
+
+ break;
+ }
+
+ case PPC_ID_VLE_SE_CMPI:
+ {
+ uint16_t ui5 = (word16 >> 4) & 0x1f;
+ if (translate)
+ PushRegister(instruction, PPC_OP_REG_CRFD_IMPLY0, Crf(0));
+
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(rx));
+ PushUIMMValue(instruction, ui5);
+ break;
+ }
+
+ // <op> rX, OIMM (no rc)
+ case PPC_ID_VLE_SE_ADDI:
+ {
+ uint32_t oim5 = (word16 >> 4) & 0x1f;
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(rx));
+
+ if (translate)
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(rx));
+
+ PushSIMMValue(instruction, oim5 + 1);
+ break;
+ }
+
+ // <op> rX, OIMM (no rc)
+ case PPC_ID_VLE_SE_CMPLI:
+ {
+ uint32_t oim5 = (word16 >> 4) & 0x1f;
+ if (translate)
+ PushRegister(instruction, PPC_OP_REG_CRFD_IMPLY0, Crf(0));
+
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(rx));
+ PushUIMMValue(instruction, oim5 + 1);
+ break;
+ }
+
+ // <op> rX, OIMM (rc)
+ case PPC_ID_VLE_SE_SUBIx:
+ {
+ uint32_t oim5 = (word16 >> 4) & 0x1f;
+ uint32_t imm5 = oim5 + 1;
+ bool rc = (word16 >> 9) & 0x1;
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(rx));
+ if (translate)
+ {
+ // In non-VLE, SUBI is a pseudo-op for ADDI with
+ // a negative value
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(rx));
+ PushSIMMValue(instruction, -((int32_t)imm5));
+ }
+ else
+ {
+ PushSIMMValue(instruction, imm5);
+ }
+ instruction->flags.rc = rc;
+ break;
+ }
+
+ // <op>[l]
+ case PPC_ID_VLE_SE_BCTRx:
+ case PPC_ID_VLE_SE_BLRx:
+ instruction->flags.lk = word16 & 0x1;
+ break;
+
+ // one-off
+ case PPC_ID_VLE_SE_Bx:
+ {
+ bool lk = (word16 >> 8) & 0x1;
+ uint16_t bd8 = word16 & 0xff;
+
+ instruction->flags.lk = lk;
+ uint64_t target = address + (int32_t)sign_extend(bd8 << 1, 9);
+ PushLabel(instruction, target);
+ break;
+ }
+
+ case PPC_ID_VLE_SE_BC:
+ {
+ uint16_t bo16 = (word16 >> 10) & 0x1;
+ uint16_t bi16 = (word16 >> 8) & 0x3;
+ uint16_t bd8 = word16 & 0xff;
+
+ if (translate)
+ {
+ // VLEPEM Table 2-6: BO16 Field Encodings
+ // 0 --> branch if condition false
+ // 1 --> branch if condition true
+ //
+ // PowerPC programming environments 8-7: BO Operand Encodings
+ // (relevant excerpt)
+ // 001zy --> branch if condition false
+ // 011zy --> branch if condition true
+ //
+ // VLE doesn't encode hints, so we just map to encodings
+ // with z and y equal to 0
+ uint32_t mapped_bo;
+
+ switch (bo16) {
+ case 0: mapped_bo = 0x04; break;
+ case 1: mapped_bo = 0x0c; break;
+ default:
+ // should be unreachable
+ mapped_bo = 0; // only to silence compiler warning
+ }
+
+ PushUIMMValue(instruction, mapped_bo);
+ }
+ else
+ {
+ PushUIMMValue(instruction, bo16);
+ }
+ PushUIMMValue(instruction, bi16);
+
+ uint64_t target = address + (int32_t)sign_extend(bd8 << 1, 9);
+ PushLabel(instruction, target);
+ break;
+ }
+
+ case PPC_ID_VLE_SE_BCLRI:
+ {
+ // --> PPC_ID_ANDI
+ uint16_t ui5 = (word16 >> 4) & 0x1f;
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(rx));
+ if (translate)
+ {
+ PushRegister(instruction, PPC_OP_REG_RS, Gpr(rx));
+ PushUIMMValue(instruction, ~(1 << ui5));
+ }
+ else
+ {
+ PushUIMMValue(instruction, ui5);
+ }
+ break;
+ }
+
+ case PPC_ID_VLE_SE_BGENI:
+ {
+ // --> PPC_ID_LI
+ uint16_t ui5 = (word16 >> 4) & 0x1f;
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(rx));
+ if (translate)
+ {
+ uint32_t value = (1ul << ui5);
+ PushUIMMValue(instruction, value);
+ }
+ else
+ {
+ PushUIMMValue(instruction, ui5);
+ }
+
+ break;
+ }
+
+ case PPC_ID_VLE_SE_BMASKI:
+ {
+ // --> PPC_ID_LI
+ uint16_t ui5 = (word16 >> 4) & 0x1f;
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(rx));
+ if (translate)
+ {
+ uint32_t value = ~(1ul << ui5);
+ PushUIMMValue(instruction, value);
+ }
+ else
+ {
+ PushUIMMValue(instruction, ui5);
+ }
+ break;
+ }
+
+ case PPC_ID_VLE_SE_BSETI:
+ {
+ // --> PPC_ID_ORI
+ uint16_t ui5 = (word16 >> 4) & 0x1f;
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(rx));
+ if (translate)
+ {
+ uint32_t value = 1ul << ui5;
+ PushRegister(instruction, PPC_OP_REG_RS, Gpr(rx));
+ PushUIMMValue(instruction, value);
+ }
+ else
+ {
+ PushUIMMValue(instruction, ui5);
+ }
+ break;
+ }
+
+ case PPC_ID_VLE_SE_BTSTI:
+ {
+ // This instruction isn't expressible in standard powerpc,
+ // so we don't bother trying to convert it to anything
+ uint16_t ui5 = (word16 >> 4) & 0x1f;
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(rx));
+ PushUIMMValue(instruction, ui5);
+ break;
+ }
+
+ // NOTE: LBZ, LHZ, and LWZ in VLE don't turn rX=0 into 0
+ case PPC_ID_VLE_SE_LBZ:
+ {
+ uint32_t sd4 = (word16 >> 8) & 0xf;
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(rz));
+ PushMem(instruction, PPC_OP_MEM_RA, Gpr(rx), (int32_t)sd4);
+ break;
+ }
+
+ case PPC_ID_VLE_SE_LHZ:
+ {
+ uint32_t sd4 = ((word16 >> 8) & 0xf) * 2;
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(rz));
+ PushMem(instruction, PPC_OP_MEM_RA, Gpr(rx), (int32_t)sd4);
+ break;
+ }
+
+ case PPC_ID_VLE_SE_LI:
+ {
+ uint32_t ui7 = (word16 >> 4) & 0x7f;
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(rx));
+ PushUIMMValue(instruction, ui7);
+ break;
+ }
+
+ case PPC_ID_VLE_SE_LWZ:
+ {
+ uint32_t sd4 = ((word16 >> 8) & 0xf) * 4;
+ PushRegister(instruction, PPC_OP_REG_RD, Gpr(rz));
+ PushMem(instruction, PPC_OP_MEM_RA, Gpr(rx), (int32_t)sd4);
+ break;
+ }
+
+ case PPC_ID_VLE_SE_MFAR:
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(rx));
+ PushRegister(instruction, PPC_OP_REG_RS, Gpr(8 + ry));
+ break;
+
+ case PPC_ID_VLE_SE_MTAR:
+ PushRegister(instruction, PPC_OP_REG_RA, Gpr(8 + rx));
+ PushRegister(instruction, PPC_OP_REG_RS, Gpr(ry));
+ break;
+
+ // NOTE: STB, STH, and STW in VLE don't turn rX=0 into 0
+ case PPC_ID_VLE_SE_STB:
+ {
+ uint32_t sd4 = (word16 >> 8) & 0xf;
+ PushRegister(instruction, PPC_OP_REG_RS, Gpr(rz));
+ PushMem(instruction, PPC_OP_MEM_RA, Gpr(rx), (int32_t)sd4);
+ break;
+ }
+
+ case PPC_ID_VLE_SE_STH:
+ {
+ uint32_t sd4 = ((word16 >> 8) & 0xf) * 2;
+ PushRegister(instruction, PPC_OP_REG_RS, Gpr(rz));
+ PushMem(instruction, PPC_OP_MEM_RA, Gpr(rx), (int32_t)sd4);
+ break;
+ }
+
+ case PPC_ID_VLE_SE_STW:
+ {
+ uint32_t sd4 = ((word16 >> 8) & 0xf) * 4;
+ PushRegister(instruction, PPC_OP_REG_RS, Gpr(rz));
+ PushMem(instruction, PPC_OP_MEM_RA, Gpr(rx), (int32_t)sd4);
+ break;
+ }
+
+ default:
+ ;
+ }
+}
+
+bool Decompose16Vle(Instruction* instruction, uint16_t word16, uint64_t address, uint32_t flags)
+{
+ memset(instruction, 0, sizeof *instruction);
+ instruction->id = Decode16Vle(word16, flags);
+ if (instruction->id == PPC_ID_INVALID)
+ return false;
+
+ bool translate = (flags & DECODE_FLAGS_VLE_TRANSLATE) != 0;
+ FillOperands16Vle(instruction, word16, address, translate);
+ if (translate)
+ instruction->id = VleTranslateMnemonic(instruction->id);
+
+ return true;
+}
+
+void FillVle16BcOperands(OperandsList *se_bc, const Instruction *instruction)
+{
+ memset(se_bc, 0, sizeof *se_bc);
+
+ if (instruction->id != PPC_ID_VLE_SE_BC)
+ return;
+
+ // se_bc only looks at CR0
+ se_bc->operands[0].cls = PPC_OP_REG_CRFS_IMPLY0;
+ se_bc->operands[0].reg = Crf(0);
+ se_bc->numOperands = 1;
+}
diff --git a/arch/powerpc/decode/vle32.c b/arch/powerpc/decode/vle32.c
new file mode 100644
index 00000000..7f87689d
--- /dev/null
+++ b/arch/powerpc/decode/vle32.c
@@ -0,0 +1,715 @@
+#include <string.h>
+
+#include "decode.h"
+#include "priv.h"
+
+void PushMemRA8(Instruction* instruction, uint32_t word32)
+{
+ int32_t offset = (int32_t)((int8_t)(word32 & 0xff));
+ PushMem(instruction, PPC_OP_MEM_RA, Gpr(GetA(word32)), offset);
+}
+
+static InstructionId Decode32Vle0x06(uint32_t word32, uint32_t decodeFlags)
+{
+ uint32_t subop = (word32 >> 12) & 0xf;
+ switch (subop)
+ {
+ case 0x8:
+ return PPC_ID_VLE_E_ADDIx;
+
+ case 0x9:
+ return PPC_ID_VLE_E_ADDIx;
+
+ case 0xb:
+ return PPC_ID_VLE_E_SUBFICx;
+
+ case 0xc:
+ return PPC_ID_VLE_E_ANDIx;
+
+ case 0xd:
+ return PPC_ID_VLE_E_ORIx;
+
+ case 0xe:
+ return PPC_ID_VLE_E_XORIx;
+
+ default:
+ ;
+ }
+
+ subop = (word32 >> 11) & 0x1f;
+ switch (subop)
+ {
+ case 0x14:
+ return PPC_ID_VLE_E_MULLI;
+
+ case 0x15:
+ {
+ uint32_t subsubop = ((word32 >> 23) & 0x7);
+ switch (subsubop)
+ {
+ case 0:
+ return PPC_ID_VLE_E_CMPI;
+
+ case 1:
+ return PPC_ID_VLE_E_CMPLI;
+
+ default:
+ ;
+ }
+ }
+
+ default:
+ ;
+ }
+
+ subop = (word32 >> 8) & 0xff;
+ switch (subop)
+ {
+ case 0x00:
+ return PPC_ID_VLE_E_LBZU;
+
+ case 0x01:
+ return PPC_ID_VLE_E_LHZU;
+
+ case 0x02:
+ return PPC_ID_VLE_E_LWZU;
+
+ case 0x03:
+ return PPC_ID_VLE_E_LHAU;
+
+ case 0x04:
+ return PPC_ID_VLE_E_STBU;
+
+ case 0x05:
+ return PPC_ID_VLE_E_STHU;
+
+ case 0x06:
+ return PPC_ID_VLE_E_STWU;
+
+ case 0x08:
+ return PPC_ID_VLE_E_LMW;
+
+ case 0x09:
+ return PPC_ID_VLE_E_STMW;
+
+ case 0x10:
+ {
+ uint32_t subsubop = (word32 >> 21) & 0x1f;
+ switch (subsubop)
+ {
+ case 0: return PPC_ID_VLE_E_LDVGPRW;
+ case 1: return PPC_ID_VLE_E_LDVSPRW;
+ case 4: return PPC_ID_VLE_E_LDVSRRW;
+ case 5: return PPC_ID_VLE_E_LDVCSRRW;
+ case 6: return PPC_ID_VLE_E_LDVDSRRW;
+ default: return PPC_ID_INVALID;
+ }
+ }
+
+ case 0x11:
+ {
+ uint32_t subsubop = (word32 >> 21) & 0x1f;
+ switch (subsubop)
+ {
+ case 0: return PPC_ID_VLE_E_STMVGPRW;
+ case 1: return PPC_ID_VLE_E_STMVSPRW;
+ case 4: return PPC_ID_VLE_E_STMVSRRW;
+ case 5: return PPC_ID_VLE_E_STMVCSRRW;
+ case 6: return PPC_ID_VLE_E_STMVDSRRW;
+ default: return PPC_ID_INVALID;
+ }
+ }
+
+ default:
+ return PPC_ID_INVALID;
+ }
+}
+
+static InstructionId Decode32Vle0x1C(uint32_t word32, uint32_t decodeFlags)
+{
+ uint32_t subop = (word32 >> 15) & 0x1;
+ if (subop == 0)
+ return PPC_ID_VLE_E_LI;
+
+ subop = (word32 >> 11) & 0x1f;
+ switch (subop)
+ {
+ case 0x11:
+ return PPC_ID_VLE_E_ADD2I;
+
+ case 0x12:
+ return PPC_ID_VLE_E_ADD2IS;
+
+ case 0x13:
+ return PPC_ID_VLE_E_CMP16I;
+
+ case 0x14:
+ return PPC_ID_VLE_E_MULL2I;
+
+ case 0x15:
+ return PPC_ID_VLE_E_CMPL16I;
+
+ case 0x16:
+ return PPC_ID_VLE_E_CMPH16I;
+
+ case 0x17:
+ return PPC_ID_VLE_E_CMPHL16I;
+
+ case 0x18:
+ return PPC_ID_VLE_E_OR2I;
+
+ case 0x19:
+ return PPC_ID_VLE_E_AND2I;
+
+ case 0x1a:
+ return PPC_ID_VLE_E_OR2IS;
+
+ case 0x1c:
+ return PPC_ID_VLE_E_LIS;
+
+ case 0x1d:
+ return PPC_ID_VLE_E_AND2IS;
+
+ default:
+ return PPC_ID_INVALID;
+ }
+}
+
+static InstructionId Decode32Vle0x1F(uint32_t word32, uint32_t decodeFlags)
+{
+ uint32_t subop = word32 & 0x7ff;
+ switch (subop)
+ {
+ // There are a handful of VLE-specific instructions for this
+ // primary opcode, but the rest are standard
+ case 0x020:
+ return PPC_ID_VLE_E_MCRF;
+
+ case 0x042:
+ return PPC_ID_VLE_E_CRNOR;
+
+ case 0x05c:
+ if ((word32 & 0x00600000) == 0)
+ return PPC_ID_INVALID;
+ else
+ return PPC_ID_VLE_E_CMPHL;
+
+ case 0x070:
+ case 0x071:
+ return PPC_ID_VLE_E_SLWIx;
+
+ case 0x102:
+ return PPC_ID_VLE_E_CRANDC;
+
+ case 0x182:
+ return PPC_ID_VLE_E_CRXOR;
+
+ case 0x1c2:
+ return PPC_ID_VLE_E_CRNAND;
+
+ case 0x202:
+ return PPC_ID_VLE_E_CRAND;
+
+ case 0x230:
+ case 0x231:
+ return PPC_ID_VLE_E_RLWx;
+
+ case 0x242:
+ return PPC_ID_VLE_E_CREQV;
+
+ case 0x270:
+ case 0x271:
+ return PPC_ID_VLE_E_RLWIx;
+
+ case 0x342:
+ return PPC_ID_VLE_E_CRORC;
+
+ case 0x382:
+ return PPC_ID_VLE_E_CROR;
+
+ case 0x470:
+ case 0x471:
+ return PPC_ID_VLE_E_SRWIx;
+
+ default:
+ return Decode0x1F(word32, decodeFlags);
+ }
+}
+
+static InstructionId Decode32Vle(uint32_t word32, uint32_t decodeFlags)
+{
+ uint32_t primary = (word32 >> 26) & 0x3f;
+ switch (primary)
+ {
+ // 0x1000_0000
+ case 0x04:
+ // This is the same as non-VLE decoding
+ return Decode0x04(word32, decodeFlags);
+
+ // 0x1800_0000
+ case 0x06:
+ return Decode32Vle0x06(word32, decodeFlags);
+
+ // 0x1c00_0000
+ case 0x07:
+ return PPC_ID_VLE_E_ADD16I;
+
+ // 0x3000_0000
+ case 0x0c:
+ return PPC_ID_VLE_E_LBZ;
+
+ // 0x3400_0000
+ case 0x0d:
+ return PPC_ID_VLE_E_STB;
+
+ // 0x3800_0000
+ case 0x0e:
+ return PPC_ID_VLE_E_LHA;
+
+ // 0x5000_0000
+ case 0x14:
+ return PPC_ID_VLE_E_LWZ;
+
+ // 0x5400_0000
+ case 0x15:
+ return PPC_ID_VLE_E_STW;
+
+ // 0x5800_0000
+ case 0x16:
+ return PPC_ID_VLE_E_LHZ;
+
+ // 0x5c00_0000
+ case 0x17:
+ return PPC_ID_VLE_E_STH;
+
+ // 0x7000_0000
+ case 0x1c:
+ return Decode32Vle0x1C(word32, decodeFlags);
+
+ // 0x7400_0000
+ case 0x1d:
+ if ((word32 & 0x1) == 0)
+ return PPC_ID_VLE_E_RLWIMI;
+ else
+ return PPC_ID_VLE_E_RLWINM;
+
+ // 0x7800_0000
+ case 0x1e:
+ if ((word32 & 0x02000000) == 0)
+ return PPC_ID_VLE_E_Bx;
+ else if ((word32 & 0xffc00000) == 0x7a000000)
+ return PPC_ID_VLE_E_BCx;
+ else
+ return PPC_ID_INVALID;
+
+ // 0x7c00_0000
+ case 0x1f:
+ return Decode32Vle0x1F(word32, decodeFlags);
+
+ default:
+ return PPC_ID_INVALID;
+ }
+}
+
+static uint32_t ComputeSCI8(uint32_t word32) {
+ unsigned int scl = (word32 >> 8) & 0x3;
+ unsigned int shift = 8*scl;
+ uint32_t ui8 = word32 & 0xff;
+ bool f = (word32 >> 10) & 0x1;
+
+ uint32_t imm_value = f ? 0xffffffff : 0;
+ imm_value &= ~(0xfful << shift);
+ imm_value |= (ui8 << shift);
+
+ return imm_value;
+}
+
+static void FillOperands32Vle(Instruction* instruction, uint32_t word32, uint64_t address, bool translate)
+{
+ uint16_t ui0_4 = (word32 >> 16) & 0x1f;
+ uint16_t ui5_15 = word32 & 0x7ff;
+ uint32_t ui_split16 = (ui0_4 << 11) | ui5_15;
+ int32_t si_split16 = (int32_t)(int16_t)(uint16_t)(ui_split16);
+
+ // Surprisingly (or maybe not surprisingly), PowerPC throws us a bone
+ // and puts registers in the same bit locations that they are in normal
+ // PowerPC
+
+ switch (instruction->id) {
+ // <op>[.] rD, rA, SCI8
+ case PPC_ID_VLE_E_ADDIx:
+ case PPC_ID_VLE_E_ADDICx:
+ case PPC_ID_VLE_E_SUBFICx:
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushSIMMValue(instruction, (int32_t)ComputeSCI8(word32));
+
+ instruction->flags.rc = (word32 >> 11) & 0x1;
+ break;
+
+ // <op> rD, rA, SCI8 (unconditional no-dot)
+ case PPC_ID_VLE_E_MULLI:
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushSIMMValue(instruction, (int32_t)ComputeSCI8(word32));
+
+ break;
+
+ // <op>[.] rA, rS, SCI8
+ case PPC_ID_VLE_E_ANDIx:
+ case PPC_ID_VLE_E_ORIx:
+ case PPC_ID_VLE_E_XORIx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, ComputeSCI8(word32));
+
+ instruction->flags.rc = (word32 >> 11) & 0x1;
+ break;
+
+ case PPC_ID_VLE_E_ADD2I:
+ case PPC_ID_VLE_E_ADD2IS:
+ case PPC_ID_VLE_E_MULL2I:
+ PushRD(instruction, word32);
+ if (translate)
+ PushRA(instruction, word32);
+
+ PushSIMMValue(instruction, si_split16);
+ if (instruction->id == PPC_ID_VLE_E_ADD2I)
+ instruction->flags.rc = true;
+ break;
+
+ // <op>_2i rD, UI
+ case PPC_ID_VLE_E_AND2I:
+ case PPC_ID_VLE_E_AND2IS:
+ case PPC_ID_VLE_E_OR2I:
+ case PPC_ID_VLE_E_OR2IS:
+ {
+ uint32_t ui5_15 = word32 & 0x7ff;
+ uint32_t ui0_4 = (word32 >> 16) & 0xf;
+ uint32_t ui = (ui0_4 << 11) | ui5_15;
+
+ PushRA(instruction, word32);
+ if (translate)
+ PushRS(instruction, word32);
+
+ PushUIMMValue(instruction, ui);
+ if ((instruction->id == PPC_ID_VLE_E_AND2I) || (instruction->id == PPC_ID_VLE_E_AND2IS))
+ instruction->flags.rc = true;
+ break;
+ }
+
+ // <op>[.] rA, rS, SH
+ case PPC_ID_VLE_E_RLWIx:
+ case PPC_ID_VLE_E_SLWIx:
+ case PPC_ID_VLE_E_SRWIx:
+ {
+ uint32_t sh = (word32 >> 11) & 0x1f;
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, sh);
+ instruction->flags.rc = word32 & 0x1;
+ break;
+ }
+
+ // <op> crbD, crbA, crbB
+ case PPC_ID_VLE_E_CRAND:
+ case PPC_ID_VLE_E_CRANDC:
+ case PPC_ID_VLE_E_CREQV:
+ case PPC_ID_VLE_E_CRNAND:
+ case PPC_ID_VLE_E_CRNOR:
+ case PPC_ID_VLE_E_CROR:
+ case PPC_ID_VLE_E_CRORC:
+ case PPC_ID_VLE_E_CRXOR:
+ PushCRBitD(instruction, word32);
+ PushCRBitA(instruction, word32);
+ PushCRBitB(instruction, word32);
+ break;
+
+ // loads
+ case PPC_ID_VLE_E_LBZ:
+ case PPC_ID_VLE_E_LHA:
+ case PPC_ID_VLE_E_LHZ:
+ case PPC_ID_VLE_E_LWZ:
+ PushRD(instruction, word32);
+ PushMemRA(instruction, word32);
+ break;
+
+ // loads with update/load multiple
+ case PPC_ID_VLE_E_LBZU:
+ case PPC_ID_VLE_E_LHAU:
+ case PPC_ID_VLE_E_LHZU:
+ case PPC_ID_VLE_E_LWZU:
+ case PPC_ID_VLE_E_LMW:
+ PushRD(instruction, word32);
+ PushMemRA8(instruction, word32);
+ break;
+
+ // stores
+ case PPC_ID_VLE_E_STB:
+ case PPC_ID_VLE_E_STH:
+ case PPC_ID_VLE_E_STW:
+ PushRS(instruction, word32);
+ PushMemRA(instruction, word32);
+ break;
+
+ // stores with update/store multiple
+ case PPC_ID_VLE_E_STBU:
+ case PPC_ID_VLE_E_STHU:
+ case PPC_ID_VLE_E_STMW:
+ case PPC_ID_VLE_E_STWU:
+ PushRS(instruction, word32);
+ PushMemRA8(instruction, word32);
+ break;
+
+ // vector loads/stores
+ case PPC_ID_VLE_E_LDVGPRW:
+ case PPC_ID_VLE_E_LDVSPRW:
+ case PPC_ID_VLE_E_LDVSRRW:
+ case PPC_ID_VLE_E_LDVCSRRW:
+ case PPC_ID_VLE_E_LDVDSRRW:
+ case PPC_ID_VLE_E_STMVGPRW:
+ case PPC_ID_VLE_E_STMVSPRW:
+ case PPC_ID_VLE_E_STMVSRRW:
+ case PPC_ID_VLE_E_STMVCSRRW:
+ case PPC_ID_VLE_E_STMVDSRRW:
+ PushMemRA8(instruction, word32);
+ break;
+
+ // <op> rA, rS, SH, MB, ME
+ case PPC_ID_VLE_E_RLWIMI:
+ case PPC_ID_VLE_E_RLWINM:
+ {
+ uint32_t sh = (word32 >> 11) & 0x1f;
+ uint32_t mb = (word32 >> 6) & 0x1f;
+ uint32_t me = (word32 >> 1) & 0x1f;
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushUIMMValue(instruction, sh);
+ PushUIMMValue(instruction, mb);
+ PushUIMMValue(instruction, me);
+ break;
+ }
+
+ // <op>_16i rA, SI
+ case PPC_ID_VLE_E_CMP16I:
+ case PPC_ID_VLE_E_CMPH16I:
+ if (translate)
+ PushRegister(instruction, PPC_OP_REG_CRFD_IMPLY0, Crf(0));
+
+ PushRA(instruction, word32);
+ PushSIMMValue(instruction, si_split16);
+ break;
+
+ // <op>_16i rA, UI
+ case PPC_ID_VLE_E_CMPL16I:
+ case PPC_ID_VLE_E_CMPHL16I:
+ if (translate)
+ PushRegister(instruction, PPC_OP_REG_CRFD_IMPLY0, Crf(0));
+
+ PushRA(instruction, word32);
+ PushUIMMValue(instruction, ui_split16);
+ break;
+
+ // one-off
+ case PPC_ID_VLE_E_ADD16I:
+ {
+ int16_t si = (int16_t)(uint16_t)(word32 & 0xffff);
+ PushRD(instruction, word32);
+ PushRA(instruction, word32);
+ PushSIMMValue(instruction, si);
+ break;
+ }
+
+ case PPC_ID_VLE_E_Bx:
+ {
+ uint32_t bd24 = word32 & 0x01fffffe;
+ uint64_t target = address + (int64_t)sign_extend(bd24, 24);
+ PushLabel(instruction, target);
+ instruction->flags.lk = word32 & 0x1;
+ break;
+ }
+
+ case PPC_ID_VLE_E_BCx:
+ {
+ uint32_t bo32 = (word32 >> 20) & 0x3;
+ uint32_t bi32 = (word32 >> 16) & 0xf;
+ uint32_t bd15 = word32 & 0xfffe;
+
+ if (translate)
+ {
+ // VLEPEM Table 2-5: BO32 Field Encodings
+ // 00 --> branch if condition false
+ // 01 --> branch if condition true
+ // 10 --> decrement CTR, branch if CTR!=0
+ // 11 --> decrement CTR, branch if CTR==0
+ //
+ // PowerPC programming environments 8-7: BO Operand Encodings
+ // (relevant excerpt)
+ // 001zy --> branch if condition false
+ // 011zy --> branch if condition true
+ // 1z00y --> decrement CTR, branch if CTR!=0
+ // 1z01y --> decrement CTR, branch if CTR==0
+ //
+ // VLE doesn't encode hints, so we just map to encodings
+ // with z and y equal to 0
+
+ uint32_t mapped_bo = 0;
+ switch (bo32) {
+ case 0: mapped_bo = 0x04; break;
+ case 1: mapped_bo = 0x0c; break;
+ case 2: mapped_bo = 0x10; break;
+ case 3: mapped_bo = 0x12; break;
+ default:
+ // unreachable
+ ;
+ }
+
+ PushUIMMValue(instruction, mapped_bo);
+ }
+ else
+ {
+ PushUIMMValue(instruction, bo32);
+ }
+
+ // BI32 maps to the same as the non-VLE variant, it's
+ // just a more restricted value
+ PushUIMMValue(instruction, bi32);
+ uint64_t target = address + (int64_t)sign_extend(bd15, 15);
+ PushLabel(instruction, target);
+
+ instruction->flags.lk = word32 & 0x1;
+ break;
+ }
+
+ case PPC_ID_VLE_E_CMPI:
+ {
+ // We can't use PushCRFDImplyCR0, since the CRD32 field
+ // is 2 bits instead of 3
+ uint32_t crd32 = ((word32) >> 21) & 0x3;
+ PushRegister(instruction, PPC_OP_REG_CRFD_IMPLY0, Crf(crd32));
+ PushRA(instruction, word32);
+ PushUIMMValue(instruction, (int32_t)ComputeSCI8(word32));
+ break;
+ }
+
+ case PPC_ID_VLE_E_CMPLI:
+ {
+ // We can't use PushCRFDImplyCR0, since the CRD32 field
+ // is 2 bits instead of 3
+ uint32_t crd32 = ((word32) >> 21) & 0x3;
+ PushRegister(instruction, PPC_OP_REG_CRFD_IMPLY0, Crf(crd32));
+ PushRA(instruction, word32);
+ PushUIMMValue(instruction, ComputeSCI8(word32));
+ break;
+ }
+
+ case PPC_ID_VLE_E_CMPHL:
+ PushCRFDImplyCR0(instruction, word32);
+ PushRA(instruction, word32);
+ PushRB(instruction, word32);
+ break;
+
+ case PPC_ID_VLE_E_LI:
+ {
+ uint32_t li20_4_8 = (word32 >> 16) & 0x1f;
+ uint32_t li20_0_3 = (word32 >> 11) & 0xf;
+ uint32_t li20_9_19 = word32 & 0x7ff;
+ uint32_t li20 = (li20_0_3 << 16) | (li20_4_8 << 11) | li20_9_19;
+ int32_t signed_li20 = sign_extend(li20, 20);
+
+ PushRD(instruction, word32);
+ PushSIMMValue(instruction, signed_li20);
+ break;
+ }
+
+ case PPC_ID_VLE_E_LIS:
+ PushRD(instruction, word32);
+ PushUIMMValue(instruction, ui_split16);
+ break;
+
+ case PPC_ID_VLE_E_MCRF:
+ PushCRFD(instruction, word32);
+ PushCRFS(instruction, word32);
+ break;
+
+ case PPC_ID_VLE_E_RLWx:
+ PushRA(instruction, word32);
+ PushRS(instruction, word32);
+ PushRB(instruction, word32);
+ instruction->flags.rc = word32 & 0x1;
+ break;
+
+ default:
+ ;
+ }
+}
+
+bool IsVleInstructionId(InstructionId id)
+{
+ return PPC_ID_VLE_E_ADDIx <= id && id <= PPC_ID_VLE_SE_SUBIx;
+}
+
+bool Decompose32Vle(Instruction* instruction, uint32_t word32, uint64_t address, uint32_t flags)
+{
+ size_t numBytes = instruction->numBytes;
+ memset(instruction, 0, sizeof *instruction);
+ instruction->numBytes = numBytes;
+ instruction->id = Decode32Vle(word32, flags);
+ if (instruction->id == PPC_ID_INVALID)
+ return false;
+
+ if (!IsVleInstructionId(instruction->id))
+ {
+ // Fill operands for instructions that are shared between VLE
+ // and non-VLE
+ FillOperands32(instruction, word32, address);
+ return true;
+ }
+
+ if ((flags & DECODE_FLAGS_VLE_TRANSLATE) != 0)
+ {
+ FillOperands32Vle(instruction, word32, address, true);
+ instruction->id = VleTranslateMnemonic(instruction->id);
+ }
+ else
+ {
+ FillOperands32Vle(instruction, word32, address, false);
+ }
+
+ return true;
+}
+
+void FillVle32BcxOperands(OperandsList *e_bcx, const Instruction *instruction)
+{
+ memset(e_bcx, 0, sizeof *e_bcx);
+
+ if (instruction->id != PPC_ID_VLE_E_BCx)
+ return;
+
+ uint32_t bo = instruction->operands[0].uimm;
+ uint32_t bi = instruction->operands[1].uimm;
+
+ switch (bo)
+ {
+ // Condition is true/false: use crn, copy target
+ case 0:
+ case 1:
+
+ e_bcx->operands[0].cls = PPC_OP_REG_CRFS_IMPLY0;
+ e_bcx->operands[0].reg = Crf(bi >> 2);
+ CopyOperand(&e_bcx->operands[1], &instruction->operands[2]);
+ e_bcx->numOperands = 2;
+ break;
+
+ // Decrement CTR, branch if equal/not to 0: no operands
+ case 2:
+ case 3:
+ CopyOperand(&e_bcx->operands[0], &instruction->operands[2]);
+ e_bcx->numOperands = 1;
+ break;
+
+ default:
+ // unreachable
+ ;
+ }
+}
diff --git a/arch/powerpc/disassembler.cpp b/arch/powerpc/disassembler.cpp
index 2a421971..df444fe8 100644
--- a/arch/powerpc/disassembler.cpp
+++ b/arch/powerpc/disassembler.cpp
@@ -1,358 +1,221 @@
-/******************************************************************************
-See disassembler.h for more information about how this fits into the PPC
-architecture plugin picture.
-******************************************************************************/
+#include <string>
+#include <vector>
-#include <string.h> // strcpy, etc.
+#include "binaryninjaapi.h"
#define MYLOG(...) while(0);
-//#include <binaryninjaapi.h>
-//#define MYLOG BinaryNinja::LogDebug
+// #define MYLOG BinaryNinja::LogWarn
+// #define MYLOG printf
+using namespace std;
+using namespace BinaryNinja; // for ::LogDebug, etc.
+
+#include "decode/decode.h"
#include "disassembler.h"
#include "util.h"
-/* have to do this... while options can be toggled after initialization (thru
- cs_option(), the modes cannot, and endianness is considered a mode) */
-thread_local csh handle_lil = 0;
-thread_local csh handle_big = 0;
-
-int DoesQualifyForLocalDisassembly(const uint8_t *data, bool bigendian)
+bool FillInstruction(Instruction* instruction, const uint8_t* data, size_t length, uint64_t address, uint32_t extraFlags = 0, uint32_t decodeFlags = DECODE_FLAGS_PPC64, BNEndianness endian=LittleEndian)
{
- uint32_t insword = *(uint32_t *)data;
- int result = PPC_INS_INVALID;
- uint32_t tmp = 0;
-
- if(bigendian == true)
- {
- insword = bswap32(insword);
- }
-
- // 111111xxx00xxxxxxxxxx00001000000 <- fcmpo
- tmp = insword & 0xFC6007FF;
- if (tmp==0xFC000040)
- result = PPC_INS_BN_FCMPO;
- // 111100xxxxxxxxxxxxxxx00111010xxx <- xxpermr
- if((insword & 0xFC0007F8) == 0xF00001D0)
- result = PPC_INS_BN_XXPERMR;
-
- return result;
-}
-
-void ppc_fcmpo(uint32_t insword, decomp_result *res)
-{
- unsigned regtmp = 0;
-
- // 111111AAA00BBBBBCCCCC00001000000 "fcmpo crA,fB,fC"
- regtmp = PPC_REG_CR0 + ((insword >> 23) & 7);
- res->detail.ppc.operands[0].reg = (ppc_reg)(regtmp);
- res->detail.ppc.operands[0].type = PPC_OP_REG;
-
- regtmp = PPC_REG_F0 + ((insword >> 16) & 31);
- res->detail.ppc.operands[1].reg = (ppc_reg)(regtmp);
- res->detail.ppc.operands[1].type = PPC_OP_REG;
-
- regtmp = PPC_REG_F0 + ((insword >> 11) & 31);
- res->detail.ppc.operands[2].reg = (ppc_reg)(regtmp);
- res->detail.ppc.operands[2].type = PPC_OP_REG;
-
-
-#ifdef FORCE_TEST
- SStream ss;
- struct cs_struct* handle = 0;
- struct MCInst tempmc = {0};
- char* first_space = 0;
-
- // SStream_Init(&ss);
- ss.index = 0;
- ss.buffer[0] = '\0';
- regtmp = PPC_REG_CR0 + ((insword >> 23) & 7);
- tempmc.Operands[0].MachineOperandType = MCOperand::kRegister;
- tempmc.Operands[0].Kind = 1;
- tempmc.Operands[0].RegVal = regtmp;
- regtmp = PPC_REG_F0 + ((insword >> 16) & 31);
- tempmc.Operands[1].MachineOperandType = MCOperand::kRegister;
- tempmc.Operands[1].Kind = 1;
- tempmc.Operands[1].RegVal = regtmp;
- regtmp = PPC_REG_F0 + ((insword >> 11) & 31);
- tempmc.Operands[2].Kind = 1;
- tempmc.Operands[2].MachineOperandType = MCOperand::kRegister;
- tempmc.Operands[2].RegVal = regtmp;
-
- // temporarily set this so that print processing succeeds
- res->insn.id = PPC_INS_FCMPU;
-
- if (handle_big != 0)
+ instruction->numBytes = length;
+ switch (instruction->numBytes)
{
- handle = (struct cs_struct*)handle_big;
- }
- else if (handle_lil != 0)
+ case 2:
{
- handle = (struct cs_struct*)handle_lil;
- }
-
-#define PPC_FCMPUS 804
-
- tempmc.csh = handle;
- tempmc.Opcode = PPC_FCMPUS;
- tempmc.flat_insn = &res->insn;
- tempmc.flat_insn->detail = &res->detail;
+ uint16_t word16 = *(const uint16_t *) data;
+ // VLE is always big-endian
+ word16 = bswap16(word16);
- if (handle != 0)
- {
- handle->printer(&tempmc, &ss, handle->printer_info);
+ return Decompose16(instruction, word16, address, decodeFlags | extraFlags);
}
- // replace the 'fcmpu' with 'fcmpo'
- first_space = strchr(ss.buffer, ' ');
- strncpy(res->insn.op_str, first_space + 1, sizeof(res->insn.op_str));
-#endif
-
- strncpy(res->insn.mnemonic, "fcmpo", sizeof(res->insn.mnemonic));
-
- // reset this to the target value
- res->insn.id = PPC_INS_BN_FCMPO;
- res->detail.ppc.op_count = 3;
-}
-
-void ppc_xxpermr(uint32_t insword, decomp_result *res)
-{
- // 111100AAAAABBBBBCCCCC00011010BCA "xxpermr vsA,vsB,vsC"
- int a = ((insword & 0x3E00000)>>21)|((insword & 0x1)<<5);
- int b = ((insword & 0x1F0000)>>16)|((insword & 0x4)<<3);
- int c = ((insword & 0xF800)>>11)|((insword & 0x2)<<4);
-
- res->detail.ppc.operands[0].reg = (ppc_reg)(PPC_REG_VS0 + a);
- res->detail.ppc.operands[0].type = PPC_OP_REG;
- res->detail.ppc.operands[1].reg = (ppc_reg)(PPC_REG_VS0 + b);
- res->detail.ppc.operands[1].type = PPC_OP_REG;
- res->detail.ppc.operands[2].reg = (ppc_reg)(PPC_REG_VS0 + c);
- res->detail.ppc.operands[2].type = PPC_OP_REG;
-
- res->insn.id = PPC_INS_BN_XXPERMR;
- res->detail.ppc.op_count = 3;
- strncpy(res->insn.mnemonic, "xxpermr", sizeof(res->insn.mnemonic));
-}
+ case 4:
+ {
+ uint32_t word32 = *(const uint32_t *) data;
-bool PerformLocalDisassembly(const uint8_t *data, uint64_t addr, size_t &len, decomp_result* res, bool bigendian)
-{
- uint32_t local_op = 0;
- uint32_t insword = *(uint32_t *)data;
+ // VLE is always big endian
+ if (((decodeFlags & DECODE_FLAGS_VLE) != 0) || endian == BigEndian)
+ word32 = bswap32(word32);
- if(bigendian == true)
- {
- insword = bswap32(insword);
+ return Decompose32(instruction, word32, address, decodeFlags | extraFlags);
}
- local_op = DoesQualifyForLocalDisassembly(data, bigendian);
-
- switch(local_op)
- {
- case PPC_INS_BN_FCMPO:
- ppc_fcmpo(insword, res);
- break;
- case PPC_INS_BN_XXPERMR:
- ppc_xxpermr(insword, res);
- break;
default:
+ MYLOG("FillInstruction: unrecognized length %d", length);
+ LogWarn("FillInstruction: unrecognized length %d", length);
return false;
}
- return true;
}
-extern "C" int
-powerpc_init(int cs_mode_arg)
+bool PushOperandTokens(string& result, const Operand* op)
{
- int rc = -1;
+ char buf[32];
+ switch (op->cls)
+ {
+ case PPC_OP_REG_CRFD_IMPLY0:
+ case PPC_OP_REG_CRFS_IMPLY0:
+ if (op->reg == PPC_REG_CRF0)
+ return false;
- MYLOG("powerpc_init()\n");
+ result += PowerPCRegisterName(op->reg);
- if(handle_lil || handle_big) {
- MYLOG("ERROR: already initialized!\n");
- goto cleanup;
- }
+ break;
- /* initialize capstone handle */
- if(cs_open(CS_ARCH_PPC, (cs_mode)((int)CS_MODE_BIG_ENDIAN | cs_mode_arg), &handle_big) != CS_ERR_OK) {
- MYLOG("ERROR: cs_open()\n");
- goto cleanup;
- }
+ case PPC_OP_REG_RA:
+ case PPC_OP_REG_RB:
+ case PPC_OP_REG_RD:
+ case PPC_OP_REG_RS:
+ case PPC_OP_REG_FRA:
+ case PPC_OP_REG_FRB:
+ case PPC_OP_REG_FRC:
+ case PPC_OP_REG_FRD:
+ case PPC_OP_REG_FRS:
+ case PPC_OP_REG_CRFD:
+ case PPC_OP_REG_CRFS:
+ case PPC_OP_REG_AV_VA:
+ case PPC_OP_REG_AV_VB:
+ case PPC_OP_REG_AV_VC:
+ case PPC_OP_REG_AV_VD:
+ case PPC_OP_REG_AV_VS:
+ case PPC_OP_REG_VSX_RA:
+ case PPC_OP_REG_VSX_RA_DWORD0:
+ case PPC_OP_REG_VSX_RB:
+ case PPC_OP_REG_VSX_RB_DWORD0:
+ case PPC_OP_REG_VSX_RC:
+ case PPC_OP_REG_VSX_RC_DWORD0:
+ case PPC_OP_REG_VSX_RD:
+ case PPC_OP_REG_VSX_RD_DWORD0:
+ case PPC_OP_REG_VSX_RS:
+ case PPC_OP_REG_VSX_RS_DWORD0:
+ result += PowerPCRegisterName(op->reg);
+ break;
- if(cs_open(CS_ARCH_PPC, (cs_mode)((int)CS_MODE_LITTLE_ENDIAN | cs_mode_arg), &handle_lil) != CS_ERR_OK) {
- MYLOG("ERROR: cs_open()\n");
- goto cleanup;
- }
+ case PPC_OP_UIMM:
+ snprintf(buf, sizeof(buf), "0x%" PRIx64, op->uimm);
+ result += buf;
+ break;
- cs_option(handle_big, CS_OPT_DETAIL, CS_OPT_ON);
- cs_option(handle_lil, CS_OPT_DETAIL, CS_OPT_ON);
+ case PPC_OP_SIMM:
+ if (op->simm < 0 && op->simm > -0x10000)
+ snprintf(buf, sizeof(buf), "-0x%llx", -op->simm);
+ else
+ snprintf(buf, sizeof(buf), "0x%llx", op->simm);
+ result += buf;
+ break;
- rc = 0;
- cleanup:
- if(rc) {
- powerpc_release();
- }
+ case PPC_OP_LABEL:
+ snprintf(buf, sizeof(buf), "0x%llx", op->label);
+ result += buf;
+ break;
- return rc;
-}
+ case PPC_OP_CRBIT_A:
+ case PPC_OP_CRBIT_B:
+ case PPC_OP_CRBIT_D:
+ result += GetCRBitName(op->crbit);
+ break;
-extern "C" void
-powerpc_release(void)
-{
- if(handle_lil) {
- cs_close(&handle_lil);
- handle_lil = 0;
- }
+ case PPC_OP_MEM_RA:
+ // eg: lwz r11, 8(r11)
+ //
+ // TODO: it would be nice to have the option to print these
+ // in hex; printed in decimal now for backwards compatibility
+ snprintf(buf, sizeof(buf), "%d", op->mem.offset);
+ result += buf;
+
+ result += "(";
+ if (op->mem.reg == PPC_REG_GPR0)
+ result += "0";
+ else
+ result += PowerPCRegisterName(op->mem.reg);
+ result += ")";
+ break;
- if(handle_big) {
- cs_close(&handle_big);
- handle_big = 0;
+ default:
+ //MYLOG("pushing a ???\n");
+ result += "???";
}
+
+ return true;
}
-extern "C" int
-powerpc_decompose(const uint8_t *data, int size, uint64_t addr, bool lil_end,
- struct decomp_result *res, bool is_64bit, int cs_mode_arg)
+int disassemble(uint8_t *data, uint32_t addr, string& result)
{
int rc = -1;
- res->status = STATUS_ERROR_UNSPEC;
-
- if(!handle_lil) {
- powerpc_init(cs_mode_arg);
- }
-
- //typedef struct cs_insn {
- // unsigned int id; /* see capstone/ppc.h for PPC_INS_ADD, etc. */
- // uint64_t address;
- // uint16_t size;
- // uint8_t bytes[16];
- // char mnemonic[32]; /* string */
- // char op_str[160]; /* string */
- // cs_detail *detail; /* need CS_OP_DETAIL ON and CS_OP_SKIPDATA is OFF */
- //} cs_insn;
- // where cs_detail is some details + architecture specific part
- // typedef struct cs_detail {
- // uint8_t regs_read[12];
- // uint8_t regs_read_count;
- // uint8_t regs_write;
- // uint8_t regs_write_count;
- // uint8_t groups[8];
- // uint8_t groups_count;
- // cs_ppc *ppc;
- // }
+ char buf[32];
+ size_t strlenMnem;
+ Instruction instruction;
+ const char* mnemonic = NULL;
+ size_t len = 4;
+ uint32_t decodeFlags = DECODE_FLAGS_PPC64;
- // and finally ppc is:
- // typedef struct cs_ppc {
- // ppc_bc bc; /* branch code, see capstone/ppc.h for PPC_BC_LT, etc. */
- // ppc_bh bh; /* branch hint, see capstone/ppc.h for PPC_BH_PLUS, etc. */
- // bool update_cr0;
- // uint8_t op_count;
- // cs_ppc_op operands[8];
- // } cs_ppc;
-
- // and each operand is:
- // typedef struct cs_ppc_op {
- // ppc_op_type type; /* see capstone/ppc.h for PPC_OP_REG, etc. */
- // union {
- // unsigned int reg; // register value for REG operand
- // int32_t imm; // immediate value for IMM operand
- // ppc_op_mem mem; // struct ppc_op_mem { uint base; int disp }
- // ppc_op_crx crx; // struct ppc_op_crx { uint scale, uint reg }
- // };
- // } cs_ppc_op;
-
- csh handle;
- struct cs_struct *hand_tmp = 0;
- cs_insn *insn = 0; /* instruction information
- cs_disasm() will allocate array of cs_insn here */
-
- /* which handle to use?
- BIG end or LITTLE end? */
- handle = handle_big;
- if(lil_end) handle = handle_lil;
- res->handle = handle;
-
- hand_tmp = (struct cs_struct *)handle;
- hand_tmp->mode = (cs_mode)((int)hand_tmp->mode | cs_mode_arg);
-
- /* call */
- size_t n = cs_disasm(handle, data, size, addr, 1, &insn);
- if(n != 1) {
- MYLOG("ERROR: cs_disasm() returned %" PRIdPTR " (cs_errno:%d)\n", n, cs_errno(handle));
- goto cleanup;
+ //MYLOG("%s()\n", __func__);
+ size_t instructionLength = GetInstructionLength(data, len, decodeFlags);
+ if (instructionLength == 0)
+ {
+ MYLOG("ERROR: not enough bytes for instruction\n");
+ return false;
}
- /* set the status */
- res->status = STATUS_SUCCESS;
-
- /* copy the instruction struct, and detail sub struct to result */
- memcpy(&(res->insn), insn, sizeof(cs_insn));
- memcpy(&(res->detail), insn->detail, sizeof(cs_detail));
-
- rc = 0;
- cleanup:
- if(insn) {
- cs_free(insn, 1);
- insn = 0;
+ len = instructionLength;
+ if (!FillInstruction(&instruction, data, instructionLength, addr))
+ {
+ MYLOG("ERROR: FillInstruction()\n");
+ return -1;
}
- return rc;
-}
-extern "C" int
-powerpc_disassemble(struct decomp_result *res, char *buf, size_t len)
-{
- /* ideally the "heavy" string disassemble result is derived from light data
- in the decomposition result, but capstone doesn't make this distinction */
- int rc = -1;
+ /* mnemonic */
+ mnemonic = GetMnemonic(&instruction);
- if(len < strlen(res->insn.mnemonic)+strlen(res->insn.op_str) + 2) {
- MYLOG("ERROR: insufficient room\n");
- goto cleanup;
- }
+ result = mnemonic;
+ if (instruction.numOperands > 0)
+ result += " ";
- strcpy(buf, res->insn.mnemonic);
- strcat(buf, " ");
- strcat(buf, res->insn.op_str);
+ OperandsList operand_list;
+ memset(&operand_list, 0, sizeof(operand_list));
- rc = 0;
- cleanup:
- return rc;
-}
+ // The default is to just copy every operand, to simplify the
+ // alternate code path for special cases
+ operand_list.numOperands = instruction.numOperands;
+ for (int i = 0; i < instruction.numOperands; ++i)
+ {
+ operand_list.operands[i] = instruction.operands[i];
+ }
-static const char* const gqr_array[] = {"gqr0", "gqr1", "gqr2", "gqr3", "gqr4", "gqr5", "gqr6", "gqr7"};
+ switch(instruction.id)
+ {
+ case PPC_ID_BCx:
+ FillBcxOperands(&operand_list, &instruction);
+ break;
+ case PPC_ID_BCCTRx:
+ FillBcctrxOperands(&operand_list, &instruction);
+ break;
+ case PPC_ID_BCLRx:
+ FillBclrxOperands(&operand_list, &instruction);
+ break;
+ case PPC_ID_VLE_SE_BC:
+ FillVle16BcOperands(&operand_list, &instruction);
+ break;
+ case PPC_ID_VLE_E_BCx:
+ FillVle32BcxOperands(&operand_list, &instruction);
+ break;
+ default:
+ // Already copied by default
+ ;
+ }
-extern "C" const char *
-powerpc_reg_to_str(uint32_t rid, int cs_mode_arg)
-{
- if ((cs_mode_arg & CS_MODE_PS) != 0)
+ for (int i = 0; i < operand_list.numOperands; ++i)
{
- if ((rid >= PPC_REG_BN_GQR0) && (rid < PPC_REG_BN_ENDING))
+ Operand* op = &(operand_list.operands[i]);
+ bool was_pushed = PushOperandTokens(result, op);
+
+ if (was_pushed && i < operand_list.numOperands - 1)
{
- return gqr_array[rid - PPC_REG_BN_GQR0];
+ //MYLOG("pushing a comma\n");
+ result += ", ";
}
}
-
- if(!handle_lil) {
- powerpc_init(cs_mode_arg);
- }
-
- return cs_reg_name(handle_lil, rid);
-}
-
-extern "C" const uint32_t
-powerpc_crx_to_reg(uint32_t rid)
-{
- if (rid >= PPC_REG_CR0EQ && rid <= PPC_REG_CR7EQ)
- return (rid - PPC_REG_CR0EQ) * 4 + 2;
- else if (rid >= PPC_REG_CR0GT && rid <= PPC_REG_CR7GT)
- return (rid - PPC_REG_CR0GT) * 4 + 1;
- else if (rid >= PPC_REG_CR0LT && rid <= PPC_REG_CR7LT)
- return (rid - PPC_REG_CR0LT) * 4 + 0;
- else if (rid >= PPC_REG_CR0UN && rid <= PPC_REG_CR7UN)
- return (rid - PPC_REG_CR0UN) * 4 + 3;
- else
- return rid;
+ return 0;
}
diff --git a/arch/powerpc/disassembler.h b/arch/powerpc/disassembler.h
index d4679ae0..bb764433 100644
--- a/arch/powerpc/disassembler.h
+++ b/arch/powerpc/disassembler.h
@@ -1,98 +1,5 @@
-/******************************************************************************
-This is the layer that the architecture module uses to access disassemble
-functionality.
+#include <string>
+using namespace std;
-Currently, it wraps capstone, but that could change in the future. It exists
-precisely to make swapping out disassemblers easy, because disassembler details
-(like capstone types) will not be intertwined in the architecture plugin code.
-
-Also, with the disassembler object separate, we can link it against
-easy-to-compile test harnesses like the speed test.
-
-There are three main functions:
-
-powerpc_init() - initializes this module
-powerpc_release() - un-initializes this module
-powerpc_decompose() - converts bytes into decomp_result
-powerpc_disassemble() - converts decomp_result to string
-
-Then some helpers if you need them:
-
-******************************************************************************/
-
-/* capstone stuff /usr/local/include/capstone */
-#include "capstone/capstone.h"
-#include "capstone/cs_priv.h"
-#include "capstone/ppc.h"
-
-#define PPC_CRX_REG_MASK 0x1ff
-#define PPC_CRX_FLOAT_MASK 0x200
-
-// TODO this is some sorta capstone baddy, where xori is showing as xnop's
-// opcode. Maybe pulling capstone will fix, need for xori to correctly
-// lift. Capstone is posting that XORI is 1452, though that is XNOP
-#define PPC_BN_INS_XORI PPC_INS_XNOP
-
-//*****************************************************************************
-// structs and types
-//*****************************************************************************
-enum ppc_status_t {
- STATUS_ERROR_UNSPEC=-1, STATUS_SUCCESS=0, STATUS_UNDEF_INSTR
-};
-
-typedef enum ppc_insn_bn {
- PPC_INS_BN_FCMPO = PPC_INS_ENDING+1,
- PPC_INS_BN_XXPERMR,
- PPC_INS_BN_ENDING
-} ppc_insn_bn;
-
-typedef enum ppc_reg_bn {
- PPC_REG_BN_GQR0 = PPC_REG_ENDING+1,
- PPC_REG_BN_GQR1,
- PPC_REG_BN_GQR2,
- PPC_REG_BN_GQR3,
- PPC_REG_BN_GQR4,
- PPC_REG_BN_GQR5,
- PPC_REG_BN_GQR6,
- PPC_REG_BN_GQR7,
- PPC_REG_BN_ENDING
-} ppc_reg_bn;
-
-/* operand type */
-enum operand_type_t { REG, VAL, LABEL };
-
-struct decomp_request
-{
- uint8_t *data;
- int size;
- uint32_t addr;
- bool lil_end;
-};
-
-struct decomp_result
-{
- /* actual capstone handle used, in case caller wants to do extra stuff
- (this can be one of two handles opened for BE or LE disassembling) */
- csh handle;
-
- ppc_status_t status;
-
- cs_insn insn;
- cs_detail detail;
-};
-
-//*****************************************************************************
-// function prototypes
-//*****************************************************************************
-int DoesQualifyForLocalDisassembly(const uint8_t *data, bool bigendian);
-bool PerformLocalDisassembly(const uint8_t *data, uint64_t addr, size_t &len, decomp_result* res, bool bigendian);
-
-extern "C" int powerpc_init(int);
-extern "C" void powerpc_release(void);
-extern "C" int powerpc_decompose(const uint8_t *data, int size, uint64_t addr,
- bool lil_end, struct decomp_result *result, bool is_64bit, int cs_mode);
-extern "C" int powerpc_disassemble(struct decomp_result *, char *buf, size_t len);
-
-extern "C" const char *powerpc_reg_to_str(uint32_t rid, int cs_mode_arg);
-extern "C" const uint32_t powerpc_crx_to_reg(uint32_t rid);
+int disassemble(uint8_t *data, uint32_t addr, string& result);
diff --git a/arch/powerpc/il.cpp b/arch/powerpc/il.cpp
index ad8e29a5..b288561a 100644
--- a/arch/powerpc/il.cpp
+++ b/arch/powerpc/il.cpp
@@ -1,23 +1,15 @@
#include "lowlevelilinstruction.h"
-#include <binaryninjaapi.h>
+#include "binaryninjaapi.h"
#include "disassembler.h"
+#include "decode/decode.h"
+
using namespace BinaryNinja;
#include "il.h"
#include "util.h"
-#define OTI_SEXT32_REGS 1
-#define OTI_SEXT64_REGS 2
-#define OTI_ZEXT32_REGS 4
-#define OTI_ZEXT64_REGS 8
-#define OTI_SEXT32_IMMS 16
-#define OTI_SEXT64_IMMS 32
-#define OTI_ZEXT32_IMMS 64
-#define OTI_ZEXT64_IMMS 128
-#define OTI_IMM_CPTR 256
-#define OTI_IMM_REL_CPTR 512
#define OTI_IMM_BIAS 1024
#define OTI_GPR0_ZERO 2048
@@ -32,144 +24,107 @@ static uint32_t genMask(uint32_t mb, uint32_t me)
return (mb <= me) ? (maskBegin & maskEnd) : (maskBegin | maskEnd);
}
+static uint64_t genMask64(uint32_t mb, uint32_t me)
+{
+ uint64_t maskBegin = ~0ull >> mb;
+ uint64_t maskEnd = ~0ull << (63 - me);
+
+ return (mb <= me) ? (maskBegin & maskEnd) : (maskBegin | maskEnd);
+}
+
#define PPC_IL_OPTIONS_DEFAULT 0
#define PPC_IL_EXTRA_DEFAULT 0
#define RZF 4
-static ExprId operToIL(LowLevelILFunction &il, struct cs_ppc_op *op,
+static ExprId operToIL(LowLevelILFunction &il, Operand* op,
int options=PPC_IL_OPTIONS_DEFAULT, uint64_t extra=PPC_IL_EXTRA_DEFAULT, size_t regsz=4)
{
ExprId res;
- if(!op) {
+ if (!op)
+ {
MYLOG("ERROR: operToIL() got NULL operand\n");
return il.Unimplemented();
}
- switch(op->type) {
- case PPC_OP_REG:
- //MYLOG("case PPC_OP_REG returning reg %d\n", op->reg);
- if (options & OTI_GPR0_ZERO && op->reg == PPC_REG_R0)
+ switch (op->cls)
+ {
+ case PPC_OP_REG_RA:
+ case PPC_OP_REG_RB:
+ case PPC_OP_REG_RC: // XXX: valid?
+ case PPC_OP_REG_RD:
+ case PPC_OP_REG_RS:
+ case PPC_OP_REG_FRA:
+ case PPC_OP_REG_FRB:
+ case PPC_OP_REG_FRC:
+ case PPC_OP_REG_FRD:
+ case PPC_OP_REG_FRS:
+ if (options & OTI_GPR0_ZERO && op->reg == PPC_REG_GPR0)
res = il.Const(regsz, 0);
else
res = il.Register(regsz, op->reg);
break;
- case PPC_OP_IMM:
- /* the immediate is a constant pointer (eg: absolute address) */
- if(options & OTI_IMM_CPTR) {
- res = il.ConstPointer(regsz, op->imm);
+
+ case PPC_OP_SIMM:
+ if (options & OTI_IMM_BIAS)
+ {
+ /* the immediate should be biased with given value */
+ res = il.Const(regsz, op->simm + extra);
}
- /* the immediate is a displacement (eg: relative addressing) */
- else if(options & OTI_IMM_REL_CPTR) {
- res = il.ConstPointer(regsz, op->imm + extra);
+ else
+ {
+ /* the immediate is just a plain boring immediate */
+ res = il.Const(regsz, op->simm);
}
- /* the immediate should be biased with given value */
- else if(options & OTI_IMM_BIAS) {
- res = il.Const(regsz, op->imm + extra);
+ break;
+
+ case PPC_OP_UIMM:
+ if (options & OTI_IMM_BIAS)
+ {
+ /* the immediate should be biased with given value */
+ res = il.Const(regsz, op->uimm + extra);
}
- /* the immediate is just a plain boring immediate */
- else {
- res = il.Const(regsz, op->imm);
+ else
+ {
+ /* the immediate is just a plain boring immediate */
+ res = il.Const(regsz, op->uimm);
}
break;
- case PPC_OP_MEM:
- //MYLOG("case PPC_OP_MEM returning regs (%d,%d)\n", op->mem.base, op->mem.disp);
-
- if (options & OTI_GPR0_ZERO && op->mem.base == PPC_REG_R0)
+ case PPC_OP_MEM_RA:
+ if (options & OTI_GPR0_ZERO && op->mem.reg == PPC_REG_GPR0)
res = il.Const(regsz, 0);
else
- res = il.Register(regsz, op->mem.base);
+ res = il.Register(regsz, op->mem.reg);
if(options & OTI_IMM_BIAS)
- res = il.Add(regsz, res, il.Const(4, op->mem.disp + extra));
+ res = il.Add(regsz, res, il.Const(regsz, op->mem.offset + extra));
else
- res = il.Add(regsz, res, il.Const(4, op->mem.disp));
+ res = il.Add(regsz, res, il.Const(regsz, op->mem.offset));
break;
- case PPC_OP_CRX:
- case PPC_OP_INVALID:
+ case PPC_OP_NONE:
default:
MYLOG("ERROR: don't know how to convert operand to IL\n");
res = il.Unimplemented();
}
- switch(options) {
- case OTI_SEXT32_REGS:
- if(op->type == PPC_OP_REG)
- res = il.SignExtend(4, res);
- break;
- case OTI_SEXT64_REGS:
- if(op->type == PPC_OP_REG)
- res = il.SignExtend(8, res);
- break;
- case OTI_ZEXT32_REGS:
- if(op->type == PPC_OP_REG)
- res = il.ZeroExtend(4, res);
- break;
- case OTI_ZEXT64_REGS:
- if(op->type == PPC_OP_REG)
- res = il.ZeroExtend(8, res);
- break;
- case OTI_SEXT32_IMMS:
- if(op->type == PPC_OP_REG)
- res = il.SignExtend(4, res);
- break;
- case OTI_SEXT64_IMMS:
- if(op->type == PPC_OP_REG)
- res = il.SignExtend(8, res);
- break;
- case OTI_ZEXT32_IMMS:
- if(op->type == PPC_OP_REG)
- res = il.ZeroExtend(4, res);
- break;
- case OTI_ZEXT64_IMMS:
- if(op->type == PPC_OP_REG)
- res = il.ZeroExtend(8, res);
- break;
- }
-
return res;
}
#define operToIL_a(il, op, regSz) operToIL(il, op, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, regSz)
/* map PPC_REG_CRX to an IL flagwrite type (a named set of written flags */
-int crxToFlagWriteType(int crx, bool signedComparison = true)
+int crxToFlagWriteType(Register reg, ppc_suf suf)
{
- // MYLOG("%s() crx:%d", __func__, crx);
- int flag_out = 0;
- int crx_local = 0;
- int crx_type = 0;
- int crx_index = 0;
- int suf = 0;
-
- crx_local = crx & PPC_CRX_REG_MASK;
- crx_type = crx & PPC_CRX_FLOAT_MASK;
- if ((crx_local < PPC_REG_CR0) || (crx_local > PPC_REG_CR7))
- {
- goto fail;
- }
-
- crx_index = crx_local - PPC_REG_CR0;
-
- if (crx_type != 0)
- {
- suf = PPC_SUF_F;
- }
- else if (signedComparison == false)
- {
- suf = PPC_SUF_U;
- }
+ if ((reg < PPC_REG_CRF0) || (reg > PPC_REG_CRF7))
+ return IL_FLAGWRITE_NONE;
/* when we have more flags... */
- flag_out = (crx_index * PPC_SUF_SZ) + IL_FLAGWRITE_CR0_S + suf;
-
-fail:
- return flag_out;
+ int crx_index = reg - PPC_REG_CRF0;
+ return (crx_index * PPC_SUF_SZ) + IL_FLAGWRITE_CR0_S + suf;
}
-
static ExprId ExtractConditionClause(LowLevelILFunction& il, uint8_t crBit, bool negate = false)
{
// MYLOG("%s() crbit:%x", __func__, crBit);
@@ -242,55 +197,34 @@ static bool LiftConditionalBranch(LowLevelILFunction& il, uint8_t bo, uint8_t bi
return isConditional;
}
-static bool LiftBranches(Architecture* arch, LowLevelILFunction &il, const uint8_t* data, uint64_t addr, bool le)
+static bool LiftBranches(Architecture* arch, LowLevelILFunction &il, const Instruction *instruction, uint64_t addr)
{
- // MYLOG("%s() addr:0x%08llx\n", __func__, addr);
- uint32_t insn = *(const uint32_t *) data;
- bool lk;
size_t addressSize_l = arch->GetAddressSize();
-
- if (!le)
- {
- insn = bswap32(insn);
- }
-
- lk = insn & 1;
-
- switch (insn >> 26)
+ switch (instruction->id)
{
- case PPC_INS_BCA: /* b (b, ba, bl, bla) */
+ case PPC_ID_Bx:
{
- uint64_t target = insn & 0x03fffffc;
-
- /* sign extend target */
- target = sign_extend(addressSize_l, target, 25);
-
- /* account for absolute addressing */
- if (!(insn & 2))
- {
- target += addr;
- ADDRMASK(addressSize_l, target);
- }
+ uint64_t target = instruction->operands[0].label;
BNLowLevelILLabel* label = il.GetLabelForAddress(arch, target);
- if (label && !(lk && (target != (addr+4))))
+ if (label && !(instruction->flags.lk && (target != (addr+instruction->numBytes))))
{
/* branch to an instruction within the same function -- take
* 'lk' bit behavior into account, but don't emit as a call
*/
- if (lk)
+ if (instruction->flags.lk)
{
- il.AddInstruction(il.SetRegister(addressSize_l, PPC_REG_LR, il.ConstPointer(addressSize_l, addr + 4)));
+ il.AddInstruction(il.SetRegister(addressSize_l, PPC_REG_LR, il.ConstPointer(addressSize_l, addr + instruction->numBytes)));
}
il.AddInstruction(il.Goto(*label));
}
else
{
- ExprId dest = il.ConstPointer(4, target);
+ ExprId dest = il.ConstPointer(addressSize_l, target);
- if (lk)
+ if (instruction->flags.lk)
il.AddInstruction(il.Call(dest));
else
il.AddInstruction(il.Jump(dest));
@@ -298,28 +232,51 @@ static bool LiftBranches(Architecture* arch, LowLevelILFunction &il, const uint8
break;
}
- case PPC_INS_BA: /* bc */
+ case PPC_ID_BCx: /* bc */
+ case PPC_ID_VLE_E_BCx:
+ case PPC_ID_VLE_SE_BC:
{
- uint64_t target = insn & 0xfffc;
- uint8_t bo = (insn >> 21) & 0x1f;
- uint8_t bi = (insn >> 16) & 0x1f;
-
- /* sign extend target */
- target = sign_extend(addressSize_l, target, 15);
+ uint8_t bo = instruction->operands[0].uimm;
+ uint8_t bi = instruction->operands[1].uimm;
+ uint64_t target = instruction->operands[2].label;
- /* account for absolute addressing */
- if (!(insn & 2))
+ if (instruction->id == PPC_ID_VLE_E_BCx)
+ {
+ // Table 2-5. BO32 Field Encodings in VLEPEM,
+ // mapped to their equivalent BO fields for
+ // normal BC instructions
+ //
+ // 0b00 -> branch if condition false | 0b00100
+ // 0b01 -> branch if condition true | 0b01100
+ // 0b10 -> dec CTR, branch if CTR != 0 | 0b10000
+ // 0b11 -> dec CTR, branch if CTR == 0 | 0b10010
+ switch (bo)
+ {
+ case 0: bo = 0x04; break;
+ case 1: bo = 0x0c; break;
+ case 2: bo = 0x10; break;
+ case 3: bo = 0x12; break;
+ default:
+ ; // unreachable
+ }
+ }
+ else if (instruction->id == PPC_ID_VLE_SE_BC)
{
- target += addr;
- ADDRMASK(addressSize_l, target);
+ // Table 2-6. BO16 Field Encodings in VLEPEM,
+ // mapped to their equivalent BO fields for
+ // normal BC instructions
+ //
+ // 0b0 -> branch if condition false | 0b00100
+ // 0b1 -> branch if condition true | 0b01100
+ bo = (bo << 3) | 0x4;
}
BNLowLevelILLabel *existingTakenLabel = il.GetLabelForAddress(arch, target);
- BNLowLevelILLabel *existingFalseLabel = il.GetLabelForAddress(arch, addr + 4);
+ BNLowLevelILLabel *existingFalseLabel = il.GetLabelForAddress(arch, addr + instruction->numBytes);
- if (lk)
+ if (instruction->flags.lk)
{
- il.AddInstruction(il.SetRegister(addressSize_l, PPC_REG_LR, il.ConstPointer(addressSize_l, addr + 4)));
+ il.AddInstruction(il.SetRegister(addressSize_l, PPC_REG_LR, il.ConstPointer(addressSize_l, addr + instruction->numBytes)));
}
LowLevelILLabel takenLabelManual, falseLabelManual;
@@ -343,9 +300,9 @@ static bool LiftBranches(Architecture* arch, LowLevelILFunction &il, const uint8
{
il.AddInstruction(il.Goto(*takenLabel));
}
- else if (target != addr + 4)
+ else if (target != addr + instruction->numBytes)
{
- if (lk)
+ if (instruction->flags.lk)
{
il.AddInstruction(il.Call(il.ConstPointer(addressSize_l, target)));
if (wasConditionalBranch)
@@ -364,29 +321,30 @@ static bool LiftBranches(Architecture* arch, LowLevelILFunction &il, const uint8
break;
}
- case PPC_INS_BCCTR: /* bcctr, bclr */
+ case PPC_ID_BCCTRx: /* bcctr, bclr */
+ case PPC_ID_BCLRx:
{
- uint8_t bo = (insn >> 21) & 0x1f;
- uint8_t bi = (insn >> 16) & 0x1f;
+ uint8_t bo = instruction->operands[0].uimm;
+ uint8_t bi = instruction->operands[1].uimm;
bool blr = false;
ExprId expr;
-
- switch ((insn >> 1) & 0x3ff)
+ switch (instruction->id)
{
- case 16:
- expr = il.Register(addressSize_l, PPC_REG_LR);
- blr = true;
- break;
- case 528:
- if (!(bo & 4))
+ case PPC_ID_BCCTRx:
+ if (!(bo & 0x4))
return false;
expr = il.Register(addressSize_l, PPC_REG_CTR);
+ blr = false;
+ break;
+ case PPC_ID_BCLRx:
+ expr = il.Register(addressSize_l, PPC_REG_LR);
+ blr = true;
break;
default:
return false;
}
- BNLowLevelILLabel *existingFalseLabel = il.GetLabelForAddress(arch, addr + 4);
+ BNLowLevelILLabel *existingFalseLabel = il.GetLabelForAddress(arch, addr + instruction->numBytes);
BNLowLevelILLabel* falseLabel = existingFalseLabel;
LowLevelILLabel takenLabel, falseLabelManual;
@@ -399,7 +357,7 @@ static bool LiftBranches(Architecture* arch, LowLevelILFunction &il, const uint8
if (wasConditionalBranch)
il.MarkLabel(takenLabel);
- if (lk)
+ if (instruction->flags.lk)
{
il.AddInstruction(il.Call(expr));
if (wasConditionalBranch)
@@ -415,6 +373,24 @@ static bool LiftBranches(Architecture* arch, LowLevelILFunction &il, const uint8
break;
}
+ case PPC_ID_VLE_SE_BLRx:
+ {
+ if (instruction->flags.lk)
+ il.AddInstruction(il.Call(il.Register(addressSize_l, PPC_REG_LR)));
+ else
+ il.AddInstruction(il.Return(il.Register(addressSize_l, PPC_REG_LR)));
+
+ break;
+ }
+ case PPC_ID_VLE_SE_BCTRx:
+ {
+ if (instruction->flags.lk)
+ il.AddInstruction(il.Call(il.Register(addressSize_l, PPC_REG_CTR)));
+ else
+ il.AddInstruction(il.Jump(il.Register(addressSize_l, PPC_REG_CTR)));
+
+ break;
+ }
default:
return false;
}
@@ -455,67 +431,67 @@ static ExprId ByteReverseRegister(LowLevelILFunction &il, uint32_t reg, size_t s
}
-static void ByteReversedLoad(LowLevelILFunction &il, struct cs_ppc* ppc, size_t size, size_t addressSize_a=4)
+static void ByteReversedLoad(LowLevelILFunction &il, Instruction* instruction, size_t size, size_t address_size_a=4)
{
- ExprId addr = operToIL(il, &ppc->operands[1], OTI_GPR0_ZERO, PPC_IL_EXTRA_DEFAULT, addressSize_a); // (rA|0)
- ExprId val = il.Load(size, il.Add(addressSize_a, addr, operToIL_a(il, &ppc->operands[2], addressSize_a))); // [(rA|0) + (rB)]
+ ExprId addr = operToIL(il, &instruction->operands[1], OTI_GPR0_ZERO, PPC_IL_EXTRA_DEFAULT, address_size_a); // (rA|0)
+ ExprId val = il.Load(size, il.Add(address_size_a, addr, operToIL_a(il, &instruction->operands[2], address_size_a))); // [(rA|0) + (rB)]
- if (size < addressSize_a)
+ if (size < address_size_a)
{
- val = il.ZeroExtend(addressSize_a, val);
+ val = il.ZeroExtend(address_size_a, val);
}
/* set reg immediately; this will cause xrefs to be sized correctly,
* we'll use this as the scratch while we calculate the swapped value */
- il.AddInstruction(il.SetRegister(addressSize_a, ppc->operands[0].reg, val)); // rD = [(rA|0) + (rB)]
- ExprId swap = ByteReverseRegister(il, ppc->operands[0].reg, size);
+ il.AddInstruction(il.SetRegister(address_size_a, instruction->operands[0].reg, val)); // rD = [(rA|0) + (rB)]
+ ExprId swap = ByteReverseRegister(il, instruction->operands[0].reg, size);
- il.AddInstruction(il.SetRegister(addressSize_a, ppc->operands[0].reg, swap)); // rD = swap([(rA|0) + (rB)])
+ il.AddInstruction(il.SetRegister(address_size_a, instruction->operands[0].reg, swap)); // rD = swap([(rA|0) + (rB)])
}
-static void ByteReversedStore(LowLevelILFunction &il, struct cs_ppc* ppc, size_t size, size_t addressSize_a=4)
+static void ByteReversedStore(LowLevelILFunction &il, Instruction* instruction, size_t size, size_t addressSize_a=4)
{
- ExprId addr = operToIL(il, &ppc->operands[1], OTI_GPR0_ZERO, PPC_IL_EXTRA_DEFAULT, addressSize_a); // (rA|0)
- addr = il.Add(addressSize_a, addr, operToIL_a(il, &ppc->operands[2], addressSize_a)); // (rA|0) + (rB)
- ExprId val = ByteReverseRegister(il, ppc->operands[0].reg, size); // rS = swap(rS)
- il.AddInstruction(il.Store(size, addr, val)); // [(rA|0) + (rB)] = swap(rS)
+ ExprId addr = operToIL(il, &instruction->operands[1], OTI_GPR0_ZERO, PPC_IL_EXTRA_DEFAULT, addressSize_a); // (rA|0)
+ addr = il.Add(addressSize_a, addr, operToIL_a(il, &instruction->operands[2], addressSize_a)); // (rA|0) + (rB)
+ ExprId val = ByteReverseRegister(il, instruction->operands[0].reg, size); // rS = swap(rS)
+ il.AddInstruction(il.Store(size, addr, val)); // [(rA|0) + (rB)] = swap(rS)
}
-static void loadstoreppcfs(LowLevelILFunction& il,
- int load_store_sz,
- cs_ppc_op* operand1, /* register that gets read/written */
- cs_ppc_op* operand2, /* location the read/write occurs */
- cs_ppc_op* operand3=0,
+static void load_float(LowLevelILFunction& il,
+ int load_sz,
+ Operand* operand1, /* register that gets read/written */
+ Operand* operand2, /* location the read/write occurs */
+ Operand* operand3=0,
bool update=false
)
{
- ExprId tmp = 0;
+ ExprId tmp = BN_INVALID_EXPR;
const int addrsz = 4;
// assume single
- if (!load_store_sz)
- load_store_sz = 4;
+ if (!load_sz)
+ load_sz = 4;
// operand1.reg = [operand2.reg + operand2.imm]
- if (operand2->type == PPC_OP_MEM)
+ if (operand2->cls == PPC_OP_MEM_RA)
{
- if (operand2->mem.disp == 0)
+ if (operand2->mem.reg == 0)
{
- tmp = il.Register(4, operand2->mem.base);
+ tmp = il.Const(addrsz, operand2->mem.offset);
}
else
{
- tmp = il.Add(addrsz, il.Register(addrsz, operand2->mem.base), il.Const(addrsz, operand2->mem.disp));
+ tmp = il.Add(addrsz, il.Register(addrsz, operand2->mem.reg), il.Const(addrsz, operand2->mem.offset));
}
}
- else if(operand2->type == PPC_OP_REG)
+ else if(operand2->cls == PPC_OP_REG_RA)
{
- if ((operand3 != 0) && (operand3->type == PPC_OP_REG))
+ if ((operand3 != 0) && (operand3->cls == PPC_OP_REG_RB))
{
tmp = il.Add(4, il.Register(addrsz, operand2->reg), il.Register(addrsz, operand3->reg));
}
}
- il.AddInstruction(il.SetRegister(load_store_sz, operand1->reg, il.FloatConvert(load_store_sz, il.Operand(1, il.Load(load_store_sz, tmp)))));
+ il.AddInstruction(il.SetRegister(load_sz, operand1->reg, il.FloatConvert(load_sz, il.Operand(1, il.Load(load_sz, tmp)))));
if (update == true)
{
@@ -527,100 +503,43 @@ static void loadstoreppcfs(LowLevelILFunction& il,
/* returns TRUE - if this IL continues
FALSE - if this IL terminates a block */
bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
- const uint8_t* data, uint64_t addr, decomp_result *res, bool le)
+ Instruction* instruction, uint64_t addr)
{
- int i;
- bool rc = true;
- struct cs_insn *insn = 0;
- struct cs_detail *detail = 0;
- struct cs_ppc *ppc = 0;
- size_t addressSize_l = 0;
- int extend_l = 0;
- uint32_t rawInsn = *(const uint32_t *) data;
-
- // for ppc_ps
- // ppc_reg_bn gqr_l = (ppc_reg_bn)0;
- // int w_l = 0;
-
- addressSize_l = arch->GetAddressSize();
- if (!le)
- {
- rawInsn = bswap32(rawInsn);
- }
-
-
- /* bypass capstone path for *all* branching instructions; capstone
- * is too difficult to work with and is outright broken for some
- * branch instructions (bdnz, etc.)
- */
- if (LiftBranches(arch, il, data, addr, le))
+ if (LiftBranches(arch, il, instruction, addr))
return true;
- insn = &(res->insn);
- detail = &(res->detail);
- ppc = &(detail->ppc);
+ int i;
+ size_t addressSize_l = arch->GetAddressSize();
+ size_t opSize = 4;
- /* There is a simplifying reduction available for:
- * rlwinm <reg>, <reg>, <rol_amt>, <mask_begin>, <mask_end>
- * When <rol_amt> == <mask_begin> == 0, this can be translated to:
- * clrwi <reg>, <reg>, 31-<mask_end>
- *
- * Unfortunately capstone screws this up, replacing just the instruction id with PPC_INSN_CLRWI.
- * The mnemonic ("rlwinm"), operands, etc. all stay the same.
- */
- if (insn->id == PPC_INS_CLRLWI && insn->mnemonic[0] == 'r')
- {
- insn->id = PPC_INS_RLWINM;
- }
+ bool rc = true;
/* create convenient access to instruction operands */
- cs_ppc_op *oper0=NULL, *oper1=NULL, *oper2=NULL, *oper3=NULL, *oper4=NULL;
+ Operand *oper0=NULL, *oper1=NULL, *oper2=NULL, *oper3=NULL, *oper4=NULL;
#define REQUIRE1OP if(!oper0) goto ReturnUnimpl;
#define REQUIRE2OPS if(!oper0 || !oper1) goto ReturnUnimpl;
#define REQUIRE3OPS if(!oper0 || !oper1 || !oper2) goto ReturnUnimpl;
#define REQUIRE4OPS if(!oper0 || !oper1 || !oper2 || !oper3) goto ReturnUnimpl;
#define REQUIRE5OPS if(!oper0 || !oper1 || !oper2 || !oper3 || !oper4) goto ReturnUnimpl;
- switch(ppc->op_count) {
+ switch (instruction->numOperands)
+ {
default:
- case 5: oper4 = &(ppc->operands[4]); FALL_THROUGH
- case 4: oper3 = &(ppc->operands[3]); FALL_THROUGH
- case 3: oper2 = &(ppc->operands[2]); FALL_THROUGH
- case 2: oper1 = &(ppc->operands[1]); FALL_THROUGH
- case 1: oper0 = &(ppc->operands[0]); FALL_THROUGH
+ case 5: oper4 = &(instruction->operands[4]); FALL_THROUGH
+ case 4: oper3 = &(instruction->operands[3]); FALL_THROUGH
+ case 3: oper2 = &(instruction->operands[2]); FALL_THROUGH
+ case 2: oper1 = &(instruction->operands[1]); FALL_THROUGH
+ case 1: oper0 = &(instruction->operands[0]); FALL_THROUGH
case 0: while(0);
}
- /* for conditionals that specify a crx, treat it special */
- if(ppc->bc != PPC_BC_INVALID) {
- if(oper0 && oper0->type == PPC_OP_REG && oper0->reg >= PPC_REG_CR0 &&
- ppc->operands[0].reg <= PPC_REG_CR7) {
- oper0 = oper1;
- oper1 = oper2;
- oper2 = oper3;
- oper3 = NULL;
- }
- }
+ ExprId ei0 = BN_INVALID_EXPR, ei1 = BN_INVALID_EXPR, ei2 = BN_INVALID_EXPR;
- if(0 && insn->id == PPC_INS_CMPLWI) {
- MYLOG("%s() %08llx: %02X %02X %02X %02X %s %s has %d operands\n",
- __func__, addr, data[0], data[1], data[2], data[3],
- insn->mnemonic, insn->op_str, ppc->op_count
- );
-
- //printInstructionVerbose(res);
- //MYLOG("oper0: %p\n", oper0);
- //MYLOG("oper1: %p\n", oper1);
- //MYLOG("oper2: %p\n", oper2);
- //MYLOG("oper3: %p\n", oper3);
- }
-
- ExprId ei0 = 0, ei1 = 0, ei2 = 0;
-
- switch(insn->id) {
+ switch (instruction->id)
+ {
/* add
"add." also updates the CR0 bits */
- case PPC_INS_ADD: /* add */
+ case PPC_ID_ADDx: /* add */
REQUIRE2OPS
ei0 = il.Add(
addressSize_l,
@@ -628,12 +547,12 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
operToIL_a(il, oper2, addressSize_l)
);
ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0,
- (insn->id == PPC_INS_ADD && ppc->update_cr0) ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_ADDE: /* add, extended (+ carry flag) */
+ case PPC_ID_ADDEx: /* add, extended (+ carry flag) */
REQUIRE3OPS
ei0 = il.AddCarry(
addressSize_l,
@@ -643,15 +562,15 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
IL_FLAGWRITE_XER_CA
);
ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_ADDME: /* add, extended (+ carry flag) minus one */
- case PPC_INS_ADDZE:
+ case PPC_ID_ADDMEx: /* add, extended (+ carry flag) minus one */
+ case PPC_ID_ADDZEx:
REQUIRE2OPS
- if (insn->id == PPC_INS_ADDME)
+ if (instruction->id == PPC_ID_ADDMEx)
ei0 = il.Const(addressSize_l, ADDRNEG1(addressSize_l));
else
ei0 = il.Const(addressSize_l, 0);
@@ -663,13 +582,13 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
IL_FLAGWRITE_XER_CA
);
ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_ADDC: /* add, carrying */
- case PPC_INS_ADDIC: /* add immediate, carrying */
+ case PPC_ID_ADDCx: /* add, carrying */
+ case PPC_ID_ADDICx: /* add immediate, carrying */
REQUIRE3OPS
ei0 = il.Add(
addressSize_l,
@@ -678,18 +597,18 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
IL_FLAGWRITE_XER_CA
);
ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_ADDI: /* add immediate, eg: addi rD, rA, <imm> */
- case PPC_INS_ADDIS: /* add immediate, shifted */
+ case PPC_ID_ADDIx: /* add immediate, eg: addi rD, rA, <imm> */
+ case PPC_ID_ADDIS: /* add immediate, shifted */
REQUIRE2OPS
- if (insn->id == PPC_INS_ADDIS)
- ei0 = il.Const(addressSize_l, oper2->imm << 16);
+ if (instruction->id == PPC_ID_ADDIS)
+ ei0 = il.Const(addressSize_l, oper2->simm << 16);
else
- ei0 = il.Const(addressSize_l, oper2->imm);
+ ei0 = il.Const(addressSize_l, oper2->simm);
ei0 = il.Add(
addressSize_l,
operToIL(il, oper1, OTI_GPR0_ZERO, PPC_IL_EXTRA_DEFAULT, addressSize_l),
@@ -699,183 +618,179 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
break;
- case PPC_INS_LIS: /* load immediate, shifted */
+ case PPC_ID_LIS: /* load immediate, shifted */
REQUIRE2OPS
ei0 = il.SetRegister(
addressSize_l,
oper0->reg,
- il.ConstPointer(addressSize_l, oper1->imm << 16)
+ il.ConstPointer(addressSize_l, oper1->simm << 16)
);
il.AddInstruction(ei0);
break;
- case PPC_INS_LI: /* load immediate */
- case PPC_INS_LA: /* load displacement */
+ case PPC_ID_LI: /* load immediate */
REQUIRE2OPS
il.AddInstruction(il.SetRegister(addressSize_l, oper0->reg, operToIL_a(il, oper1, addressSize_l)));
break;
- case PPC_INS_AND:
- case PPC_INS_ANDC: // and [with complement]
- case PPC_INS_NAND:
+ case PPC_ID_ANDx:
+ case PPC_ID_ANDCx: // and [with complement]
+ case PPC_ID_NANDx:
REQUIRE3OPS
- ei0 = operToIL_a(il, oper2, addressSize_l);
- if (insn->id == PPC_INS_ANDC)
+ ei0 = operToIL(il, oper2);
+ if (instruction->id == PPC_ID_ANDCx)
ei0 = il.Not(addressSize_l, ei0);
- ei0 = il.And(addressSize_l, operToIL_a(il, oper1, addressSize_l), ei0);
- if (insn->id == PPC_INS_NAND)
+ ei0 = il.And(addressSize_l, operToIL(il, oper1), ei0);
+ if (instruction->id == PPC_ID_NANDx)
ei0 = il.Not(addressSize_l, ei0);
ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_ANDIS:
- case PPC_INS_ANDI:
+ case PPC_ID_ANDIx:
+ case PPC_ID_ANDIS:
REQUIRE3OPS
- if (insn->id == PPC_INS_ANDIS)
- ei0 = il.Const(addressSize_l, oper2->imm << 16);
+ if (instruction->id == PPC_ID_ANDIS)
+ ei0 = il.Const(addressSize_l, oper2->uimm << 16);
else
- ei0 = il.Const(addressSize_l, oper2->imm);
- ei0 = il.And(addressSize_l, operToIL_a(il, oper1, addressSize_l), ei0);
- ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0, IL_FLAGWRITE_CR0_S);
+ ei0 = il.Const(addressSize_l, oper2->uimm);
+ ei0 = il.And(addressSize_l, operToIL(il, oper1), ei0);
+
+ // VLE instructions that get translated to ANDIx may
+ // not have the rc bit set
+ if (instruction->flags.rc)
+ ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0, IL_FLAGWRITE_CR0_S);
il.AddInstruction(ei0);
break;
- case PPC_INS_CMP:
- case PPC_INS_CMPW: /* compare (signed) word(32-bit) */
- REQUIRE2OPS
- ei0 = operToIL_a(il, oper2 ? oper1 : oper0, addressSize_l);
- ei1 = operToIL_a(il, oper2 ? oper2 : oper1, addressSize_l);
- ei2 = il.Sub(addressSize_l, ei0, ei1, crxToFlagWriteType(oper2 ? oper0->reg : PPC_REG_CR0));
+ case PPC_ID_CMPW: /* compare (signed) word(32-bit) */
+ REQUIRE3OPS
+ ei0 = operToIL(il, oper1);
+ ei1 = operToIL(il, oper2);
+ ei2 = il.Sub(addressSize_l, ei0, ei1, crxToFlagWriteType(oper0->reg, PPC_SUF_S));
il.AddInstruction(ei2);
break;
- case PPC_INS_CMPL:
- case PPC_INS_CMPLW: /* compare logical(unsigned) word(32-bit) */
- REQUIRE2OPS
- ei0 = operToIL_a(il, oper2 ? oper1 : oper0, addressSize_l);
- ei1 = operToIL_a(il, oper2 ? oper2 : oper1, addressSize_l);
- ei2 = il.Sub(addressSize_l, ei0, ei1, crxToFlagWriteType(oper2 ? oper0->reg : PPC_REG_CR0, false));
+ case PPC_ID_CMPLW: /* compare logical(unsigned) word(32-bit) */
+ REQUIRE3OPS
+ ei0 = operToIL(il, oper1);
+ ei1 = operToIL(il, oper2);
+ ei2 = il.Sub(addressSize_l, ei0, ei1, crxToFlagWriteType(oper0->reg, PPC_SUF_U));
il.AddInstruction(ei2);
break;
- case PPC_INS_CMPI:
- case PPC_INS_CMPWI: /* compare (signed) word(32-bit) immediate */
- case PPC_INS_CMPDI:
- REQUIRE2OPS
- EXTOPTS(rawInsn, addressSize_l, extend_l);
- ei0 = operToIL_a(il, oper2 ? oper1 : oper0, addressSize_l);
- ei1 = operToIL(il, oper2 ? oper2 : oper1, extend_l, PPC_IL_EXTRA_DEFAULT, addressSize_l);
- ei2 = il.Sub(addressSize_l, ei0, ei1, crxToFlagWriteType(oper2 ? oper0->reg : PPC_REG_CR0));
+ case PPC_ID_CMPWI: /* compare (signed) word(32-bit) immediate */
+ REQUIRE3OPS
+ ei0 = operToIL(il, oper1);
+ ei1 = operToIL_a(il, oper2, addressSize_l);
+ ei2 = il.Sub(addressSize_l, ei0, ei1, crxToFlagWriteType(oper0->reg, PPC_SUF_S));
il.AddInstruction(ei2);
break;
- case PPC_INS_CMPLI:
- case PPC_INS_CMPLWI: /* compare logical(unsigned) word(32-bit) immediate */
- REQUIRE2OPS
- EXTOPTZ(rawInsn, addressSize_l, extend_l);
- ei0 = operToIL_a(il, oper2 ? oper1 : oper0, addressSize_l);
- ei1 = operToIL(il, oper2 ? oper2 : oper1, extend_l, PPC_IL_EXTRA_DEFAULT, addressSize_l);
- ei2 = il.Sub(addressSize_l, ei0, ei1, crxToFlagWriteType(oper2 ? oper0->reg : PPC_REG_CR0, false));
+ case PPC_ID_CMPLWI: /* compare logical(unsigned) word(32-bit) immediate */
+ REQUIRE3OPS
+ ei0 = operToIL(il, oper1);
+ ei1 = operToIL_a(il, oper2, addressSize_l);
+ ei2 = il.Sub(addressSize_l, ei0, ei1, crxToFlagWriteType(oper0->reg, PPC_SUF_U));
il.AddInstruction(ei2);
break;
- //case PPC_INS_CMPD: /* compare (signed) d-word(64-bit) */
- // REQUIRE2OPS
- // ei0 = operToIL(il, oper0);
- // ei1 = operToIL(il, oper1, OTI_SEXT64_REGS);
- // ei2 = il.Sub(4, ei0, ei1, flagWriteType);
- // il.AddInstruction(ei2);
- // break;
+ case PPC_ID_CMPD: /* compare (signed) d-word(64-bit) */
+ REQUIRE2OPS
+ ei0 = operToIL_a(il, oper1, 8);
+ ei1 = operToIL_a(il, oper2, 8);
+ ei2 = il.Sub(addressSize_l, ei0, ei1, crxToFlagWriteType(oper0->reg, PPC_SUF_S));
+ il.AddInstruction(ei2);
+ break;
- //case PPC_INS_CMPLD: /* compare logical(unsigned) d-word(64-bit) */
- // REQUIRE2OPS
- // ei0 = operToIL(il, oper0);
- // ei1 = operToIL(il, oper1, OTI_ZEXT64_REGS);
- // ei2 = il.Sub(4, ei0, ei1, flagWriteType);
- // il.AddInstruction(ei2);
- // break;
+ case PPC_ID_CMPLD: /* compare logical(unsigned) d-word(64-bit) */
+ REQUIRE2OPS
+ ei0 = operToIL_a(il, oper1, 8);
+ ei1 = operToIL_a(il, oper2, 8);
+ ei2 = il.Sub(addressSize_l, ei0, ei1, crxToFlagWriteType(oper0->reg, PPC_SUF_U));
+ il.AddInstruction(ei2);
+ break;
- //case PPC_INS_CMPDI: /* compare (signed) d-word(64-bit) immediate */
- // REQUIRE2OPS
- // ei0 = operToIL(il, oper0);
- // ei1 = operToIL(il, oper1, OTI_SEXT64_IMMS);
- // ei2 = il.Sub(4, ei0, ei1, flagWriteType);
- // il.AddInstruction(ei2);
- // break;
+ case PPC_ID_CMPDI:
+ REQUIRE2OPS
+ ei0 = operToIL_a(il, oper1, 8);
+ ei1 = operToIL_a(il, oper2, 8);
+ ei2 = il.Sub(8, ei0, ei1, crxToFlagWriteType(oper0->reg, PPC_SUF_S));
+ il.AddInstruction(ei2);
+ break;
- //case PPC_INS_CMPLDI: /* compare logical(unsigned) d-word(64-bit) immediate */
- // REQUIRE2OPS
- // ei0 = operToIL(il, oper0);
- // ei1 = operToIL(il, oper1, OTI_ZEXT64_IMMS);
- // ei2 = il.Sub(4, ei0, ei1, flagWriteType);
- // il.AddInstruction(ei2);
- // break;
+ case PPC_ID_CMPLDI:
+ REQUIRE2OPS
+ ei0 = operToIL_a(il, oper1, 8);
+ ei1 = operToIL_a(il, oper2, 8);
+ ei2 = il.Sub(8, ei0, ei1, crxToFlagWriteType(oper0->reg, PPC_SUF_U));
+ il.AddInstruction(ei2);
+ break;
- case PPC_INS_CRAND:
- case PPC_INS_CRANDC:
- case PPC_INS_CRNAND:
+ case PPC_ID_CRAND:
+ case PPC_ID_CRANDC:
+ case PPC_ID_CRNAND:
REQUIRE3OPS
- ei0 = il.Flag(oper1->reg - PPC_REG_R0);
- ei1 = il.Flag(oper2->reg - PPC_REG_R0);
- if (insn->id == PPC_INS_CRANDC)
+ ei0 = il.Flag(oper1->crbit);
+ ei1 = il.Flag(oper2->crbit);
+ if (instruction->id == PPC_ID_CRANDC)
ei1 = il.Not(0, ei1);
ei0 = il.And(0, ei0, ei1);
- if (insn->id == PPC_INS_CRNAND)
+ if (instruction->id == PPC_ID_CRNAND)
ei0 = il.Not(0, ei0);
- il.AddInstruction(il.SetFlag(oper0->reg - PPC_REG_R0, ei0));
+ il.AddInstruction(il.SetFlag(oper0->crbit, ei0));
break;
- case PPC_INS_CROR:
- case PPC_INS_CRORC:
- case PPC_INS_CRNOR:
+ case PPC_ID_CROR:
+ case PPC_ID_CRORC:
+ case PPC_ID_CRNOR:
REQUIRE3OPS
- ei0 = il.Flag(oper1->reg - PPC_REG_R0);
- ei1 = il.Flag(oper2->reg - PPC_REG_R0);
- if (insn->id == PPC_INS_CRORC)
+ ei0 = il.Flag(oper1->crbit);
+ ei1 = il.Flag(oper2->crbit);
+ if (instruction->id == PPC_ID_CRORC)
ei1 = il.Not(0, ei1);
ei0 = il.Or(0, ei0, ei1);
- if (insn->id == PPC_INS_CRNOR)
+ if (instruction->id == PPC_ID_CRNOR)
ei0 = il.Not(0, ei0);
- il.AddInstruction(il.SetFlag(oper0->reg - PPC_REG_R0, ei0));
+ il.AddInstruction(il.SetFlag(oper0->crbit, ei0));
break;
- case PPC_INS_CREQV:
- case PPC_INS_CRXOR:
+ case PPC_ID_CREQV:
+ case PPC_ID_CRXOR:
REQUIRE3OPS
- ei0 = il.Flag(oper1->reg - PPC_REG_R0);
- ei1 = il.Flag(oper2->reg - PPC_REG_R0);
+ ei0 = il.Flag(oper1->crbit);
+ ei1 = il.Flag(oper2->crbit);
ei0 = il.Xor(0, ei0, ei1);
- if (insn->id == PPC_INS_CREQV)
+ if (instruction->id == PPC_ID_CREQV)
ei0 = il.Not(0, ei0);
- il.AddInstruction(il.SetFlag(oper0->reg - PPC_REG_R0, ei0));
+ il.AddInstruction(il.SetFlag(oper0->crbit, ei0));
break;
- case PPC_INS_CRSET:
+ case PPC_ID_CRSET:
REQUIRE1OP
- ei0 = il.SetFlag(oper0->reg - PPC_REG_R0, il.Const(0, 1));
+ ei0 = il.SetFlag(oper0->crbit, il.Const(0, 1));
il.AddInstruction(ei0);
break;
- case PPC_INS_CRCLR:
+ case PPC_ID_CRCLR:
REQUIRE1OP
- ei0 = il.SetFlag(oper0->reg - PPC_REG_R0, il.Const(0, 0));
+ ei0 = il.SetFlag(oper0->crbit, il.Const(0, 0));
il.AddInstruction(ei0);
break;
- case PPC_INS_CRNOT:
- case PPC_INS_CRMOVE:
+ case PPC_ID_CRNOT:
+ case PPC_ID_CRMOVE:
REQUIRE2OPS
- ei0 = il.Flag(oper1->reg - PPC_REG_R0);
- if (insn->id == PPC_INS_CRNOT)
+ ei0 = il.Flag(oper1->crbit);
+ if (instruction->id == PPC_ID_CRNOT)
ei0 = il.Not(0, ei0);
- ei0 = il.SetFlag(oper0->reg - PPC_REG_R0, ei0);
+ ei0 = il.SetFlag(oper0->crbit, ei0);
il.AddInstruction(ei0);
break;
- case PPC_INS_MFCR:
+ case PPC_ID_MFCR:
REQUIRE1OP
il.AddInstruction(il.SetRegister(4, oper0->reg,
il.Or(4, il.FlagBit(4, IL_FLAG_LT, 31),
@@ -912,11 +827,26 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.FlagBit(4, IL_FLAG_SO_7, 0))))))))))))))))))))))))))))))))));
break;
- case PPC_INS_MTCRF:
+ case PPC_ID_MCRF:
+ {
+ REQUIRE2OPS
+ uint32_t from = oper1->reg - PPC_REG_CRF0;
+ uint32_t to = oper0->reg - PPC_REG_CRF0;
+
+ il.AddInstruction(il.SetFlag(4*to + IL_FLAG_LT, il.FlagBit(0, 4*from + IL_FLAG_LT, 31 - (4*from + IL_FLAG_LT))));
+ il.AddInstruction(il.SetFlag(4*to + IL_FLAG_GT, il.FlagBit(0, 4*from + IL_FLAG_GT, 31 - (4*from + IL_FLAG_GT))));
+ il.AddInstruction(il.SetFlag(4*to + IL_FLAG_EQ, il.FlagBit(0, 4*from + IL_FLAG_EQ, 31 - (4*from + IL_FLAG_EQ))));
+ il.AddInstruction(il.SetFlag(4*to + IL_FLAG_SO, il.FlagBit(0, 4*from + IL_FLAG_SO, 31 - (4*from + IL_FLAG_SO))));
+
+ break;
+
+ }
+
+ case PPC_ID_MTCRF:
REQUIRE2OPS
for (uint8_t test = 0x80, i = 0; test; test >>= 1, i++)
{
- if (test & oper0->imm)
+ if (test & oper0->uimm)
{
ei0 = il.Or(4, il.Register(4, oper1->reg), il.Const(4, 0), IL_FLAGWRITE_MTCR0 + i);
il.AddInstruction(ei0);
@@ -924,11 +854,11 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
}
break;
- case PPC_INS_EXTSB:
- case PPC_INS_EXTSH:
+ case PPC_ID_EXTSBx:
+ case PPC_ID_EXTSHx:
REQUIRE2OPS
ei0 = il.Register(addressSize_l, oper1->reg);
- if (insn->id == PPC_INS_EXTSB)
+ if (instruction->id == PPC_ID_EXTSBx)
{
ei0 = il.LowPart(1, ei0);
}
@@ -938,27 +868,27 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
}
ei0 = il.SignExtend(addressSize_l, ei0);
ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_EXTSW:
+ case PPC_ID_EXTSWx:
REQUIRE2OPS
ei0 = il.Register(8, oper1->reg);
ei0 = il.LowPart(4, ei0);
ei0 = il.SignExtend(8, ei0);
ei0 = il.SetRegister(8, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_ISEL:
+ case PPC_ID_ISEL:
REQUIRE4OPS
{
LowLevelILLabel trueLabel, falseLabel, doneLabel;
- uint32_t crBit = powerpc_crx_to_reg(oper3->reg);
+ uint32_t crBit = oper3->crbit;
uint32_t cr = crBit / 4;
switch (crBit % 4)
@@ -996,9 +926,10 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
}
break;
- case PPC_INS_LMW:
+ case PPC_ID_LMW:
REQUIRE2OPS
- for(i=oper0->reg; i<=PPC_REG_R31; ++i) {
+ for (i = oper0->reg; i <= PPC_REG_GPR31; ++i)
+ {
ei0 = il.SetRegister(4,
i, // dest
il.Load(4, // source
@@ -1014,28 +945,36 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
/*
load byte and zero extend [and update]
*/
- case PPC_INS_LBZ:
- case PPC_INS_LBZU:
+ case PPC_ID_LBZ:
+ case PPC_ID_LBZU:
+ case PPC_ID_VLE_SE_LBZ:
+ {
+ // 16-bit VLE loads/stores treats r0 as a normal register
+ uint32_t options = OTI_GPR0_ZERO;
+ if (instruction->id == PPC_ID_VLE_SE_LBZ)
+ options = 0;
+
REQUIRE2OPS
- ei0 = operToIL(il, oper1, OTI_GPR0_ZERO, PPC_IL_EXTRA_DEFAULT, addressSize_l); // d(rA) or 0
+ ei0 = operToIL(il, oper1, options, PPC_IL_EXTRA_DEFAULT, addressSize_l); // d(rA) or 0
ei0 = il.Load(1, ei0); // [d(rA)]
ei0 = il.ZeroExtend(addressSize_l, ei0);
ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0); // rD = [d(rA)]
il.AddInstruction(ei0);
// if update, rA is set to effective address (d(rA))
- if(insn->id == PPC_INS_LBZU) {
- ei0 = il.SetRegister(addressSize_l, oper1->mem.base, operToIL_a(il, oper1, addressSize_l));
+ if(instruction->id == PPC_ID_LBZU) {
+ ei0 = il.SetRegister(addressSize_l, oper1->mem.reg, operToIL(il, oper1, addressSize_l));
il.AddInstruction(ei0);
}
break;
+ }
/*
load half word [and zero/sign extend] [and update]
*/
- case PPC_INS_LBZX:
- case PPC_INS_LBZUX:
+ case PPC_ID_LBZX:
+ case PPC_ID_LBZUX:
REQUIRE3OPS
ei0 = operToIL(il, oper1, OTI_GPR0_ZERO, PPC_IL_EXTRA_DEFAULT, addressSize_l); // d(rA) or 0
ei0 = il.Load(1, il.Add(addressSize_l, ei0, operToIL_a(il, oper2, addressSize_l))); // [d(rA) + d(rB)]
@@ -1044,7 +983,8 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
// if update, rA is set to effective address (d(rA))
- if(insn->id == PPC_INS_LBZUX && oper1->reg != oper0->reg && oper1->reg != PPC_REG_R0) {
+ if (instruction->id == PPC_ID_LBZUX && oper1->reg != oper0->reg && oper1->reg != PPC_REG_GPR0)
+ {
ei0 = il.SetRegister(addressSize_l, oper1->reg, operToIL_a(il, oper1, addressSize_l));
il.AddInstruction(ei0);
}
@@ -1054,14 +994,21 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
/*
load half word [and zero/sign extend] [and update]
*/
- case PPC_INS_LHZ:
- case PPC_INS_LHZU:
- case PPC_INS_LHA:
- case PPC_INS_LHAU:
+ case PPC_ID_LHZ:
+ case PPC_ID_LHZU:
+ case PPC_ID_LHA:
+ case PPC_ID_LHAU:
+ case PPC_ID_VLE_SE_LHZ:
+ {
+ // 16-bit VLE loads/stores treats r0 as a normal register
+ uint32_t options = OTI_GPR0_ZERO;
+ if (instruction->id == PPC_ID_VLE_SE_LHZ)
+ options = 0;
+
REQUIRE2OPS
- ei0 = operToIL(il, oper1, OTI_GPR0_ZERO, PPC_IL_EXTRA_DEFAULT, addressSize_l); // d(rA) or 0
+ ei0 = operToIL(il, oper1, options, PPC_IL_EXTRA_DEFAULT, addressSize_l); // d(rA) or 0
ei0 = il.Load(2, ei0); // [d(rA)]
- if(insn->id == PPC_INS_LHZ || insn->id == PPC_INS_LHZU)
+ if(instruction->id == PPC_ID_LHZ || instruction->id == PPC_ID_LHZU)
ei0 = il.ZeroExtend(addressSize_l, ei0);
else
ei0 = il.SignExtend(addressSize_l, ei0);
@@ -1069,24 +1016,26 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
// if update, rA is set to effective address (d(rA))
- if(insn->id == PPC_INS_LHZU || insn->id == PPC_INS_LHAU) {
- ei0 = il.SetRegister(addressSize_l, oper1->mem.base, operToIL_a(il, oper1, addressSize_l));
+ if (instruction->id == PPC_ID_LHZU || instruction->id == PPC_ID_LHAU)
+ {
+ ei0 = il.SetRegister(addressSize_l, oper1->mem.reg, operToIL_a(il, oper1, addressSize_l));
il.AddInstruction(ei0);
}
break;
+ }
/*
load half word [and zero/sign extend] [and update]
*/
- case PPC_INS_LHZX:
- case PPC_INS_LHZUX:
- case PPC_INS_LHAX:
- case PPC_INS_LHAUX:
+ case PPC_ID_LHZX:
+ case PPC_ID_LHZUX:
+ case PPC_ID_LHAX:
+ case PPC_ID_LHAUX:
REQUIRE3OPS
ei0 = operToIL(il, oper1, OTI_GPR0_ZERO, PPC_IL_EXTRA_DEFAULT, addressSize_l); // d(rA) or 0
ei0 = il.Load(2, il.Add(addressSize_l, ei0, operToIL_a(il, oper2, addressSize_l))); // [d(rA) + d(rB)]
- if(insn->id == PPC_INS_LHZX || insn->id == PPC_INS_LHZUX)
+ if(instruction->id == PPC_ID_LHZX || instruction->id == PPC_ID_LHZUX)
ei0 = il.ZeroExtend(addressSize_l, ei0);
else
ei0 = il.SignExtend(addressSize_l, ei0);
@@ -1094,7 +1043,7 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
// if update, rA is set to effective address (d(rA))
- if((insn->id == PPC_INS_LHZUX || insn->id == PPC_INS_LHAUX) && oper1->reg != oper0->reg && oper1->reg != PPC_REG_R0) {
+ if((instruction->id == PPC_ID_LHZUX || instruction->id == PPC_ID_LHAUX) && oper1->reg != oper0->reg && oper1->reg != PPC_REG_GPR0) {
ei0 = il.SetRegister(addressSize_l, oper1->reg, operToIL_a(il, oper1, addressSize_l));
il.AddInstruction(ei0);
}
@@ -1104,10 +1053,17 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
/*
load word [and zero] [and update]
*/
- case PPC_INS_LWZ:
- case PPC_INS_LWZU:
+ case PPC_ID_LWZ:
+ case PPC_ID_LWZU:
+ case PPC_ID_VLE_SE_LWZ:
+ {
+ // 16-bit VLE loads/stores treats r0 as a normal register
+ uint32_t options = OTI_GPR0_ZERO;
+ if (instruction->id == PPC_ID_VLE_SE_LWZ)
+ options = 0;
+
REQUIRE2OPS
- ei0 = operToIL(il, oper1, OTI_GPR0_ZERO, PPC_IL_EXTRA_DEFAULT, addressSize_l); // d(rA) or 0
+ ei0 = operToIL(il, oper1, options, PPC_IL_EXTRA_DEFAULT, addressSize_l); // d(rA) or 0
ei0 = il.Load(4, ei0); // [d(rA)]
if(addressSize_l == 8)
{
@@ -1117,19 +1073,19 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
// if update, rA is set to effective address (d(rA))
- if(insn->id == PPC_INS_LWZU)
- {
- ei0 = il.SetRegister(addressSize_l, oper1->mem.base, operToIL_a(il, oper1, addressSize_l));
+ if(instruction->id == PPC_ID_LWZU) {
+ ei0 = il.SetRegister(addressSize_l, oper1->mem.reg, operToIL_a(il, oper1, addressSize_l));
il.AddInstruction(ei0);
}
break;
+ }
/*
load word [and zero] [and update]
*/
- case PPC_INS_LWZX:
- case PPC_INS_LWZUX:
+ case PPC_ID_LWZX:
+ case PPC_ID_LWZUX:
REQUIRE3OPS
ei0 = operToIL(il, oper1, OTI_GPR0_ZERO, PPC_IL_EXTRA_DEFAULT, addressSize_l); // d(rA) or 0
ei0 = il.Load(4, il.Add(addressSize_l, ei0, operToIL_a(il, oper2, addressSize_l))); // [d(rA) + d(rB)]
@@ -1141,8 +1097,7 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
// if update, rA is set to effective address (d(rA))
- if(insn->id == PPC_INS_LWZUX && oper1->reg != oper0->reg && oper1->reg != PPC_REG_R0)
- {
+ if(instruction->id == PPC_ID_LWZUX && oper1->reg != oper0->reg && oper1->reg != PPC_REG_GPR0) {
ei0 = il.SetRegister(addressSize_l, oper1->reg, operToIL_a(il, oper1, addressSize_l));
il.AddInstruction(ei0);
}
@@ -1152,8 +1107,8 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
/*
load doubleword [and update]
*/
- case PPC_INS_LD:
- case PPC_INS_LDU:
+ case PPC_ID_LD:
+ case PPC_ID_LDU:
REQUIRE2OPS
ei0 = operToIL(il, oper1, OTI_GPR0_ZERO); // d(rA) or 0
ei0 = il.Load(8, ei0); // [d(rA)]
@@ -1161,8 +1116,8 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
// if update, rA is set to effective address (d(rA))
- if(insn->id == PPC_INS_LWZU) {
- ei0 = il.SetRegister(8, oper1->mem.base, operToIL(il, oper1));
+ if(instruction->id == PPC_ID_LWZU) {
+ ei0 = il.SetRegister(8, oper1->mem.reg, operToIL(il, oper1));
il.AddInstruction(ei0);
}
@@ -1171,8 +1126,8 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
/*
load doubleword [and update]
*/
- case PPC_INS_LDX:
- case PPC_INS_LDUX:
+ case PPC_ID_LDX:
+ case PPC_ID_LDUX:
REQUIRE3OPS
ei0 = operToIL(il, oper1, OTI_GPR0_ZERO); // d(rA) or 0
ei0 = il.Load(8, il.Add(8, ei0, operToIL(il, oper2))); // [d(rA) + d(rB)]
@@ -1180,124 +1135,115 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
// if update, rA is set to effective address (d(rA))
- if(insn->id == PPC_INS_LWZUX && oper1->reg != oper0->reg && oper1->reg != PPC_REG_R0) {
+ if(instruction->id == PPC_ID_LWZUX && oper1->reg != oper0->reg && oper1->reg != PPC_REG_GPR0) {
ei0 = il.SetRegister(8, oper1->reg, operToIL(il, oper1));
il.AddInstruction(ei0);
}
break;
- case PPC_INS_LHBRX:
+ case PPC_ID_LHBRX:
REQUIRE3OPS
- ByteReversedLoad(il, ppc, 2, addressSize_l);
+ ByteReversedLoad(il, instruction, 2, addressSize_l);
break;
- case PPC_INS_LWBRX:
+ case PPC_ID_LWBRX:
REQUIRE3OPS
- ByteReversedLoad(il, ppc, 4, addressSize_l);
+ ByteReversedLoad(il, instruction, 4, addressSize_l);
break;
- case PPC_INS_STHBRX:
+ case PPC_ID_STHBRX:
REQUIRE3OPS
- ByteReversedStore(il, ppc, 2, addressSize_l);
+ ByteReversedStore(il, instruction, 2, addressSize_l);
break;
- case PPC_INS_STWBRX:
+ case PPC_ID_STWBRX:
REQUIRE3OPS
- ByteReversedStore(il, ppc, 4, addressSize_l);
+ ByteReversedStore(il, instruction, 4, addressSize_l);
break;
- case PPC_INS_MFCTR: // move from ctr
+ case PPC_ID_MFCTR: // move from ctr
REQUIRE1OP
il.AddInstruction(il.SetRegister(addressSize_l, oper0->reg, il.Register(addressSize_l, PPC_REG_CTR)));
break;
- case PPC_INS_MFLR: // move from link register
+ case PPC_ID_MFLR: // move from link register
REQUIRE1OP
il.AddInstruction(il.SetRegister(addressSize_l, oper0->reg, il.Register(addressSize_l, PPC_REG_LR)));
break;
- case PPC_INS_MTCTR: // move to ctr
+ case PPC_ID_MTCTR: // move to ctr
REQUIRE1OP
il.AddInstruction(il.SetRegister(addressSize_l, PPC_REG_CTR, operToIL_a(il, oper0, addressSize_l)));
break;
- case PPC_INS_MTLR: // move to link register
+ case PPC_ID_MTLR: // move to link register
REQUIRE1OP
il.AddInstruction(il.SetRegister(addressSize_l, PPC_REG_LR, operToIL_a(il, oper0, addressSize_l)));
break;
- case PPC_INS_NEG:
+ case PPC_ID_NEGx:
REQUIRE2OPS
- ei0 = il.Neg(addressSize_l, operToIL_a(il, oper1, addressSize_l));
+ ei0 = il.Neg(addressSize_l, operToIL(il, oper1));
il.AddInstruction(il.SetRegister(addressSize_l, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
));
break;
- case PPC_INS_NOP:
+ case PPC_ID_NOP:
il.AddInstruction(il.Nop());
break;
- case PPC_INS_NOT:
- REQUIRE2OPS
- ei0 = il.Not(addressSize_l, operToIL_a(il, oper1, addressSize_l));
- il.AddInstruction(il.SetRegister(addressSize_l, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
- ));
- break;
-
- case PPC_INS_OR:
- case PPC_INS_ORC:
- case PPC_INS_NOR:
+ case PPC_ID_ORx:
+ case PPC_ID_ORCx:
+ case PPC_ID_NORx:
REQUIRE3OPS
ei0 = operToIL_a(il, oper2, addressSize_l);
- if (insn->id == PPC_INS_ORC)
+ if (instruction->id == PPC_ID_ORCx)
ei0 = il.Not(addressSize_l, ei0);
ei0 = il.Or(addressSize_l, operToIL_a(il, oper1, addressSize_l), ei0);
- if (insn->id == PPC_INS_NOR)
+ if (instruction->id == PPC_ID_NORx)
ei0 = il.Not(addressSize_l, ei0);
ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_ORI:
- case PPC_INS_ORIS:
+ case PPC_ID_ORIx:
+ case PPC_ID_ORIS:
REQUIRE3OPS
- if (insn->id == PPC_INS_ORIS)
- ei0 = il.Const(addressSize_l, oper2->imm << 16);
+ if (instruction->id == PPC_ID_ORIS)
+ ei0 = il.Const(addressSize_l, oper2->uimm << 16);
else
- ei0 = il.Const(addressSize_l, oper2->imm);
+ ei0 = il.Const(addressSize_l, oper2->uimm);
ei0 = il.Or(addressSize_l, operToIL_a(il, oper1, addressSize_l), ei0);
ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0);
il.AddInstruction(ei0);
break;
- case PPC_INS_XOR:
- case PPC_INS_EQV:
+ case PPC_ID_XORx:
+ case PPC_ID_EQVx:
REQUIRE3OPS
ei0 = il.Xor(addressSize_l,
operToIL_a(il, oper1, addressSize_l),
operToIL_a(il, oper2, addressSize_l)
);
- if (insn->id == PPC_INS_EQV)
+ if (instruction->id == PPC_ID_EQVx)
ei0 = il.Not(addressSize_l, ei0);
ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_XORI:
- case PPC_BN_INS_XORI:
- case PPC_INS_XORIS:
+ case PPC_ID_XORIx:
+ case PPC_ID_XORIS:
REQUIRE3OPS
- if (insn->id == PPC_INS_XORIS)
- ei0 = il.Const(addressSize_l, oper2->imm << 16);
+ if (instruction->id == PPC_ID_XORIS)
+ ei0 = il.Const(addressSize_l, oper2->uimm << 16);
else
- ei0 = il.Const(addressSize_l, oper2->imm);
+ ei0 = il.Const(addressSize_l, oper2->uimm);
ei0 = il.SetRegister(
addressSize_l,
oper0->reg,
@@ -1309,23 +1255,23 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
break;
- case PPC_INS_SUBF:
- case PPC_INS_SUBFC:
- case PPC_INS_SUBFIC:
+ case PPC_ID_SUBFx:
+ case PPC_ID_SUBFCx:
+ case PPC_ID_SUBFICx:
REQUIRE3OPS
ei0 = il.Sub(
addressSize_l,
operToIL_a(il, oper2, addressSize_l),
operToIL_a(il, oper1, addressSize_l),
- (insn->id != PPC_INS_SUBF) ? IL_FLAGWRITE_XER_CA : 0
+ (instruction->id != PPC_ID_SUBFx) ? IL_FLAGWRITE_XER_CA : 0
);
ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_SUBFE:
+ case PPC_ID_SUBFEx:
REQUIRE3OPS
ei0 = il.SubBorrow(
addressSize_l,
@@ -1335,15 +1281,15 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
IL_FLAGWRITE_XER_CA
);
ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_SUBFME:
- case PPC_INS_SUBFZE:
+ case PPC_ID_SUBFMEx:
+ case PPC_ID_SUBFZEx:
REQUIRE2OPS
- if (insn->id == PPC_INS_SUBFME)
+ if (instruction->id == PPC_ID_SUBFMEx)
ei0 = il.Const(addressSize_l, ADDRNEG1(addressSize_l));
else
ei0 = il.Const(addressSize_l, 0);
@@ -1355,14 +1301,15 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
IL_FLAGWRITE_XER_CA
);
ei0 = il.SetRegister(addressSize_l, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_STMW:
+ case PPC_ID_STMW:
REQUIRE2OPS
- for(i=oper0->reg; i<=PPC_REG_R31; ++i) {
+ for (i = oper0->reg; i <= PPC_REG_GPR31; ++i)
+ {
ei0 = il.Register(4, i); // source
ei1 = operToIL(il, oper1, OTI_IMM_BIAS, (i-(oper0->reg))*4, addressSize_l);
il.AddInstruction(
@@ -1376,26 +1323,34 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
break;
/* store half word [with update] */
- case PPC_INS_STB:
- case PPC_INS_STBU: /* store(size, addr, val) */
+ case PPC_ID_STB:
+ case PPC_ID_STBU: /* store(size, addr, val) */
+ case PPC_ID_VLE_SE_STB:
+ {
+ // 16-bit VLE loads/stores treats r0 as a normal register
+ uint32_t options = OTI_GPR0_ZERO;
+ if (instruction->id == PPC_ID_VLE_SE_STB)
+ options = 0;
+
REQUIRE2OPS
ei0 = il.Store(1,
- operToIL(il, oper1, OTI_GPR0_ZERO, PPC_IL_EXTRA_DEFAULT, addressSize_l),
+ operToIL(il, oper1, options, PPC_IL_EXTRA_DEFAULT, addressSize_l),
il.LowPart(1, operToIL_a(il, oper0, addressSize_l))
);
il.AddInstruction(ei0);
// if update, then rA gets updated address
- if(insn->id == PPC_INS_STBU) {
- ei0 = il.SetRegister(addressSize_l, oper1->mem.base, operToIL_a(il, oper1, addressSize_l));
+ if(instruction->id == PPC_ID_STBU) {
+ ei0 = il.SetRegister(addressSize_l, oper1->mem.reg, operToIL_a(il, oper1, addressSize_l));
il.AddInstruction(ei0);
}
break;
+ }
/* store half word indexed [with update] */
- case PPC_INS_STBX:
- case PPC_INS_STBUX: /* store(size, addr, val) */
+ case PPC_ID_STBX:
+ case PPC_ID_STBUX: /* store(size, addr, val) */
REQUIRE3OPS
ei0 = il.Store(1,
il.Add(
@@ -1407,7 +1362,7 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
// if update, then rA gets updated address
- if(insn->id == PPC_INS_STBUX) {
+ if(instruction->id == PPC_ID_STBUX) {
ei0 = il.SetRegister(addressSize_l, oper1->reg,
il.Add(addressSize_l, operToIL_a(il, oper1, addressSize_l), operToIL_a(il, oper2, addressSize_l))
);
@@ -1417,26 +1372,34 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
break;
/* store half word [with update] */
- case PPC_INS_STH:
- case PPC_INS_STHU: /* store(size, addr, val) */
+ case PPC_ID_STH:
+ case PPC_ID_STHU: /* store(size, addr, val) */
+ case PPC_ID_VLE_SE_STH:
+ {
+ // 16-bit VLE loads/stores treats r0 as a normal register
+ uint32_t options = OTI_GPR0_ZERO;
+ if (instruction->id == PPC_ID_VLE_SE_STH)
+ options = 0;
+
REQUIRE2OPS
ei0 = il.Store(2,
- operToIL(il, oper1, OTI_GPR0_ZERO, PPC_IL_EXTRA_DEFAULT, addressSize_l),
+ operToIL(il, oper1, options, PPC_IL_EXTRA_DEFAULT, addressSize_l),
il.LowPart(2, operToIL_a(il, oper0, addressSize_l))
);
il.AddInstruction(ei0);
// if update, then rA gets updated address
- if(insn->id == PPC_INS_STHU) {
- ei0 = il.SetRegister(addressSize_l, oper1->mem.base, operToIL_a(il, oper1, addressSize_l));
+ if(instruction->id == PPC_ID_STHU) {
+ ei0 = il.SetRegister(addressSize_l, oper1->mem.reg, operToIL_a(il, oper1, addressSize_l));
il.AddInstruction(ei0);
}
break;
+ }
/* store half word indexed [with update] */
- case PPC_INS_STHX:
- case PPC_INS_STHUX: /* store(size, addr, val) */
+ case PPC_ID_STHX:
+ case PPC_ID_STHUX: /* store(size, addr, val) */
REQUIRE3OPS
ei0 = il.Store(2,
il.Add(
@@ -1448,7 +1411,7 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
// if update, then rA gets updated address
- if(insn->id == PPC_INS_STHUX) {
+ if(instruction->id == PPC_ID_STHUX) {
ei0 = il.SetRegister(addressSize_l, oper1->reg,
il.Add(addressSize_l, operToIL_a(il, oper1, addressSize_l), operToIL_a(il, oper2, addressSize_l))
);
@@ -1458,8 +1421,15 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
break;
/* store word [with update] */
- case PPC_INS_STW:
- case PPC_INS_STWU: /* store(size, addr, val) */
+ case PPC_ID_STW:
+ case PPC_ID_STWU: /* store(size, addr, val) */
+ case PPC_ID_VLE_SE_STW:
+ {
+ // 16-bit VLE loads/stores treats r0 as a normal register
+ uint32_t options = OTI_GPR0_ZERO;
+ if (instruction->id == PPC_ID_VLE_SE_STW)
+ options = 0;
+
REQUIRE2OPS
if (addressSize_l == 8)
{
@@ -1469,23 +1439,25 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
{
ei0 = operToIL(il, oper0);
}
+
ei0 = il.Store(4,
- operToIL(il, oper1, OTI_GPR0_ZERO, PPC_IL_EXTRA_DEFAULT, addressSize_l),
+ operToIL(il, oper1, options, PPC_IL_EXTRA_DEFAULT, addressSize_l),
ei0
);
il.AddInstruction(ei0);
// if update, then rA gets updated address
- if(insn->id == PPC_INS_STWU) {
- ei0 = il.SetRegister(addressSize_l, oper1->mem.base, operToIL_a(il, oper1, addressSize_l));
+ if(instruction->id == PPC_ID_STWU) {
+ ei0 = il.SetRegister(addressSize_l, oper1->mem.reg, operToIL_a(il, oper1, addressSize_l));
il.AddInstruction(ei0);
}
break;
+ }
/* store word indexed [with update] */
- case PPC_INS_STWX:
- case PPC_INS_STWUX: /* store(size, addr, val) */
+ case PPC_ID_STWX:
+ case PPC_ID_STWUX: /* store(size, addr, val) */
REQUIRE3OPS
if (addressSize_l == 8)
{
@@ -1505,7 +1477,7 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
// if update, then rA gets updated address
- if(insn->id == PPC_INS_STWUX) {
+ if(instruction->id == PPC_ID_STWUX) {
ei0 = il.SetRegister(addressSize_l, oper1->reg,
il.Add(addressSize_l, operToIL_a(il, oper1, addressSize_l), operToIL_a(il, oper2, addressSize_l))
);
@@ -1515,8 +1487,8 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
break;
/* store double word [with update] */
- case PPC_INS_STD:
- case PPC_INS_STDU: /* store(size, addr, val) */
+ case PPC_ID_STD:
+ case PPC_ID_STDU: /* store(size, addr, val) */
REQUIRE2OPS
ei0 = il.Store(8,
operToIL(il, oper1, OTI_GPR0_ZERO, PPC_IL_OPTIONS_DEFAULT, addressSize_l),
@@ -1525,16 +1497,16 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
// if update, then rA gets updated address
- if(insn->id == PPC_INS_STDU) {
- ei0 = il.SetRegister(8, oper1->mem.base, operToIL_a(il, oper1, 8));
+ if(instruction->id == PPC_ID_STWU) {
+ ei0 = il.SetRegister(8, oper1->mem.reg, operToIL_a(il, oper1, 8));
il.AddInstruction(ei0);
}
break;
/* store word indexed [with update] */
- case PPC_INS_STDX:
- case PPC_INS_STDUX: /* store(size, addr, val) */
+ case PPC_ID_STDX:
+ case PPC_ID_STDUX: /* store(size, addr, val) */
REQUIRE3OPS
ei0 = il.Store(8,
il.Add(8, operToIL(il, oper1, OTI_GPR0_ZERO), operToIL_a(il, oper2, addressSize_l)),
@@ -1543,7 +1515,7 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
// if update, then rA gets updated address
- if(insn->id == PPC_INS_STDUX) {
+ if(instruction->id == PPC_ID_STDUX) {
ei0 = il.SetRegister(8, oper1->reg,
il.Add(8, operToIL_a(il, oper1, 8), operToIL_a(il, oper2, 8))
);
@@ -1552,21 +1524,21 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
break;
- case PPC_INS_RLWIMI:
+ case PPC_ID_RLWIMIx:
REQUIRE5OPS
{
- uint32_t mask = genMask(oper3->imm, oper4->imm);
+ uint32_t mask = genMask(oper3->uimm, oper4->uimm);
ei0 = il.Register(4, oper1->reg);
- if (oper2->imm != 0)
+ if (oper2->uimm != 0)
{
- if ((mask & (~0u >> (32 - oper2->imm))) == 0)
- ei0 = il.ShiftLeft(4, ei0, il.Const(4, oper2->imm));
- else if ((mask & (~0u << oper2->imm)) == 0)
- ei0 = il.LogicalShiftRight(4, ei0, il.Const(4, 32 - oper2->imm));
+ if ((mask & (~0u >> (32 - oper2->uimm))) == 0)
+ ei0 = il.ShiftLeft(4, ei0, il.Const(4, oper2->uimm));
+ else if ((mask & (~0u << oper2->uimm)) == 0)
+ ei0 = il.LogicalShiftRight(4, ei0, il.Const(4, 32 - oper2->uimm));
else
- ei0 = il.RotateLeft(4, ei0, il.Const(4, oper2->imm));
+ ei0 = il.RotateLeft(4, ei0, il.Const(4, oper2->uimm));
}
ei0 = il.And(4, ei0, il.Const(4, mask));
@@ -1574,38 +1546,74 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
ei0 = il.Or(4, il.And(4, il.Register(4, oper0->reg), il.Const(4, invertMask)), ei0);
ei0 = il.SetRegister(4, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
+ );
+ il.AddInstruction(ei0);
+ }
+ break;
+
+ case PPC_ID_RLDIMIx:
+ case PPC_ID_RLDICx:
+ REQUIRE4OPS
+ {
+ uint64_t mask = 0;
+ uint64_t sh = oper2->uimm;
+ uint64_t mb = oper3 ? oper3->uimm : 0;
+ uint64_t me = 63 - sh;
+ mask = genMask64(mb, me);
+
+ ei0 = il.Register(8, oper1->reg);
+
+ if (sh != 0)
+ {
+ if ((mask & (~0ull >> (64 - sh))) == 0)
+ ei0 = il.ShiftLeft(8, ei0, il.Const(8, sh));
+ else if ((mask & (~0ull << sh)) == 0)
+ ei0 = il.LogicalShiftRight(8, ei0, il.Const(8, 64 - sh));
+ else
+ ei0 = il.RotateLeft(8, ei0, il.Const(8, sh));
+ }
+
+ ei0 = il.And(8, ei0, il.Const(8, mask));
+ if (instruction->id == PPC_ID_RLDIMIx)
+ {
+ uint64_t invertMask = ~mask;
+ ei0 = il.Or(8, il.And(8, il.Register(8, oper0->reg), il.Const(8, invertMask)), ei0);
+ }
+
+ ei0 = il.SetRegister(8, oper0->reg, ei0,
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
}
break;
- case PPC_INS_RLWINM:
+ case PPC_ID_RLWINMx:
REQUIRE5OPS
{
- uint32_t mask = genMask(oper3->imm, oper4->imm);
+ uint32_t mask = genMask(oper3->uimm, oper4->uimm);
ei0 = il.Register(4, oper1->reg);
- if (oper2->imm != 0)
+ if (oper2->uimm != 0)
{
- if ((mask & (~0u >> (32 - oper2->imm))) == 0)
+ if ((mask & (~0u >> (32 - oper2->uimm))) == 0)
{
if (mask != 0xffffffff)
- ei0 = il.And(4, ei0, il.Const(4, mask >> oper2->imm));
+ ei0 = il.And(4, ei0, il.Const(4, mask >> oper2->uimm));
- ei0 = il.ShiftLeft(4, ei0, il.Const(4, oper2->imm));
+ ei0 = il.ShiftLeft(4, ei0, il.Const(4, oper2->uimm));
}
- else if ((mask & (~0u << oper2->imm)) == 0)
+ else if ((mask & (~0u << oper2->uimm)) == 0)
{
if (mask != 0xffffffff)
- ei0 = il.And(4, ei0, il.Const(4, mask << (32 - oper2->imm)));
+ ei0 = il.And(4, ei0, il.Const(4, mask << (32 - oper2->uimm)));
- ei0 = il.LogicalShiftRight(4, ei0, il.Const(4, 32 - oper2->imm));
+ ei0 = il.LogicalShiftRight(4, ei0, il.Const(4, 32 - oper2->uimm));
}
else
{
- ei0 = il.RotateLeft(4, ei0, il.Const(4, oper2->imm));
+ ei0 = il.RotateLeft(4, ei0, il.Const(4, oper2->uimm));
if (mask != 0xffffffff)
ei0 = il.And(4, ei0, il.Const(4, mask));
@@ -1617,64 +1625,204 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
}
ei0 = il.SetRegister(4, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
}
break;
- case PPC_INS_SLWI:
+ case PPC_ID_RLDICRx:
+ case PPC_ID_RLDICLx:
+ case PPC_ID_EXTLDIx:
+ case PPC_ID_EXTRDIx:
+ REQUIRE4OPS
+ case PPC_ID_CLRLDIx:
+ case PPC_ID_CLRRDIx:
+ // case PPC_ID_SLDIx:
+ // case PPC_ID_SRDIx:
+ case PPC_ID_ROTLDIx:
+ case PPC_ID_ROTRDIx:
REQUIRE3OPS
- ei0 = il.Const(4, oper2->imm); // amt: shift amount
- ei1 = il.Register(4, oper1->reg); // rS: reg to be shifted
- ei0 = il.ShiftLeft(4, ei1, ei0); // (rS << amt)
- ei0 = il.SetRegister(4, oper0->reg, ei0, // rD = (rs << amt)
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ {
+ uint64_t mask = 0;
+ uint64_t sh = oper2->uimm;
+ uint64_t mb = oper3 ? oper3->uimm : 0;
+ uint64_t me = oper3 ? oper3->uimm : 0;
+
+ switch (instruction->id)
+ {
+ case PPC_ID_CLRRDIx: me = 63 - sh; sh = 0;
+ // case PPC_ID_EXTLDIx:
+ case PPC_ID_RLDICRx: mb = 0; break;
+ case PPC_ID_EXTLDIx: sh = oper3->uimm; mb = 0; me = oper2->uimm - 1; break;
+
+ case PPC_ID_CLRLDIx: mb = sh; sh = 0;
+ // case PPC_ID_EXTRDIx:
+ case PPC_ID_RLDICLx: me = 63; break;
+ case PPC_ID_EXTRDIx: sh = oper2->uimm + oper3->uimm; mb = 64 - oper2->uimm; me = 63; break;
+
+ case PPC_ID_SLDIx: mb = 0; me = 63 - sh; break;
+ case PPC_ID_SRDIx: mb = 64 - sh; me = sh; break;
+
+ case PPC_ID_ROTLDIx: mb = 0; me = 63; break;
+ case PPC_ID_ROTRDIx: mb = 0; me = 63; sh = 64 - sh; break;
+ default: // Impossible
+ ;
+ }
+ mask = genMask64(mb, me);
+
+ ei0 = il.Register(8, oper1->reg);
+
+ if (sh != 0)
+ {
+ if ((mask & (~0ull >> (64 - sh))) == 0)
+ {
+ if (mask != 0xffffffffffffffff)
+ ei0 = il.And(8, ei0, il.Const(8, mask >> sh));
+
+ ei0 = il.ShiftLeft(8, ei0, il.Const(8, sh));
+ }
+ else if ((mask & (~0ull << sh)) == 0)
+ {
+ if (mask != 0xffffffffffffffff)
+ ei0 = il.And(8, ei0, il.Const(8, mask << (64 - sh)));
+
+ ei0 = il.LogicalShiftRight(8, ei0, il.Const(8, 64 - sh));
+ }
+ else
+ {
+ ei0 = il.RotateLeft(8, ei0, il.Const(8, sh));
+
+ if (mask != 0xffffffffffffffff)
+ ei0 = il.And(8, ei0, il.Const(8, mask));
+ }
+ }
+ else if (mask != 0xffffffffffffffff)
+ {
+ ei0 = il.And(8, ei0, il.Const(8, mask));
+ }
+
+ ei0 = il.SetRegister(8, oper0->reg, ei0,
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
+ );
+ il.AddInstruction(ei0);
+ }
+ break;
+
+ case PPC_ID_SLDIx:
+ opSize = 8;
+ case PPC_ID_SLWIx:
+ REQUIRE3OPS
+ ei0 = il.Const(opSize, oper2->uimm); // amt: shift amount
+ ei1 = il.Register(opSize, oper1->reg); // rS: reg to be shifted
+ ei0 = il.ShiftLeft(opSize, ei1, ei0); // (rS << amt)
+ ei0 = il.SetRegister(opSize, oper0->reg, ei0, // rD = (rs << amt)
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_SRWI:
+ case PPC_ID_SRDIx:
+ opSize = 8;
+ case PPC_ID_SRWIx:
REQUIRE3OPS
- ei0 = il.Const(4, oper2->imm); // amt: shift amount
- ei1 = il.Register(4, oper1->reg); // rS: reg to be shifted
- ei0 = il.LogicalShiftRight(4, ei1, ei0); // (rS << amt)
- ei0 = il.SetRegister(4, oper0->reg, ei0, // rD = (rs << amt)
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ ei0 = il.Const(opSize, oper2->uimm); // amt: shift amount
+ ei1 = il.Register(opSize, oper1->reg); // rS: reg to be shifted
+ ei0 = il.LogicalShiftRight(opSize, ei1, ei0); // (rS << amt)
+ ei0 = il.SetRegister(opSize, oper0->reg, ei0, // rD = (rs << amt)
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_CLRLWI:
+ case PPC_ID_CLRRWIx:
REQUIRE3OPS
- ei0 = il.Const(4, (uint32_t) (0xffffffff >> oper2->imm));
- ei1 = il.Register(4, oper1->reg);
- ei0 = il.And(4, ei1, ei0);
- ei0 = il.SetRegister(4, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ ei0 = il.Const(opSize, (uint32_t)(0xffffffff << (oper2->uimm)));
+ ei1 = il.Register(opSize, oper1->reg);
+ ei0 = il.And(opSize, ei1, ei0);
+ ei0 = il.SetRegister(opSize, oper0->reg, ei0,
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_ROTLWI:
+ // case PPC_ID_CLRLDIx:
+ // opSize = 8;
+ case PPC_ID_CLRLWIx:
+ REQUIRE3OPS
+ switch (instruction->id)
+ {
+ case PPC_ID_CLRLDIx:
+ ei0 = il.Const(opSize, (uint64_t)(0xffff'ffff'ffff'ffff >> oper2->uimm));
+ break;
+
+ case PPC_ID_CLRLWIx:
+ ei0 = il.Const(opSize, (uint32_t)(0xffffffff >> oper2->uimm));
+ break;
+ default: // Impossible
+ ;
+ }
+ ei1 = il.Register(opSize, oper1->reg);
+ ei0 = il.And(opSize, ei1, ei0);
+ ei0 = il.SetRegister(opSize, oper0->reg, ei0,
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
+ );
+ il.AddInstruction(ei0);
+ break;
+
+ // case PPC_ID_CLRLWIx:
+ // REQUIRE3OPS
+ // ei0 = il.Const(4, (uint32_t) (0xffffffff >> oper2->uimm));
+ // ei1 = il.Register(4, oper1->reg);
+ // ei0 = il.And(4, ei1, ei0);
+ // ei0 = il.SetRegister(4, oper0->reg, ei0,
+ // instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
+ // );
+ // il.AddInstruction(ei0);
+ // break;
+
+ case PPC_ID_ROTLWIx:
REQUIRE3OPS
ei0 = il.Register(4, oper1->reg);
- ei0 = il.RotateLeft(4, ei0, il.Const(4, oper2->imm));
+ ei0 = il.RotateLeft(4, ei0, il.Const(4, oper2->uimm));
ei0 = il.SetRegister(4, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
break;
- case PPC_INS_ROTLW:
- case PPC_INS_RLWNM:
+ case PPC_ID_RLDCLx:
+ case PPC_ID_RLDCRx:
+ REQUIRE4OPS;
+ case PPC_ID_ROTLDx:
+ REQUIRE3OPS;
+ {
+ uint64_t mask = 0;
+ uint64_t mx = oper3 ? oper3->uimm : 0;
+ if (instruction->id == PPC_ID_RLDCRx)
+ mask = genMask64(0, mx);
+ else
+ mask = genMask64(mx, 63);
+
+ ei0 = il.Register(8, oper1->reg);
+ ei0 = il.RotateLeft(8, il.Register(8, oper2->reg), ei0);
+ if (mask != 0xffffffffffffffff)
+ ei0 = il.And(8, ei0, il.Const(8, mask));
+ ei0 = il.SetRegister(8, oper0->reg, ei0,
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
+ );
+ il.AddInstruction(ei0);
+ }
+
+ case PPC_ID_ROTLWx:
+ case PPC_ID_RLWNMx:
REQUIRE3OPS
{
uint32_t mask = 0xffffffff;
- if (insn->id == PPC_INS_RLWNM)
+ if (instruction->id == PPC_ID_RLWNMx)
{
REQUIRE5OPS
- mask = genMask(oper3->imm, oper4->imm);
+ mask = genMask(oper3->uimm, oper4->uimm);
}
ei0 = il.Register(4, oper1->reg);
ei1 = il.Register(4, oper2->reg);
@@ -1683,230 +1831,213 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
if (mask != 0xffffffff)
ei0 = il.And(4, ei0, il.Const(4, mask));
ei0 = il.SetRegister(4, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
);
il.AddInstruction(ei0);
}
break;
- case PPC_INS_SLW:
- case PPC_INS_SRW:
+ case PPC_ID_SLWx:
+ case PPC_ID_SRWx:
REQUIRE3OPS
ei0 = il.Register(4, oper1->reg);
// permit bit 26 to survive to enable clearing the whole register
ei1 = il.And(4, il.Register(4, oper2->reg), il.Const(4, 0x3f));
- if (insn->id == PPC_INS_SLW)
+ if (instruction->id == PPC_ID_SLWx)
ei0 = il.ShiftLeft(4, ei0, ei1);
else
ei0 = il.LogicalShiftRight(4, ei0, ei1);
il.AddInstruction(il.SetRegister(4, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
));
break;
- case PPC_INS_SLD:
- case PPC_INS_SRD:
+ case PPC_ID_SLDx:
+ case PPC_ID_SRDx:
REQUIRE3OPS
ei0 = il.Register(8, oper1->reg);
// permit bit 25 to survive to enable clearing the whole register
ei1 = il.And(8, il.Register(8, oper2->reg), il.Const(8, 0x7f));
- if (insn->id == PPC_INS_SLD)
+ if (instruction->id == PPC_ID_SLDx)
ei0 = il.ShiftLeft(8, ei0, ei1);
else
ei0 = il.LogicalShiftRight(8, ei0, ei1);
il.AddInstruction(il.SetRegister(8, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
));
break;
- case PPC_INS_SRAW:
+ case PPC_ID_SRAWx:
REQUIRE3OPS
ei0 = il.Register(4, oper1->reg);
ei1 = il.And(4, il.Register(4, oper2->reg), il.Const(4, 0x1f));
ei0 = il.ArithShiftRight(4, ei0, ei1, IL_FLAGWRITE_XER_CA);
il.AddInstruction(il.SetRegister(4, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
));
break;
- case PPC_INS_SRAWI:
+ case PPC_ID_SRAWIx:
REQUIRE3OPS
ei0 = il.Register(4, oper1->reg);
- ei0 = il.ArithShiftRight(4, ei0, il.Const(4, oper2->imm), IL_FLAGWRITE_XER_CA);
+ ei0 = il.ArithShiftRight(4, ei0, il.Const(4, oper2->uimm), IL_FLAGWRITE_XER_CA);
il.AddInstruction(il.SetRegister(4, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
));
break;
- case PPC_INS_SRAD:
+ case PPC_ID_SRADx:
REQUIRE3OPS
ei0 = il.Register(8, oper1->reg);
ei1 = il.And(8, il.Register(8, oper2->reg), il.Const(8, 0x3f));
ei0 = il.ArithShiftRight(8, ei0, ei1, IL_FLAGWRITE_XER_CA);
il.AddInstruction(il.SetRegister(8, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
));
break;
- case PPC_INS_SRADI:
+ case PPC_ID_SRADIx:
REQUIRE3OPS
ei0 = il.Register(8, oper1->reg);
- ei0 = il.ArithShiftRight(8, ei0, il.Const(8, oper2->imm), IL_FLAGWRITE_XER_CA);
+ ei0 = il.ArithShiftRight(8, ei0, il.Const(8, oper2->uimm), IL_FLAGWRITE_XER_CA);
il.AddInstruction(il.SetRegister(8, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
));
break;
- case PPC_INS_MULLW:
+ case PPC_ID_MULLWx:
REQUIRE3OPS
ei0 = il.Register(4, oper1->reg);
- ei0 = il.Mult(4, ei0, il.Register(4, oper2->reg));
+ ei0 = il.MultDoublePrecUnsigned(4, ei0, il.Register(4, oper2->reg));
+ ei0 = il.LowPart(4, ei0);
il.AddInstruction(il.SetRegister(4, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
));
break;
- case PPC_INS_MULLI:
+ case PPC_ID_MULLI:
REQUIRE3OPS
ei0 = il.Register(4, oper1->reg);
- ei0 = il.Mult(4, ei0, il.Const(4, oper2->imm));
+ ei0 = il.MultDoublePrecUnsigned(4, ei0, il.Const(4, oper2->uimm));
+ ei0 = il.LowPart(4, ei0);
il.AddInstruction(il.SetRegister(4, oper0->reg, ei0));
break;
- case PPC_INS_MULHW:
+ case PPC_ID_MULHWx:
REQUIRE3OPS
ei0 = il.Register(4, oper1->reg);
ei0 = il.MultDoublePrecSigned(4, ei0, il.Register(4, oper2->reg));
- // TODO: This may be incorrect for 64-bit mode:
- // The 32-bit operands are the low-order 32 bits of RA and */ of RB.The high - order 32 bits of the 64 - bit product of the operands are placed into RT32 : 63. The contents of RT0 : 31 are undefined.
ei0 = il.LowPart(4, il.LogicalShiftRight(8, ei0, il.Const(1, 32)));
il.AddInstruction(il.SetRegister(4, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
));
break;
- case PPC_INS_MULHWU:
+ case PPC_ID_MULHWUx:
REQUIRE3OPS
ei0 = il.Register(4, oper1->reg);
ei0 = il.MultDoublePrecUnsigned(4, ei0, il.Register(4, oper2->reg));
- // TODO: This may be incorrect for 64-bit mode:
- // The 32-bit operands are the low-order 32 bits of RA and */ of RB.The high - order 32 bits of the 64 - bit product of the operands are placed into RT32 : 63. The contents of RT0 : 31 are undefined.
ei0 = il.LowPart(4, il.LogicalShiftRight(8, ei0, il.Const(1, 32)));
il.AddInstruction(il.SetRegister(4, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
));
break;
- case PPC_INS_DIVW:
+ case PPC_ID_DIVWx:
REQUIRE3OPS
ei0 = il.Register(4, oper1->reg);
ei0 = il.DivSigned(4, ei0, il.Register(4, oper2->reg));
il.AddInstruction(il.SetRegister(4, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
));
break;
- case PPC_INS_DIVWU:
+ case PPC_ID_DIVWUx:
REQUIRE3OPS
ei0 = il.Register(4, oper1->reg);
ei0 = il.DivUnsigned(4, ei0, il.Register(4, oper2->reg));
il.AddInstruction(il.SetRegister(4, oper0->reg, ei0,
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0
));
break;
- case PPC_INS_MR: /* move register */
+ case PPC_ID_MRx: /* move register */
REQUIRE2OPS
ei0 = il.SetRegister(addressSize_l, oper0->reg, operToIL_a(il, oper1, addressSize_l),
- ppc->update_cr0 ? IL_FLAGWRITE_CR0_S : 0);
+ instruction->flags.rc ? IL_FLAGWRITE_CR0_S : 0);
il.AddInstruction(ei0);
break;
- case PPC_INS_SC:
+ case PPC_ID_SC:
il.AddInstruction(il.SystemCall());
break;
- case PPC_INS_RFI:
+ case PPC_ID_RFI:
il.AddInstruction(il.Return(il.Unimplemented()));
break;
- case PPC_INS_TRAP:
+ case PPC_ID_TWU:
il.AddInstruction(il.Trap(0));
break;
-// =====================================
-// =====FLOATING POINT INSTRUCTIONS=====
-// =====================================
-
- // case PPC_INS_FCMPO: /* compare (signed) word(32-bit) */
- // REQUIRE2OPS
- // ei0 = operToIL(il, oper2 ? oper1 : oper0);
- // ei1 = operToIL(il, oper2 ? oper2 : oper1);
- // ei2 = il.Sub(4, ei0, ei1, crxToFlagWriteType(oper2 ? oper0->reg : PPC_REG_CR0));
- // il.AddInstruction(ei2);
- // break;
+ // =====================================
+ // =====FLOATING POINT INSTRUCTIONS=====
+ // =====================================
- // for this one, i guess the easiest thing to do is to summarize it by
- // the end result. For this instuction to happen, the end result is:
- // register Fn is stored at Rn.
- // how do we achieve this result in IL?
- // had it not had the quantization, we could probably get away with
- // a cast and then store.
-
- case PPC_INS_FADD:
+ case PPC_ID_FADDx:
REQUIRE3OPS
- ei0 = il.FloatAdd(8, operToIL(il, oper1, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8),
- operToIL(il, oper2, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
- ei0 = il.SetRegister(8, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei0 = il.FloatAdd(8, operToIL_a(il, oper1, 8),
+ operToIL_a(il, oper2, 8));
+ ei0 = il.SetRegister(8, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei0);
break;
- case PPC_INS_FADDS:
+ case PPC_ID_FADDSx:
REQUIRE3OPS
ei0 = il.FloatAdd(4, operToIL(il, oper1), operToIL(il, oper2));
- ei0 = il.SetRegister(4, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei0 = il.SetRegister(4, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei0);
break;
- case PPC_INS_FSUB:
+ case PPC_ID_FSUBx:
REQUIRE3OPS
- ei0 = il.FloatSub(8, operToIL(il, oper1, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8),
- operToIL(il, oper2, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
- ei0 = il.SetRegister(8, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei0 = il.FloatSub(8, operToIL_a(il, oper1, 8),
+ operToIL_a(il, oper2, 8));
+ ei0 = il.SetRegister(8, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei0);
break;
- case PPC_INS_FSUBS:
+ case PPC_ID_FSUBSx:
REQUIRE3OPS
ei0 = il.FloatSub(4, operToIL(il, oper1), operToIL(il, oper2));
- ei0 = il.SetRegister(4, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei0 = il.SetRegister(4, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei0);
break;
- case PPC_INS_FCMPU:
+ case PPC_ID_FCMPU:
REQUIRE3OPS
ei0 = il.Register(RZF, oper1->reg);
ei1 = il.Register(RZF, oper2->reg);
- ei2 = il.FloatSub(RZF, ei0, ei1, crxToFlagWriteType(oper0->reg | PPC_CRX_FLOAT_MASK));
+ ei2 = il.FloatSub(RZF, ei0, ei1, crxToFlagWriteType(oper0->reg, PPC_SUF_F));
il.AddInstruction(ei2);
break;
- case PPC_INS_BN_FCMPO:
+ case PPC_ID_FCMPO:
REQUIRE3OPS
ei0 = il.Register(RZF, oper1->reg);
ei1 = il.Register(RZF, oper2->reg);
- ei2 = il.FloatSub(RZF, ei0, ei1, crxToFlagWriteType(oper0->reg | PPC_CRX_FLOAT_MASK));
+ ei2 = il.FloatSub(RZF, ei0, ei1, crxToFlagWriteType(oper0->reg, PPC_SUF_F));
il.AddInstruction(ei2);
break;
- case PPC_INS_FMR:
+ case PPC_ID_FMRx:
REQUIRE2OPS
- ei0 = il.SetRegister(8, oper0->reg, operToIL(il, oper1, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
+ ei0 = il.SetRegister(8, oper0->reg, operToIL_a(il, oper1, 8));
il.AddInstruction(ei0);
break;
- case PPC_INS_STFS:
+ case PPC_ID_STFS:
REQUIRE2OPS
ei0 = il.FloatConvert(4, operToIL(il, oper0));
ei0 = il.Store(4, operToIL(il, oper1), ei0);
@@ -1914,7 +2045,7 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
break;
- case PPC_INS_STFSX:
+ case PPC_ID_STFSX:
REQUIRE3OPS
ei0 = il.FloatConvert(4, operToIL(il, oper0));
ei1 = il.Add(4, operToIL(il, oper1), operToIL(il, oper2));
@@ -1923,15 +2054,15 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
break;
- case PPC_INS_STFD:
+ case PPC_ID_STFD:
REQUIRE2OPS
ei0 = il.Store(8, operToIL(il, oper1),
- il.FloatConvert(8, operToIL(il, oper0, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8)));
+ il.FloatConvert(8, operToIL_a(il, oper0, 8)));
// ei0 = il.FloatConvert(8, ei0);
il.AddInstruction(ei0);
break;
- case PPC_INS_LFS:
+ case PPC_ID_LFS:
REQUIRE2OPS
// ei0 = operToIL(il, oper1); // d(rA) or 0
// ei0 = il.Load(4, ei0); // [d(rA)]
@@ -1940,10 +2071,10 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
// il.AddInstruction(ei1);
// alternatively, do it the way arm64 does it
- loadstoreppcfs(il, 4, oper0, oper1);
+ load_float(il, 4, oper0, oper1);
break;
- case PPC_INS_LFSX:
+ case PPC_ID_LFSX:
REQUIRE3OPS
// ei0 = il.Add(4, operToIL(il, oper1), operToIL(il, oper2));
// ei0 = il.Load(4, ei0);
@@ -1953,20 +2084,20 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
// // alternatively, do it the way arm64 does it
// il.AddInstruction(ei0);
- loadstoreppcfs(il, 4, oper0, oper1, oper2);
+ load_float(il, 4, oper0, oper1, oper2);
break;
- case PPC_INS_LFSU:
+ case PPC_ID_LFSU:
REQUIRE2OPS
- loadstoreppcfs(il, 4, oper0, oper1, 0, true);
+ load_float(il, 4, oper0, oper1, 0, true);
break;
- case PPC_INS_LFSUX:
+ case PPC_ID_LFSUX:
REQUIRE3OPS
- loadstoreppcfs(il, 4, oper0, oper1, oper2, true);
+ load_float(il, 4, oper0, oper1, oper2, true);
break;
- case PPC_INS_LFD:
+ case PPC_ID_LFD:
REQUIRE2OPS
// ei0 = operToIL(il, oper1); // d(rA) or 0
// ei0 = il.Load(8, ei0); // [d(rA)]
@@ -1974,70 +2105,70 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
// il.AddInstruction(ei0);
// same as lfs
- loadstoreppcfs(il, 8, oper0, oper1);
+ load_float(il, 8, oper0, oper1);
break;
- case PPC_INS_FMUL:
+ case PPC_ID_FMULx:
REQUIRE3OPS
- ei0 = il.FloatMult(8, operToIL(il, oper1, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8),
- operToIL(il, oper2, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
- ei1 = il.SetRegister(8, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei0 = il.MultDoublePrecSigned(8, operToIL_a(il, oper1, 8),
+ operToIL_a(il, oper2, 8));
+ ei1 = il.SetRegister(8, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei1);
break;
- case PPC_INS_FMULS:
+ case PPC_ID_FMULSx:
REQUIRE3OPS
ei0 = il.FloatMult(4, operToIL(il, oper1), operToIL(il, oper2));
- ei1 = il.SetRegister(4, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei1 = il.SetRegister(4, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei1);
break;
- case PPC_INS_FDIV:
+ case PPC_ID_FDIVx:
REQUIRE3OPS
- ei0 = il.FloatDiv(8, operToIL(il, oper1, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8),
- operToIL(il, oper2, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
- ei1 = il.SetRegister(8, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei0 = il.DivDoublePrecSigned(8, operToIL_a(il, oper1, 8),
+ operToIL_a(il, oper2, 8));
+ ei1 = il.SetRegister(8, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei1);
break;
- case PPC_INS_FDIVS:
+ case PPC_ID_FDIVSx:
REQUIRE3OPS
ei0 = il.FloatDiv(4, operToIL(il, oper1), operToIL(il, oper2));
- ei1 = il.SetRegister(4, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei1 = il.SetRegister(4, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei1);
break;
- case PPC_INS_FMADD:
+ case PPC_ID_FMADDx:
REQUIRE4OPS
- ei0 = il.FloatMult(8, operToIL(il, oper1, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8),
- operToIL(il, oper3, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
- ei0 = il.FloatAdd(8, ei0, operToIL(il, oper2, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
- ei1 = il.SetRegister(8, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei0 = il.FloatMult(8, operToIL_a(il, oper1, 8),
+ operToIL_a(il, oper3, 8));
+ ei0 = il.FloatAdd(8, ei0, operToIL_a(il, oper2, 8));
+ ei1 = il.SetRegister(8, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei1);
break;
- case PPC_INS_FMADDS:
+ case PPC_ID_FMADDSx:
REQUIRE4OPS
- ei0 = il.FloatMult(4, operToIL(il, oper1), operToIL(il, oper3), (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
- ei0 = il.FloatAdd(4, ei0, operToIL(il, oper2), (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei0 = il.FloatMult(4, operToIL(il, oper1), operToIL(il, oper3), (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
+ ei0 = il.FloatAdd(4, ei0, operToIL(il, oper2), (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
ei1 = il.SetRegister(4, oper0->reg, ei0);
il.AddInstruction(ei1);
break;
- case PPC_INS_FMSUB:
+ case PPC_ID_FMSUBx:
REQUIRE4OPS
- ei0 = il.FloatMult(8, operToIL(il, oper1, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8),
- operToIL(il, oper3, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
- ei0 = il.FloatSub(8, ei0, operToIL(il, oper2, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
- ei1 = il.SetRegister(8, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei0 = il.FloatMult(8, operToIL_a(il, oper1, 8),
+ operToIL_a(il, oper3, 8));
+ ei0 = il.FloatSub(8, ei0, operToIL_a(il, oper2, 8));
+ ei1 = il.SetRegister(8, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei1);
break;
- case PPC_INS_FMSUBS:
+ case PPC_ID_FMSUBSx:
REQUIRE4OPS
ei0 = il.FloatMult(4, operToIL(il, oper1), operToIL(il, oper3));
ei0 = il.FloatSub(4, ei0, operToIL(il, oper2));
- ei1 = il.SetRegister(4, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei1 = il.SetRegister(4, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei1);
break;
@@ -2045,108 +2176,108 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
// bits 32-63 of a double reg to that result, ignoring the lower 32 bits 0-31.
// TODO: needs further testing to verify that this is functional, and verify that the
// method used was correct, as well as the registers afffected, like FPSCR.
- case PPC_INS_FCTIWZ:
+ case PPC_ID_FCTIWZx:
REQUIRE2OPS
ei0 = il.FloatTrunc(RZF, operToIL(il, oper1));
ei1 = il.Const(4, 32);
ei2 = il.ShiftLeft(8, ei0, ei1);
- ei0 = il.SetRegister(8, oper0->reg, ei2, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei0 = il.SetRegister(8, oper0->reg, ei2, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei0);
break;
- case PPC_INS_FNEG:
+ case PPC_ID_FNEGx:
REQUIRE2OPS
ei0 = il.FloatNeg(4, operToIL(il, oper1));
- ei0 = il.SetRegister(4, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei0 = il.SetRegister(4, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei0);
break;
- case PPC_INS_FNMADD:
+ case PPC_ID_FNMADDx:
REQUIRE4OPS
- ei0 = il.FloatMult(8, operToIL(il, oper1, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8),
- operToIL(il, oper3, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
- ei0 = il.FloatAdd(8, ei0, operToIL(il, oper2, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
+ ei0 = il.FloatMult(8, operToIL_a(il, oper1, 8),
+ operToIL_a(il, oper3, 8));
+ ei0 = il.FloatAdd(8, ei0, operToIL_a(il, oper2, 8));
ei0 = il.FloatNeg(8, ei0);
- ei1 = il.SetRegister(8, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei1 = il.SetRegister(8, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei1);
break;
- case PPC_INS_FNMADDS:
+ case PPC_ID_FNMADDSx:
REQUIRE4OPS
- ei0 = il.FloatMult(4, operToIL(il, oper1), operToIL(il, oper3), (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
- ei0 = il.FloatAdd(4, ei0, operToIL(il, oper2), (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei0 = il.FloatMult(4, operToIL(il, oper1), operToIL(il, oper3), (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
+ ei0 = il.FloatAdd(4, ei0, operToIL(il, oper2), (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
ei0 = il.FloatNeg(4, ei0);
ei1 = il.SetRegister(4, oper0->reg, ei0);
il.AddInstruction(ei1);
break;
- case PPC_INS_FNMSUB:
+ case PPC_ID_FNMSUBx:
REQUIRE4OPS
- ei0 = il.FloatMult(8, operToIL(il, oper1, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8),
- operToIL(il, oper3, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
- ei0 = il.FloatSub(8, ei0, operToIL(il, oper2, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
+ ei0 = il.FloatMult(8, operToIL_a(il, oper1, 8),
+ operToIL_a(il, oper3, 8));
+ ei0 = il.FloatSub(8, ei0, operToIL_a(il, oper2, 8));
ei0 = il.FloatNeg(8, ei0);
- ei1 = il.SetRegister(8, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei1 = il.SetRegister(8, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei1);
break;
- case PPC_INS_FNMSUBS:
+ case PPC_ID_FNMSUBSx:
REQUIRE4OPS
ei0 = il.FloatMult(4, operToIL(il, oper1), operToIL(il, oper3));
ei0 = il.FloatSub(4, ei0, operToIL(il, oper2));
ei0 = il.FloatNeg(4, ei0);
- ei1 = il.SetRegister(4, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei1 = il.SetRegister(4, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei1);
break;
- case PPC_INS_FABS:
+ case PPC_ID_FABSx:
REQUIRE2OPS
ei0 = il.FloatAbs(4, operToIL(il, oper1));
- ei1 = il.SetRegister(4, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei1 = il.SetRegister(4, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei1);
break;
- case PPC_INS_FNABS:
+ case PPC_ID_FNABSx:
REQUIRE2OPS
ei0 = il.FloatAbs(4, operToIL(il, oper1));
ei0 = il.FloatNeg(4, ei0);
- ei1 = il.SetRegister(4, oper0->reg, ei0, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei1 = il.SetRegister(4, oper0->reg, ei0, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei1);
break;
// TODO: needs more testing to make sure that stuff is good. the decompilation is a
// little rough, seems to be making the const double 1 into an int by default,
// gonna have to figure out how if its right and FPSCR is correct.
- case PPC_INS_FRSQRTE:
+ case PPC_ID_FRSQRTEx:
REQUIRE2OPS
ei0 = il.FloatConstDouble(1);
- ei1 = il.FloatSqrt(8, operToIL(il, oper1, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
- ei1 = il.FloatDiv(8, ei0, ei1);
- ei1 = il.SetRegister(8, oper0->reg, ei1, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei1 = il.FloatSqrt(8, operToIL_a(il, oper1, 8));
+ ei1 = il.DivDoublePrecSigned(8, ei0, ei1);
+ ei1 = il.SetRegister(8, oper0->reg, ei1, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei1);
break;
- case PPC_INS_FRSQRTES:
+ case PPC_ID_FRSQRTESx:
REQUIRE2OPS
ei0 = il.FloatConstSingle(1);
- ei1 = il.FloatSqrt(4, operToIL(il, oper1, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 8));
+ ei1 = il.FloatSqrt(4, operToIL_a(il, oper1, 8));
ei1 = il.FloatDiv(4, ei0, ei1);
- ei1 = il.SetRegister(4, oper0->reg, ei1, (ppc->update_cr0) ? IL_FLAGWRITE_CR0_F : 0);
+ ei1 = il.SetRegister(4, oper0->reg, ei1, (instruction->flags.rc) ? IL_FLAGWRITE_CR0_F : 0);
il.AddInstruction(ei1);
break;
- case PPC_INS_CNTLZW:
+ case PPC_ID_CNTLZWx:
ei0 = il.Intrinsic({RegisterOrFlag::Register(oper1->reg)}, PPC_INTRIN_CNTLZW,
{operToIL(il, oper0)});
il.AddInstruction(ei0);
break;
- case PPC_INS_PSQ_ST:
+ case PPC_ID_PAIREDSINGLE_PSQ_ST:
REQUIRE4OPS
- MYLOG("0x%08x psq_st args f%d r%d[%d] w:%lldd gcqr:%lld\n",
- (uint32_t)addr, oper0->reg - PPC_REG_F0, oper1->mem.base - PPC_REG_R0, oper1->mem.disp, oper2->imm,
- oper3->imm);
- MYLOG("opcount %d insn pnem %s\n", ppc->op_count, insn->op_str);
+ // MYLOG("0x%08x psq_st args f%d r%d[%d] w:%lldd gcqr:%lld\n",
+ // (uint32_t)addr, oper0->reg - PPC_REG_F0, oper1->mem.base - PPC_REG_R0, oper1->mem.disp, oper2->imm,
+ // oper3->imm);
+ // MYLOG("opcount %d insn pnem %s\n", ppc->op_count, instruction->op_str);
// w_l = oper2->imm;
@@ -2156,8 +2287,8 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
{RegisterOrFlag::Register(oper0->reg)},
PPC_PS_INTRIN_QUANTIZE,
{
- operToIL(il, oper0, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 4),
- il.Const(4, oper3->imm)
+ operToIL(il, oper0),
+ il.Const(4, oper3->uimm)
}
);
@@ -2167,7 +2298,7 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
ei0 = il.Store(8, operToIL(il, oper1),
// temporary measure to allow it to resemble the instruction, just oper2il oper0
// ei0
- operToIL(il, oper0, PPC_IL_OPTIONS_DEFAULT, PPC_IL_EXTRA_DEFAULT, 4)
+ operToIL(il, oper0)
// ei2
);
il.AddInstruction(ei0);
@@ -2179,7 +2310,7 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
// }
break;
- case PPC_INS_PSQ_L:
+ case PPC_ID_PAIREDSINGLE_PSQ_L:
REQUIRE4OPS
// w_l = oper2->imm;
@@ -2190,7 +2321,7 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
{
ei0,
operToIL(il, oper0),
- il.Const(4, oper3->imm)
+ il.Const(4, oper3->uimm)
}
);
@@ -2204,7 +2335,7 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
break;
- case PPC_INS_FRSP:
+ case PPC_ID_FRSPx:
ei0 = il.Intrinsic(
{RegisterOrFlag::Register(oper0->reg)},
PPC_INTRIN_FRSP,
@@ -2212,765 +2343,14 @@ bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction &il,
il.AddInstruction(ei0);
break;
- // =====================================
- // =====TO BE DEFINED INSTRUCTIONS======
- // =====================================
-
- case PPC_INS_BCL:
- case PPC_INS_BCLR:
- case PPC_INS_BCLRL:
- case PPC_INS_CNTLZD:
- case PPC_INS_DCBA:
- case PPC_INS_DCBF:
- case PPC_INS_DCBI:
- case PPC_INS_DCBST:
- case PPC_INS_DCBT:
- case PPC_INS_DCBTST:
- case PPC_INS_DCBZ:
- case PPC_INS_DCBZL:
- case PPC_INS_DCCCI:
- case PPC_INS_DIVD:
- case PPC_INS_DIVDU:
- case PPC_INS_DSS:
- case PPC_INS_DSSALL:
- case PPC_INS_DST:
- case PPC_INS_DSTST:
- case PPC_INS_DSTSTT:
- case PPC_INS_DSTT:
- case PPC_INS_EIEIO:
- case PPC_INS_EVABS:
- case PPC_INS_EVADDIW:
- case PPC_INS_EVADDSMIAAW:
- case PPC_INS_EVADDSSIAAW:
- case PPC_INS_EVADDUMIAAW:
- case PPC_INS_EVADDUSIAAW:
- case PPC_INS_EVADDW:
- case PPC_INS_EVAND:
- case PPC_INS_EVANDC:
- case PPC_INS_EVCMPEQ:
- case PPC_INS_EVCMPGTS:
- case PPC_INS_EVCMPGTU:
- case PPC_INS_EVCMPLTS:
- case PPC_INS_EVCMPLTU:
- case PPC_INS_EVCNTLSW:
- case PPC_INS_EVCNTLZW:
- case PPC_INS_EVDIVWS:
- case PPC_INS_EVDIVWU:
- case PPC_INS_EVEQV:
- case PPC_INS_EVEXTSB:
- case PPC_INS_EVEXTSH:
- case PPC_INS_EVLDD:
- case PPC_INS_EVLDDX:
- case PPC_INS_EVLDH:
- case PPC_INS_EVLDHX:
- case PPC_INS_EVLDW:
- case PPC_INS_EVLDWX:
- case PPC_INS_EVLHHESPLAT:
- case PPC_INS_EVLHHESPLATX:
- case PPC_INS_EVLHHOSSPLAT:
- case PPC_INS_EVLHHOSSPLATX:
- case PPC_INS_EVLHHOUSPLAT:
- case PPC_INS_EVLHHOUSPLATX:
- case PPC_INS_EVLWHE:
- case PPC_INS_EVLWHEX:
- case PPC_INS_EVLWHOS:
- case PPC_INS_EVLWHOSX:
- case PPC_INS_EVLWHOU:
- case PPC_INS_EVLWHOUX:
- case PPC_INS_EVLWHSPLAT:
- case PPC_INS_EVLWHSPLATX:
- case PPC_INS_EVLWWSPLAT:
- case PPC_INS_EVLWWSPLATX:
- case PPC_INS_EVMERGEHI:
- case PPC_INS_EVMERGEHILO:
- case PPC_INS_EVMERGELO:
- case PPC_INS_EVMERGELOHI:
- case PPC_INS_EVMHEGSMFAA:
- case PPC_INS_EVMHEGSMFAN:
- case PPC_INS_EVMHEGSMIAA:
- case PPC_INS_EVMHEGSMIAN:
- case PPC_INS_EVMHEGUMIAA:
- case PPC_INS_EVMHEGUMIAN:
- case PPC_INS_EVMHESMF:
- case PPC_INS_EVMHESMFA:
- case PPC_INS_EVMHESMFAAW:
- case PPC_INS_EVMHESMFANW:
- case PPC_INS_EVMHESMI:
- case PPC_INS_EVMHESMIA:
- case PPC_INS_EVMHESMIAAW:
- case PPC_INS_EVMHESMIANW:
- case PPC_INS_EVMHESSF:
- case PPC_INS_EVMHESSFA:
- case PPC_INS_EVMHESSFAAW:
- case PPC_INS_EVMHESSFANW:
- case PPC_INS_EVMHESSIAAW:
- case PPC_INS_EVMHESSIANW:
- case PPC_INS_EVMHEUMI:
- case PPC_INS_EVMHEUMIA:
- case PPC_INS_EVMHEUMIAAW:
- case PPC_INS_EVMHEUMIANW:
- case PPC_INS_EVMHEUSIAAW:
- case PPC_INS_EVMHEUSIANW:
- case PPC_INS_EVMHOGSMFAA:
- case PPC_INS_EVMHOGSMFAN:
- case PPC_INS_EVMHOGSMIAA:
- case PPC_INS_EVMHOGSMIAN:
- case PPC_INS_EVMHOGUMIAA:
- case PPC_INS_EVMHOGUMIAN:
- case PPC_INS_EVMHOSMF:
- case PPC_INS_EVMHOSMFA:
- case PPC_INS_EVMHOSMFAAW:
- case PPC_INS_EVMHOSMFANW:
- case PPC_INS_EVMHOSMI:
- case PPC_INS_EVMHOSMIA:
- case PPC_INS_EVMHOSMIAAW:
- case PPC_INS_EVMHOSMIANW:
- case PPC_INS_EVMHOSSF:
- case PPC_INS_EVMHOSSFA:
- case PPC_INS_EVMHOSSFAAW:
- case PPC_INS_EVMHOSSFANW:
- case PPC_INS_EVMHOSSIAAW:
- case PPC_INS_EVMHOSSIANW:
- case PPC_INS_EVMHOUMI:
- case PPC_INS_EVMHOUMIA:
- case PPC_INS_EVMHOUMIAAW:
- case PPC_INS_EVMHOUMIANW:
- case PPC_INS_EVMHOUSIAAW:
- case PPC_INS_EVMHOUSIANW:
- case PPC_INS_EVMRA:
- case PPC_INS_EVMWHSMF:
- case PPC_INS_EVMWHSMFA:
- case PPC_INS_EVMWHSMI:
- case PPC_INS_EVMWHSMIA:
- case PPC_INS_EVMWHSSF:
- case PPC_INS_EVMWHSSFA:
- case PPC_INS_EVMWHUMI:
- case PPC_INS_EVMWHUMIA:
- case PPC_INS_EVMWLSMIAAW:
- case PPC_INS_EVMWLSMIANW:
- case PPC_INS_EVMWLSSIAAW:
- case PPC_INS_EVMWLSSIANW:
- case PPC_INS_EVMWLUMI:
- case PPC_INS_EVMWLUMIA:
- case PPC_INS_EVMWLUMIAAW:
- case PPC_INS_EVMWLUMIANW:
- case PPC_INS_EVMWLUSIAAW:
- case PPC_INS_EVMWLUSIANW:
- case PPC_INS_EVMWSMF:
- case PPC_INS_EVMWSMFA:
- case PPC_INS_EVMWSMFAA:
- case PPC_INS_EVMWSMFAN:
- case PPC_INS_EVMWSMI:
- case PPC_INS_EVMWSMIA:
- case PPC_INS_EVMWSMIAA:
- case PPC_INS_EVMWSMIAN:
- case PPC_INS_EVMWSSF:
- case PPC_INS_EVMWSSFA:
- case PPC_INS_EVMWSSFAA:
- case PPC_INS_EVMWSSFAN:
- case PPC_INS_EVMWUMI:
- case PPC_INS_EVMWUMIA:
- case PPC_INS_EVMWUMIAA:
- case PPC_INS_EVMWUMIAN:
- case PPC_INS_EVNAND:
- case PPC_INS_EVNEG:
- case PPC_INS_EVNOR:
- case PPC_INS_EVOR:
- case PPC_INS_EVORC:
- case PPC_INS_EVRLW:
- case PPC_INS_EVRLWI:
- case PPC_INS_EVRNDW:
- case PPC_INS_EVSLW:
- case PPC_INS_EVSLWI:
- case PPC_INS_EVSPLATFI:
- case PPC_INS_EVSPLATI:
- case PPC_INS_EVSRWIS:
- case PPC_INS_EVSRWIU:
- case PPC_INS_EVSRWS:
- case PPC_INS_EVSRWU:
- case PPC_INS_EVSTDD:
- case PPC_INS_EVSTDDX:
- case PPC_INS_EVSTDH:
- case PPC_INS_EVSTDHX:
- case PPC_INS_EVSTDW:
- case PPC_INS_EVSTDWX:
- case PPC_INS_EVSTWHE:
- case PPC_INS_EVSTWHEX:
- case PPC_INS_EVSTWHO:
- case PPC_INS_EVSTWHOX:
- case PPC_INS_EVSTWWE:
- case PPC_INS_EVSTWWEX:
- case PPC_INS_EVSTWWO:
- case PPC_INS_EVSTWWOX:
- case PPC_INS_EVSUBFSMIAAW:
- case PPC_INS_EVSUBFSSIAAW:
- case PPC_INS_EVSUBFUMIAAW:
- case PPC_INS_EVSUBFUSIAAW:
- case PPC_INS_EVSUBFW:
- case PPC_INS_EVSUBIFW:
- case PPC_INS_EVXOR:
- case PPC_INS_FCFID:
- case PPC_INS_FCFIDS:
- case PPC_INS_FCFIDU:
- case PPC_INS_FCFIDUS:
- case PPC_INS_FCPSGN:
- case PPC_INS_FCTID:
- case PPC_INS_FCTIDUZ:
- case PPC_INS_FCTIDZ:
- case PPC_INS_FCTIW:
- case PPC_INS_FCTIWUZ:
- case PPC_INS_FRE:
- case PPC_INS_FRES:
- case PPC_INS_FRIM:
- case PPC_INS_FRIN:
- case PPC_INS_FRIP:
- case PPC_INS_FRIZ:
- case PPC_INS_FSEL:
- case PPC_INS_FSQRT:
- case PPC_INS_FSQRTS:
- case PPC_INS_ICBI:
- case PPC_INS_ICCCI:
- case PPC_INS_ISYNC:
- case PPC_INS_LDARX:
- case PPC_INS_LDBRX:
- case PPC_INS_LFDU:
- case PPC_INS_LFDUX:
- case PPC_INS_LFDX:
- case PPC_INS_LFIWAX:
- case PPC_INS_LFIWZX:
- case PPC_INS_LSWI:
- case PPC_INS_LVEBX:
- case PPC_INS_LVEHX:
- case PPC_INS_LVEWX:
- case PPC_INS_LVSL:
- case PPC_INS_LVSR:
- case PPC_INS_LVX:
- case PPC_INS_LVXL:
- case PPC_INS_LWA:
- case PPC_INS_LWARX:
- case PPC_INS_LWAUX:
- case PPC_INS_LWAX:
- case PPC_INS_LXSDX:
- case PPC_INS_LXVD2X:
- case PPC_INS_LXVDSX:
- case PPC_INS_LXVW4X:
- case PPC_INS_MBAR:
- case PPC_INS_MCRF:
- case PPC_INS_MFDCR:
- case PPC_INS_MFFS:
- case PPC_INS_MFMSR:
- case PPC_INS_MFOCRF:
- case PPC_INS_MFSPR:
- case PPC_INS_MFSR:
- case PPC_INS_MFSRIN:
- case PPC_INS_MFTB:
- case PPC_INS_MFVSCR:
- case PPC_INS_MSYNC:
- case PPC_INS_MTDCR:
- case PPC_INS_MTFSB0:
- case PPC_INS_MTFSB1:
- case PPC_INS_MTFSF:
- case PPC_INS_MTMSR:
- case PPC_INS_MTMSRD:
- case PPC_INS_MTOCRF:
- case PPC_INS_MTSPR:
- case PPC_INS_MTSR:
- case PPC_INS_MTSRIN:
- case PPC_INS_MTVSCR:
- case PPC_INS_MULHD:
- case PPC_INS_MULHDU:
- case PPC_INS_MULLD:
- case PPC_INS_POPCNTD:
- case PPC_INS_POPCNTW:
- case PPC_INS_RFCI:
- case PPC_INS_RFDI:
- case PPC_INS_RFID:
- case PPC_INS_RFMCI:
- case PPC_INS_RLDCL:
- case PPC_INS_RLDCR:
- case PPC_INS_RLDIC:
- case PPC_INS_RLDICL:
- case PPC_INS_RLDICR:
- case PPC_INS_RLDIMI:
- case PPC_INS_SLBIA:
- case PPC_INS_SLBIE:
- case PPC_INS_SLBMFEE:
- case PPC_INS_SLBMTE:
- case PPC_INS_STDBRX:
- case PPC_INS_STDCX:
- case PPC_INS_STFDU:
- case PPC_INS_STFDUX:
- case PPC_INS_STFDX:
- case PPC_INS_STFIWX:
- case PPC_INS_STFSU:
- case PPC_INS_STFSUX:
- case PPC_INS_STSWI:
- case PPC_INS_STVEBX:
- case PPC_INS_STVEHX:
- case PPC_INS_STVEWX:
- case PPC_INS_STVX:
- case PPC_INS_STVXL:
- case PPC_INS_STWCX:
- case PPC_INS_STXSDX:
- case PPC_INS_STXVD2X:
- case PPC_INS_STXVW4X:
- case PPC_INS_SYNC:
- case PPC_INS_TD:
- case PPC_INS_TDI:
- case PPC_INS_TLBIA:
- case PPC_INS_TLBIE:
- case PPC_INS_TLBIEL:
- case PPC_INS_TLBIVAX:
- case PPC_INS_TLBLD:
- case PPC_INS_TLBLI:
- case PPC_INS_TLBRE:
- case PPC_INS_TLBSX:
- case PPC_INS_TLBSYNC:
- case PPC_INS_TLBWE:
- case PPC_INS_TW:
- case PPC_INS_TWI:
- case PPC_INS_VADDCUW:
- case PPC_INS_VADDFP:
- case PPC_INS_VADDSBS:
- case PPC_INS_VADDSHS:
- case PPC_INS_VADDSWS:
- case PPC_INS_VADDUBM:
- case PPC_INS_VADDUBS:
- case PPC_INS_VADDUHM:
- case PPC_INS_VADDUHS:
- case PPC_INS_VADDUWM:
- case PPC_INS_VADDUWS:
- case PPC_INS_VAND:
- case PPC_INS_VANDC:
- case PPC_INS_VAVGSB:
- case PPC_INS_VAVGSH:
- case PPC_INS_VAVGSW:
- case PPC_INS_VAVGUB:
- case PPC_INS_VAVGUH:
- case PPC_INS_VAVGUW:
- case PPC_INS_VCFSX:
- case PPC_INS_VCFUX:
- case PPC_INS_VCMPBFP:
- case PPC_INS_VCMPEQFP:
- case PPC_INS_VCMPEQUB:
- case PPC_INS_VCMPEQUH:
- case PPC_INS_VCMPEQUW:
- case PPC_INS_VCMPGEFP:
- case PPC_INS_VCMPGTFP:
- case PPC_INS_VCMPGTSB:
- case PPC_INS_VCMPGTSH:
- case PPC_INS_VCMPGTSW:
- case PPC_INS_VCMPGTUB:
- case PPC_INS_VCMPGTUH:
- case PPC_INS_VCMPGTUW:
- case PPC_INS_VCTSXS:
- case PPC_INS_VCTUXS:
- case PPC_INS_VEXPTEFP:
- case PPC_INS_VLOGEFP:
- case PPC_INS_VMADDFP:
- case PPC_INS_VMAXFP:
- case PPC_INS_VMAXSB:
- case PPC_INS_VMAXSH:
- case PPC_INS_VMAXSW:
- case PPC_INS_VMAXUB:
- case PPC_INS_VMAXUH:
- case PPC_INS_VMAXUW:
- case PPC_INS_VMHADDSHS:
- case PPC_INS_VMHRADDSHS:
- case PPC_INS_VMINFP:
- case PPC_INS_VMINSB:
- case PPC_INS_VMINSH:
- case PPC_INS_VMINSW:
- case PPC_INS_VMINUB:
- case PPC_INS_VMINUH:
- case PPC_INS_VMINUW:
- case PPC_INS_VMLADDUHM:
- case PPC_INS_VMRGHB:
- case PPC_INS_VMRGHH:
- case PPC_INS_VMRGHW:
- case PPC_INS_VMRGLB:
- case PPC_INS_VMRGLH:
- case PPC_INS_VMRGLW:
- case PPC_INS_VMSUMMBM:
- case PPC_INS_VMSUMSHM:
- case PPC_INS_VMSUMSHS:
- case PPC_INS_VMSUMUBM:
- case PPC_INS_VMSUMUHM:
- case PPC_INS_VMSUMUHS:
- case PPC_INS_VMULESB:
- case PPC_INS_VMULESH:
- case PPC_INS_VMULEUB:
- case PPC_INS_VMULEUH:
- case PPC_INS_VMULOSB:
- case PPC_INS_VMULOSH:
- case PPC_INS_VMULOUB:
- case PPC_INS_VMULOUH:
- case PPC_INS_VNMSUBFP:
- case PPC_INS_VNOR:
- case PPC_INS_VOR:
- case PPC_INS_VPERM:
- case PPC_INS_VPKPX:
- case PPC_INS_VPKSHSS:
- case PPC_INS_VPKSHUS:
- case PPC_INS_VPKSWSS:
- case PPC_INS_VPKSWUS:
- case PPC_INS_VPKUHUM:
- case PPC_INS_VPKUHUS:
- case PPC_INS_VPKUWUM:
- case PPC_INS_VPKUWUS:
- case PPC_INS_VREFP:
- case PPC_INS_VRFIM:
- case PPC_INS_VRFIN:
- case PPC_INS_VRFIP:
- case PPC_INS_VRFIZ:
- case PPC_INS_VRLB:
- case PPC_INS_VRLH:
- case PPC_INS_VRLW:
- case PPC_INS_VRSQRTEFP:
- case PPC_INS_VSEL:
- case PPC_INS_VSL:
- case PPC_INS_VSLB:
- case PPC_INS_VSLDOI:
- case PPC_INS_VSLH:
- case PPC_INS_VSLO:
- case PPC_INS_VSLW:
- case PPC_INS_VSPLTB:
- case PPC_INS_VSPLTH:
- case PPC_INS_VSPLTISB:
- case PPC_INS_VSPLTISH:
- case PPC_INS_VSPLTISW:
- case PPC_INS_VSPLTW:
- case PPC_INS_VSR:
- case PPC_INS_VSRAB:
- case PPC_INS_VSRAH:
- case PPC_INS_VSRAW:
- case PPC_INS_VSRB:
- case PPC_INS_VSRH:
- case PPC_INS_VSRO:
- case PPC_INS_VSRW:
- case PPC_INS_VSUBCUW:
- case PPC_INS_VSUBFP:
- case PPC_INS_VSUBSBS:
- case PPC_INS_VSUBSHS:
- case PPC_INS_VSUBSWS:
- case PPC_INS_VSUBUBM:
- case PPC_INS_VSUBUBS:
- case PPC_INS_VSUBUHM:
- case PPC_INS_VSUBUHS:
- case PPC_INS_VSUBUWM:
- case PPC_INS_VSUBUWS:
- case PPC_INS_VSUM2SWS:
- case PPC_INS_VSUM4SBS:
- case PPC_INS_VSUM4SHS:
- case PPC_INS_VSUM4UBS:
- case PPC_INS_VSUMSWS:
- case PPC_INS_VUPKHPX:
- case PPC_INS_VUPKHSB:
- case PPC_INS_VUPKHSH:
- case PPC_INS_VUPKLPX:
- case PPC_INS_VUPKLSB:
- case PPC_INS_VUPKLSH:
- case PPC_INS_VXOR:
- case PPC_INS_WAIT:
- case PPC_INS_WRTEE:
- case PPC_INS_WRTEEI:
- case PPC_INS_XSABSDP:
- case PPC_INS_XSADDDP:
- case PPC_INS_XSCMPODP:
- case PPC_INS_XSCMPUDP:
- case PPC_INS_XSCPSGNDP:
- case PPC_INS_XSCVDPSP:
- case PPC_INS_XSCVDPSXDS:
- case PPC_INS_XSCVDPSXWS:
- case PPC_INS_XSCVDPUXDS:
- case PPC_INS_XSCVDPUXWS:
- case PPC_INS_XSCVSPDP:
- case PPC_INS_XSCVSXDDP:
- case PPC_INS_XSCVUXDDP:
- case PPC_INS_XSDIVDP:
- case PPC_INS_XSMADDADP:
- case PPC_INS_XSMADDMDP:
- case PPC_INS_XSMAXDP:
- case PPC_INS_XSMINDP:
- case PPC_INS_XSMSUBADP:
- case PPC_INS_XSMSUBMDP:
- case PPC_INS_XSMULDP:
- case PPC_INS_XSNABSDP:
- case PPC_INS_XSNEGDP:
- case PPC_INS_XSNMADDADP:
- case PPC_INS_XSNMADDMDP:
- case PPC_INS_XSNMSUBADP:
- case PPC_INS_XSNMSUBMDP:
- case PPC_INS_XSRDPI:
- case PPC_INS_XSRDPIC:
- case PPC_INS_XSRDPIM:
- case PPC_INS_XSRDPIP:
- case PPC_INS_XSRDPIZ:
- case PPC_INS_XSREDP:
- case PPC_INS_XSRSQRTEDP:
- case PPC_INS_XSSQRTDP:
- case PPC_INS_XSSUBDP:
- case PPC_INS_XSTDIVDP:
- case PPC_INS_XSTSQRTDP:
- case PPC_INS_XVABSDP:
- case PPC_INS_XVABSSP:
- case PPC_INS_XVADDDP:
- case PPC_INS_XVADDSP:
- case PPC_INS_XVCMPEQDP:
- case PPC_INS_XVCMPEQSP:
- case PPC_INS_XVCMPGEDP:
- case PPC_INS_XVCMPGESP:
- case PPC_INS_XVCMPGTDP:
- case PPC_INS_XVCMPGTSP:
- case PPC_INS_XVCPSGNDP:
- case PPC_INS_XVCPSGNSP:
- case PPC_INS_XVCVDPSP:
- case PPC_INS_XVCVDPSXDS:
- case PPC_INS_XVCVDPSXWS:
- case PPC_INS_XVCVDPUXDS:
- case PPC_INS_XVCVDPUXWS:
- case PPC_INS_XVCVSPDP:
- case PPC_INS_XVCVSPSXDS:
- case PPC_INS_XVCVSPSXWS:
- case PPC_INS_XVCVSPUXDS:
- case PPC_INS_XVCVSPUXWS:
- case PPC_INS_XVCVSXDDP:
- case PPC_INS_XVCVSXDSP:
- case PPC_INS_XVCVSXWDP:
- case PPC_INS_XVCVSXWSP:
- case PPC_INS_XVCVUXDDP:
- case PPC_INS_XVCVUXDSP:
- case PPC_INS_XVCVUXWDP:
- case PPC_INS_XVCVUXWSP:
- case PPC_INS_XVDIVDP:
- case PPC_INS_XVDIVSP:
- case PPC_INS_XVMADDADP:
- case PPC_INS_XVMADDASP:
- case PPC_INS_XVMADDMDP:
- case PPC_INS_XVMADDMSP:
- case PPC_INS_XVMAXDP:
- case PPC_INS_XVMAXSP:
- case PPC_INS_XVMINDP:
- case PPC_INS_XVMINSP:
- case PPC_INS_XVMSUBADP:
- case PPC_INS_XVMSUBASP:
- case PPC_INS_XVMSUBMDP:
- case PPC_INS_XVMSUBMSP:
- case PPC_INS_XVMULDP:
- case PPC_INS_XVMULSP:
- case PPC_INS_XVNABSDP:
- case PPC_INS_XVNABSSP:
- case PPC_INS_XVNEGDP:
- case PPC_INS_XVNEGSP:
- case PPC_INS_XVNMADDADP:
- case PPC_INS_XVNMADDASP:
- case PPC_INS_XVNMADDMDP:
- case PPC_INS_XVNMADDMSP:
- case PPC_INS_XVNMSUBADP:
- case PPC_INS_XVNMSUBASP:
- case PPC_INS_XVNMSUBMDP:
- case PPC_INS_XVNMSUBMSP:
- case PPC_INS_XVRDPI:
- case PPC_INS_XVRDPIC:
- case PPC_INS_XVRDPIM:
- case PPC_INS_XVRDPIP:
- case PPC_INS_XVRDPIZ:
- case PPC_INS_XVREDP:
- case PPC_INS_XVRESP:
- case PPC_INS_XVRSPI:
- case PPC_INS_XVRSPIC:
- case PPC_INS_XVRSPIM:
- case PPC_INS_XVRSPIP:
- case PPC_INS_XVRSPIZ:
- case PPC_INS_XVRSQRTEDP:
- case PPC_INS_XVRSQRTESP:
- case PPC_INS_XVSQRTDP:
- case PPC_INS_XVSQRTSP:
- case PPC_INS_XVSUBDP:
- case PPC_INS_XVSUBSP:
- case PPC_INS_XVTDIVDP:
- case PPC_INS_XVTDIVSP:
- case PPC_INS_XVTSQRTDP:
- case PPC_INS_XVTSQRTSP:
- case PPC_INS_XXLAND:
- case PPC_INS_XXLANDC:
- case PPC_INS_XXLNOR:
- case PPC_INS_XXLOR:
- case PPC_INS_XXLXOR:
- case PPC_INS_XXMRGHW:
- case PPC_INS_XXMRGLW:
- case PPC_INS_XXPERMDI:
- case PPC_INS_XXSEL:
- case PPC_INS_XXSLDWI:
- case PPC_INS_XXSPLTW:
- case PPC_INS_BCA:
- case PPC_INS_BCLA:
- case PPC_INS_SLDI:
- case PPC_INS_BTA:
- case PPC_INS_MFBR0:
- case PPC_INS_MFBR1:
- case PPC_INS_MFBR2:
- case PPC_INS_MFBR3:
- case PPC_INS_MFBR4:
- case PPC_INS_MFBR5:
- case PPC_INS_MFBR6:
- case PPC_INS_MFBR7:
- case PPC_INS_MFXER:
- case PPC_INS_MFRTCU:
- case PPC_INS_MFRTCL:
- case PPC_INS_MFDSCR:
- case PPC_INS_MFDSISR:
- case PPC_INS_MFDAR:
- case PPC_INS_MFSRR2:
- case PPC_INS_MFSRR3:
- case PPC_INS_MFCFAR:
- case PPC_INS_MFAMR:
- case PPC_INS_MFPID:
- case PPC_INS_MFTBLO:
- case PPC_INS_MFTBHI:
- case PPC_INS_MFDBATU:
- case PPC_INS_MFDBATL:
- case PPC_INS_MFIBATU:
- case PPC_INS_MFIBATL:
- case PPC_INS_MFDCCR:
- case PPC_INS_MFICCR:
- case PPC_INS_MFDEAR:
- case PPC_INS_MFESR:
- case PPC_INS_MFSPEFSCR:
- case PPC_INS_MFTCR:
- case PPC_INS_MFASR:
- case PPC_INS_MFPVR:
- case PPC_INS_MFTBU:
- case PPC_INS_MTCR:
- case PPC_INS_MTBR0:
- case PPC_INS_MTBR1:
- case PPC_INS_MTBR2:
- case PPC_INS_MTBR3:
- case PPC_INS_MTBR4:
- case PPC_INS_MTBR5:
- case PPC_INS_MTBR6:
- case PPC_INS_MTBR7:
- case PPC_INS_MTXER:
- case PPC_INS_MTDSCR:
- case PPC_INS_MTDSISR:
- case PPC_INS_MTDAR:
- case PPC_INS_MTSRR2:
- case PPC_INS_MTSRR3:
- case PPC_INS_MTCFAR:
- case PPC_INS_MTAMR:
- case PPC_INS_MTPID:
- case PPC_INS_MTTBL:
- case PPC_INS_MTTBU:
- case PPC_INS_MTTBLO:
- case PPC_INS_MTTBHI:
- case PPC_INS_MTDBATU:
- case PPC_INS_MTDBATL:
- case PPC_INS_MTIBATU:
- case PPC_INS_MTIBATL:
- case PPC_INS_MTDCCR:
- case PPC_INS_MTICCR:
- case PPC_INS_MTDEAR:
- case PPC_INS_MTESR:
- case PPC_INS_MTSPEFSCR:
- case PPC_INS_MTTCR:
- case PPC_INS_ROTLD:
- case PPC_INS_ROTLDI:
- case PPC_INS_CLRLDI:
- case PPC_INS_SUB:
- case PPC_INS_SUBC:
- case PPC_INS_LWSYNC:
- case PPC_INS_PTESYNC:
- case PPC_INS_TDLT:
- case PPC_INS_TDEQ:
- case PPC_INS_TDGT:
- case PPC_INS_TDNE:
- case PPC_INS_TDLLT:
- case PPC_INS_TDLGT:
- case PPC_INS_TDU:
- case PPC_INS_TDLTI:
- case PPC_INS_TDEQI:
- case PPC_INS_TDGTI:
- case PPC_INS_TDNEI:
- case PPC_INS_TDLLTI:
- case PPC_INS_TDLGTI:
- case PPC_INS_TDUI:
- case PPC_INS_TLBREHI:
- case PPC_INS_TLBRELO:
- case PPC_INS_TLBWEHI:
- case PPC_INS_TLBWELO:
- case PPC_INS_TWLT:
- case PPC_INS_TWEQ:
- case PPC_INS_TWGT:
- case PPC_INS_TWNE:
- case PPC_INS_TWLLT:
- case PPC_INS_TWLGT:
- case PPC_INS_TWU:
- case PPC_INS_TWLTI:
- case PPC_INS_TWEQI:
- case PPC_INS_TWGTI:
- case PPC_INS_TWNEI:
- case PPC_INS_TWLLTI:
- case PPC_INS_TWLGTI:
- case PPC_INS_TWUI:
- case PPC_INS_WAITRSV:
- case PPC_INS_WAITIMPL:
- // TODO not technically implemented but capstone misinterprettation
- // where it is posting that XORI is 1452, though that is XNOP
- // case PPC_INS_XNOP:
- case PPC_INS_XVMOVDP:
- case PPC_INS_XVMOVSP:
- case PPC_INS_XXSPLTD:
- case PPC_INS_XXMRGHD:
- case PPC_INS_XXMRGLD:
- case PPC_INS_XXSWAPD:
- case PPC_INS_BT:
- case PPC_INS_BF:
- case PPC_INS_BDNZT:
- case PPC_INS_BDNZF:
- case PPC_INS_BDZF:
- case PPC_INS_BDZT:
- case PPC_INS_BFA:
- case PPC_INS_BDNZTA:
- case PPC_INS_BDNZFA:
- case PPC_INS_BDZTA:
- case PPC_INS_BDZFA:
- case PPC_INS_BTCTR:
- case PPC_INS_BFCTR:
- case PPC_INS_BTCTRL:
- case PPC_INS_BFCTRL:
- case PPC_INS_BTL:
- case PPC_INS_BFL:
- case PPC_INS_BDNZTL:
- case PPC_INS_BDNZFL:
- case PPC_INS_BDZTL:
- case PPC_INS_BDZFL:
- case PPC_INS_BTLA:
- case PPC_INS_BFLA:
- case PPC_INS_BDNZTLA:
- case PPC_INS_BDNZFLA:
- case PPC_INS_BDZTLA:
- case PPC_INS_BDZFLA:
- case PPC_INS_BTLR:
- case PPC_INS_BFLR:
- case PPC_INS_BDNZTLR:
- case PPC_INS_BDZTLR:
- case PPC_INS_BDZFLR:
- case PPC_INS_BTLRL:
- case PPC_INS_BFLRL:
- case PPC_INS_BDNZTLRL:
- case PPC_INS_BDNZFLRL:
- case PPC_INS_BDZTLRL:
- case PPC_INS_BDZFLRL:
- case PPC_INS_BRINC:
-
ReturnUnimpl:
default:
MYLOG("%s:%s() returning Unimplemented(...) on:\n",
__FILE__, __func__);
- MYLOG(" %08llx: %02X %02X %02X %02X %s %s\n",
- addr, data[0], data[1], data[2], data[3],
- res->insn.mnemonic, res->insn.op_str);
+ // MYLOG(" %08llx: %02X %02X %02X %02X %s %s\n",
+ // addr, data[0], data[1], data[2], data[3],
+ // res->insn.mnemonic, res->insn.op_str);
il.AddInstruction(il.Unimplemented());
}
diff --git a/arch/powerpc/il.h b/arch/powerpc/il.h
index b4ca2526..1e8f67c2 100644
--- a/arch/powerpc/il.h
+++ b/arch/powerpc/il.h
@@ -1,3 +1,5 @@
+#include "decode/decode.h"
+
/* these are the flags in cr0
(the default condition field in condition register CR)
@@ -219,4 +221,4 @@ enum PPCIntrinsic : uint32_t
};
-bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction& il, const uint8_t *data, uint64_t addr, decomp_result *res, bool le);
+bool GetLowLevelILForPPCInstruction(Architecture *arch, LowLevelILFunction& il, Instruction* instruction, uint64_t addr);
diff --git a/arch/powerpc/util.cpp b/arch/powerpc/util.cpp
deleted file mode 100644
index 5e37f735..00000000
--- a/arch/powerpc/util.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-#include "disassembler.h"
-
-#include <binaryninjaapi.h>
-#define MYLOG(...) while(0);
-//#define MYLOG BinaryNinja::LogDebug
-
-void printOperandVerbose(decomp_result *res, cs_ppc_op *op)
-{
- (void)res;
- if(op == NULL) {
- MYLOG("NULL\n");
- return;
- }
-
- switch(op->type) {
- case PPC_OP_INVALID:
- MYLOG("invalid\n");
- break;
- case PPC_OP_REG:
- MYLOG("reg: %s\n", cs_reg_name(res->handle, op->reg));
- break;
- case PPC_OP_IMM:
- MYLOG("imm: 0x%X\n", op->imm);
- break;
- case PPC_OP_MEM:
- MYLOG("mem (%s + %d)\n", cs_reg_name(res->handle, op->mem.base),
- op->mem.disp);
- break;
- case PPC_OP_CRX:
- MYLOG("crx (scale:%d, reg:%s)\n", op->crx.scale,
- cs_reg_name(res->handle, op->crx.reg));
- break;
- default:
- MYLOG("unknown (%d)\n", op->type);
- break;
- }
-}
-
-void printInstructionVerbose(decomp_result *res)
-{
- struct cs_insn *insn = &(res->insn);
- struct cs_detail *detail = &(res->detail);
- struct cs_ppc *ppc = &(detail->ppc);
- (void)insn;
-
- /* LEVEL1: id, address, size, bytes, mnemonic, op_str */
- MYLOG("instruction id: %d \"%s %s\"\n", insn->id, insn->mnemonic,
- insn->op_str);
-
- MYLOG(" bytes: %02X %02X %02X %02X\n", insn->bytes[0], insn->bytes[1],
- insn->bytes[2], insn->bytes[3]);
-
- /* LEVEL2: regs_read, regs_write, groups */
- MYLOG(" regs read:");
- for(int j=0; j<detail->regs_read_count; ++j) {
- MYLOG(" %s", cs_reg_name(res->handle, detail->regs_read[j]));
- }
- MYLOG("\n");
- MYLOG(" regs write:");
- for(int j=0; j<detail->regs_write_count; ++j) {
- MYLOG(" %s", cs_reg_name(res->handle, detail->regs_write[j]));
- }
- MYLOG("\n");
- MYLOG(" groups:");
- for(int j=0; j<detail->groups_count; ++j) {
- int group = detail->groups[j];
- (void)group;
- MYLOG(" %d(%s)", group, cs_group_name(res->handle, group));
- }
- MYLOG("\n");
-
- /* LEVEL3: branch code, branch hint, update_cr0, operands */
- if(1 /* branch instruction */) {
- MYLOG(" branch code: %d\n", ppc->bc); // PPC_BC_LT, PPC_BC_LE, etc.
- MYLOG(" branch hint: %d\n", ppc->bh); // PPC_BH_PLUS, PPC_BH_MINUS
- }
-
- MYLOG(" update_cr0: %d\n", ppc->update_cr0);
-
- // .op_count is number of operands
- // .operands[] is array of cs_ppc_op
- for(int j=0; j<ppc->op_count; ++j) {
- MYLOG(" operand%d: ", j);
- printOperandVerbose(res, &(ppc->operands[j]));
- }
-}
-
-uint64_t sign_extend(size_t addressSize_local, uint64_t target, int signBit)
-{
- if ((target >> signBit) & 1)
- {
- target = target | (~((1 << signBit) - 1));
- }
-
- if (addressSize_local == 4)
- {
- target = target & 0xffffffff;
- }
- return target;
-}
-
diff --git a/arch/powerpc/util.h b/arch/powerpc/util.h
index 0eb14651..39f02bc2 100644
--- a/arch/powerpc/util.h
+++ b/arch/powerpc/util.h
@@ -30,6 +30,12 @@
#define ADDRNEG1(addressSize) (addressSize == 4) ? ((uint32_t)-1) : ((uint64_t)-1)
+inline uint16_t bswap16(uint16_t x)
+{
+ return ((x&0xFF)<<8) |
+ ((x&0xFF00)>>8);
+}
+
inline uint32_t bswap32(uint32_t x)
{
return ((x&0xFF)<<24) |
@@ -38,6 +44,4 @@ inline uint32_t bswap32(uint32_t x)
((x&0xFF000000)>>24);
}
-void printOperandVerbose(decomp_result *res, cs_ppc_op *opers);
-void printInstructionVerbose(decomp_result *res);
-uint64_t sign_extend(size_t addressSize_local, uint64_t target, int signBit); \ No newline at end of file
+uint64_t sign_extend(size_t addressSize_local, uint64_t target, int signBit);