summaryrefslogtreecommitdiff
path: root/arch/powerpc/decode/priv.c
diff options
context:
space:
mode:
authorGalen Williamson <galen@vector35.com>2025-06-29 11:23:58 -0400
committerGalen Williamson <galen@vector35.com>2025-06-29 18:28:48 -0400
commite8206bc27e1633c7e4c99907f43bf67d2f200cd5 (patch)
tree2315bec284e9bb692a0eb8986578fe18e2289d23 /arch/powerpc/decode/priv.c
parent91f1eccb6c41a7ef60fd66387ffae075f88141a4 (diff)
[powerpc] Full merge of PowerPC disassembler PRs, including:
* Remove dependency on capstone for PowerPC disassembly #6292 * Add support for PowerPC VLE instruction set #6740 * Add support for paired-single instructions #6821 * Various post-merge fixes and tweaks to disassembly and lifting * Removal of dependence on capstone for assembler's scoring mechanism (capstone currently disabled, but not removed from codebase yet)
Diffstat (limited to 'arch/powerpc/decode/priv.c')
-rw-r--r--arch/powerpc/decode/priv.c251
1 files changed, 251 insertions, 0 deletions
diff --git a/arch/powerpc/decode/priv.c b/arch/powerpc/decode/priv.c
new file mode 100644
index 00000000..2db5c839
--- /dev/null
+++ b/arch/powerpc/decode/priv.c
@@ -0,0 +1,251 @@
+#include <string.h>
+
+#include "priv.h"
+
+uint32_t GetA(uint32_t word32)
+{
+ return (word32 >> 16) & 0x1f;
+}
+
+uint32_t GetB(uint32_t word32)
+{
+ return (word32 >> 11) & 0x1f;
+}
+
+uint32_t GetC(uint32_t word32)
+{
+ return (word32 >> 6) & 0x1f;
+}
+
+uint32_t GetD(uint32_t word32)
+{
+ return (word32 >> 21) & 0x1f;
+}
+
+uint32_t GetS(uint32_t word32)
+{
+ return (word32 >> 21) & 0x1f;
+}
+
+uint32_t GetBI(uint32_t word32)
+{
+ return (word32 >> 16) & 0x1f;
+}
+
+uint32_t GetBO(uint32_t word32)
+{
+ return (word32 >> 21) & 0x1f;
+}
+
+uint32_t GetVsxA(uint32_t word32)
+{
+ uint32_t ax = (word32 >> 2) & 0x1;
+ uint32_t a = (word32 >> 16) & 0x1f;
+
+ return (ax << 5) | a;
+}
+
+uint32_t GetVsxB(uint32_t word32)
+{
+ uint32_t bx = (word32 >> 1) & 0x1;
+ uint32_t b = (word32 >> 11) & 0x1f;
+
+ return (bx << 5) | b;
+}
+
+uint32_t GetVsxC(uint32_t word32)
+{
+ uint32_t cx = (word32 >> 3) & 0x1;
+ uint32_t c = (word32 >> 6) & 0x1f;
+
+ return (cx << 5) | c;
+}
+
+uint32_t GetVsxD(uint32_t word32)
+{
+ uint32_t dx = word32 & 0x1;
+ uint32_t d = (word32 >> 21) & 0x1f;
+
+ return (dx << 5) | d;
+}
+
+uint32_t GetSpecialRegisterCommon(uint32_t word32)
+{
+ uint32_t xr5_9 = (word32 >> 16) & 0x1f;
+ uint32_t xr0_4 = (word32 >> 11) & 0x1f;
+ uint32_t xr = (xr0_4 << 5) | xr5_9;
+
+ return xr;
+}
+
+uint32_t GetME(uint32_t word32)
+{
+ return (word32 >> 1) & 0x1f;
+}
+
+uint32_t GetMB(uint32_t word32)
+{
+ return (word32 >> 6) & 0x1f;
+}
+
+uint32_t GetSH(uint32_t word32)
+{
+ return (word32 >> 11) & 0x1f;
+}
+
+uint32_t GetSH64(uint32_t word32)
+{
+ uint32_t sh5 = (word32 >> 1) & 0x1;
+ uint32_t sh4_0 = (word32 >> 11) & 0x1f;
+
+ return (sh5 << 5) | sh4_0;
+}
+
+uint32_t GetMX64(uint32_t word32)
+{
+ uint32_t mx = (word32 >> 5) & 0x3f;
+
+ // x <- mx5 || mx[0:5] in powerpc's bit order
+ return ((mx & 0x1) << 5) | (mx >> 1);
+}
+
+void CopyOperand(Operand* dst, const Operand* src)
+{
+ memcpy(dst, src, sizeof *dst);
+}
+
+InstructionId VleTranslateMnemonic(InstructionId id)
+{
+ switch (id)
+ {
+ case PPC_ID_VLE_E_ADDIx: return PPC_ID_ADDIx;
+ case PPC_ID_VLE_E_ADDICx: return PPC_ID_ADDICx;
+ case PPC_ID_VLE_E_ADD2I: return PPC_ID_ADDIx;
+ case PPC_ID_VLE_E_ADD2IS: return PPC_ID_ADDIS;
+ case PPC_ID_VLE_E_ADD16I: return PPC_ID_ADDIx;
+ case PPC_ID_VLE_E_ANDIx: return PPC_ID_ANDIx;
+ case PPC_ID_VLE_E_AND2I: return PPC_ID_ANDIx;
+ case PPC_ID_VLE_E_AND2IS: return PPC_ID_ANDIS;
+ case PPC_ID_VLE_E_Bx: return PPC_ID_Bx;
+ case PPC_ID_VLE_E_CMP16I: return PPC_ID_CMPWI;
+ case PPC_ID_VLE_E_CMPI: return PPC_ID_CMPWI;
+ case PPC_ID_VLE_E_CMPL16I: return PPC_ID_CMPLWI;
+ case PPC_ID_VLE_E_CMPLI: return PPC_ID_CMPLWI;
+ case PPC_ID_VLE_E_CRAND: return PPC_ID_CRAND;
+ case PPC_ID_VLE_E_CRANDC: return PPC_ID_CRANDC;
+ case PPC_ID_VLE_E_CREQV: return PPC_ID_CREQV;
+ case PPC_ID_VLE_E_CRNAND: return PPC_ID_CRNAND;
+ case PPC_ID_VLE_E_CRNOR: return PPC_ID_CRNOR;
+ case PPC_ID_VLE_E_CROR: return PPC_ID_CROR;
+ case PPC_ID_VLE_E_CRORC: return PPC_ID_CRORC;
+ case PPC_ID_VLE_E_CRXOR: return PPC_ID_CRXOR;
+ case PPC_ID_VLE_E_LBZ: return PPC_ID_LBZ;
+ case PPC_ID_VLE_E_LBZU: return PPC_ID_LBZU;
+ case PPC_ID_VLE_E_LHA: return PPC_ID_LHA;
+ case PPC_ID_VLE_E_LHAU: return PPC_ID_LHAU;
+ case PPC_ID_VLE_E_LHZ: return PPC_ID_LHZ;
+ case PPC_ID_VLE_E_LHZU: return PPC_ID_LHZU;
+ case PPC_ID_VLE_E_LI: return PPC_ID_LI;
+ case PPC_ID_VLE_E_LIS: return PPC_ID_LIS;
+ case PPC_ID_VLE_E_LMW: return PPC_ID_LMW;
+ case PPC_ID_VLE_E_LWZ: return PPC_ID_LWZ;
+ case PPC_ID_VLE_E_LWZU: return PPC_ID_LWZU;
+ case PPC_ID_VLE_E_MCRF: return PPC_ID_MCRF;
+ case PPC_ID_VLE_E_MULL2I: return PPC_ID_MULLI;
+ case PPC_ID_VLE_E_MULLI: return PPC_ID_MULLI;
+ case PPC_ID_VLE_E_OR2I: return PPC_ID_ORIx;
+ case PPC_ID_VLE_E_OR2IS: return PPC_ID_ORIS;
+ case PPC_ID_VLE_E_ORIx: return PPC_ID_ORIx;
+ case PPC_ID_VLE_E_RLWIMI: return PPC_ID_RLWIMIx;
+ case PPC_ID_VLE_E_RLWINM: return PPC_ID_RLWINMx;
+ case PPC_ID_VLE_E_SLWIx: return PPC_ID_SLWIx;
+ case PPC_ID_VLE_E_SRWIx: return PPC_ID_SRWIx;
+ case PPC_ID_VLE_E_STB: return PPC_ID_STB;
+ case PPC_ID_VLE_E_STBU: return PPC_ID_STBU;
+ case PPC_ID_VLE_E_STH: return PPC_ID_STH;
+ case PPC_ID_VLE_E_STHU: return PPC_ID_STHU;
+ case PPC_ID_VLE_E_STMW: return PPC_ID_STMW;
+ case PPC_ID_VLE_E_STW: return PPC_ID_STW;
+ case PPC_ID_VLE_E_STWU: return PPC_ID_STWU;
+ case PPC_ID_VLE_E_SUBFICx: return PPC_ID_SUBFICx;
+ case PPC_ID_VLE_E_XORIx: return PPC_ID_XORIx;
+
+ // 16-bit VLE instructions
+ case PPC_ID_VLE_SE_ADD: return PPC_ID_ADDx;
+ case PPC_ID_VLE_SE_ADDI: return PPC_ID_ADDIx;
+ case PPC_ID_VLE_SE_ANDx: return PPC_ID_ANDx;
+ case PPC_ID_VLE_SE_ANDC: return PPC_ID_ANDCx;
+ case PPC_ID_VLE_SE_ANDI: return PPC_ID_ANDIx;
+ case PPC_ID_VLE_SE_Bx: return PPC_ID_Bx;
+ case PPC_ID_VLE_SE_BCLRI: return PPC_ID_ANDIx;
+ case PPC_ID_VLE_SE_BGENI: return PPC_ID_LI;
+ case PPC_ID_VLE_SE_BMASKI: return PPC_ID_LI;
+ case PPC_ID_VLE_SE_BSETI: return PPC_ID_ORIx;
+ case PPC_ID_VLE_SE_CMP: return PPC_ID_CMPW;
+ case PPC_ID_VLE_SE_CMPI: return PPC_ID_CMPWI;
+ case PPC_ID_VLE_SE_CMPL: return PPC_ID_CMPLW;
+ case PPC_ID_VLE_SE_CMPLI: return PPC_ID_CMPLWI;
+ case PPC_ID_VLE_SE_EXTSB: return PPC_ID_EXTSBx;
+ case PPC_ID_VLE_SE_EXTSH: return PPC_ID_EXTSHx;
+ case PPC_ID_VLE_SE_EXTZB: return PPC_ID_ANDIx;
+ case PPC_ID_VLE_SE_EXTZH: return PPC_ID_ANDIx;
+ case PPC_ID_VLE_SE_ISYNC: return PPC_ID_ISYNC;
+ case PPC_ID_VLE_SE_LI: return PPC_ID_LI;
+ case PPC_ID_VLE_SE_MFAR: return PPC_ID_MRx;
+ case PPC_ID_VLE_SE_MFCTR: return PPC_ID_MFCTR;
+ case PPC_ID_VLE_SE_MFLR: return PPC_ID_MFLR;
+ case PPC_ID_VLE_SE_MR: return PPC_ID_MRx;
+ case PPC_ID_VLE_SE_MTAR: return PPC_ID_MRx;
+ case PPC_ID_VLE_SE_MTCTR: return PPC_ID_MTCTR;
+ case PPC_ID_VLE_SE_MTLR: return PPC_ID_MTLR;
+ case PPC_ID_VLE_SE_MULLW: return PPC_ID_MULLWx;
+ case PPC_ID_VLE_SE_NEG: return PPC_ID_NEGx;
+ case PPC_ID_VLE_SE_NOP: return PPC_ID_NOP;
+ case PPC_ID_VLE_SE_NOT: return PPC_ID_NORx;
+ case PPC_ID_VLE_SE_OR: return PPC_ID_ORx;
+ case PPC_ID_VLE_SE_RFCI: return PPC_ID_RFCI;
+ case PPC_ID_VLE_SE_RFDI: return PPC_ID_RFDI;
+ case PPC_ID_VLE_SE_RFI: return PPC_ID_RFI;
+ case PPC_ID_VLE_SE_RFMCI: return PPC_ID_RFMCI;
+ case PPC_ID_VLE_SE_SC: return PPC_ID_SC;
+ case PPC_ID_VLE_SE_SLW: return PPC_ID_SLWx;
+ case PPC_ID_VLE_SE_SLWI: return PPC_ID_SLWIx;
+ case PPC_ID_VLE_SE_SRAW: return PPC_ID_SRAWx;
+ case PPC_ID_VLE_SE_SRAWI: return PPC_ID_SRAWIx;
+ case PPC_ID_VLE_SE_SRW: return PPC_ID_SRWx;
+ case PPC_ID_VLE_SE_SRWI: return PPC_ID_SRWIx;
+ case PPC_ID_VLE_SE_SUB: return PPC_ID_SUBFx;
+ case PPC_ID_VLE_SE_SUBF: return PPC_ID_SUBFx;
+ case PPC_ID_VLE_SE_SUBIx: return PPC_ID_ADDIx;
+
+ // We purposefully keep some branch instructions as VLE
+ // instructions, for translating their operand lists as
+ // a special case
+ case PPC_ID_VLE_E_BCx:
+ case PPC_ID_VLE_SE_BC:
+ case PPC_ID_VLE_SE_BCTRx:
+ case PPC_ID_VLE_SE_BLRx:
+ return id;
+
+ // These instructions don't have a non-VLE equivalent
+ case PPC_ID_VLE_E_CMPH16I:
+ case PPC_ID_VLE_E_CMPHL:
+ case PPC_ID_VLE_E_CMPHL16I:
+ case PPC_ID_VLE_E_RLWx:
+ case PPC_ID_VLE_E_RLWIx:
+ case PPC_ID_VLE_SE_BTSTI:
+ case PPC_ID_VLE_SE_CMPH:
+ case PPC_ID_VLE_SE_CMPHL:
+ case PPC_ID_VLE_SE_ILLEGAL:
+ case PPC_ID_VLE_SE_LBZ: // VLE treats rA=0 as valid base
+ case PPC_ID_VLE_SE_LHZ: // VLE treats rA=0 as valid base
+ case PPC_ID_VLE_SE_LWZ: // VLE treats rA=0 as valid base
+ case PPC_ID_VLE_SE_STB: // VLE treats rA=0 as valid base
+ case PPC_ID_VLE_SE_STH: // VLE treats rA=0 as valid base
+ case PPC_ID_VLE_SE_STW: // VLE treats rA=0 as valid base
+ return id;
+
+ default:
+ return id;
+ }
+}