diff options
| author | Galen Williamson <galen@vector35.com> | 2025-06-29 11:23:58 -0400 |
|---|---|---|
| committer | Galen Williamson <galen@vector35.com> | 2025-06-29 18:28:48 -0400 |
| commit | e8206bc27e1633c7e4c99907f43bf67d2f200cd5 (patch) | |
| tree | 2315bec284e9bb692a0eb8986578fe18e2289d23 /arch/powerpc/decode | |
| parent | 91f1eccb6c41a7ef60fd66387ffae075f88141a4 (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/decode')
| -rw-r--r-- | arch/powerpc/decode/decode.c | 6110 | ||||
| -rw-r--r-- | arch/powerpc/decode/decode.h | 1901 | ||||
| -rw-r--r-- | arch/powerpc/decode/mnemonic.c | 2188 | ||||
| -rw-r--r-- | arch/powerpc/decode/names.c | 296 | ||||
| -rw-r--r-- | arch/powerpc/decode/operands.c | 3288 | ||||
| -rw-r--r-- | arch/powerpc/decode/priv.c | 251 | ||||
| -rw-r--r-- | arch/powerpc/decode/priv.h | 54 | ||||
| -rw-r--r-- | arch/powerpc/decode/vle16.c | 790 | ||||
| -rw-r--r-- | arch/powerpc/decode/vle32.c | 715 |
9 files changed, 15593 insertions, 0 deletions
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 + ; + } +} |
