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/decode.c | |
| 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/decode.c')
| -rw-r--r-- | arch/powerpc/decode/decode.c | 6110 |
1 files changed, 6110 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; + } +} + |
