aboutsummaryrefslogtreecommitdiff
path: root/opcodes/ppc-dis.c
diff options
context:
space:
mode:
Diffstat (limited to 'opcodes/ppc-dis.c')
-rw-r--r--opcodes/ppc-dis.c83
1 files changed, 81 insertions, 2 deletions
diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c
index d75e59d..0e2e185 100644
--- a/opcodes/ppc-dis.c
+++ b/opcodes/ppc-dis.c
@@ -120,7 +120,8 @@ struct ppc_mopt ppc_opts[] = {
{ "e200z4", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE| PPC_OPCODE_SPE
| PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
| PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
- | PPC_OPCODE_E500 | PPC_OPCODE_VLE | PPC_OPCODE_E200Z4),
+ | PPC_OPCODE_E500 | PPC_OPCODE_VLE | PPC_OPCODE_E200Z4
+ | PPC_OPCODE_EFS2 | PPC_OPCODE_LSP),
0 },
{ "e300", PPC_OPCODE_PPC | PPC_OPCODE_E300,
0 },
@@ -156,6 +157,8 @@ struct ppc_mopt ppc_opts[] = {
0 },
{ "efs", PPC_OPCODE_PPC | PPC_OPCODE_EFS,
0 },
+ { "efs2", PPC_OPCODE_PPC | PPC_OPCODE_EFS | PPC_OPCODE_EFS2,
+ 0 },
{ "power4", PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4,
0 },
{ "power5", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
@@ -227,13 +230,15 @@ struct ppc_mopt ppc_opts[] = {
PPC_OPCODE_RAW },
{ "spe", PPC_OPCODE_PPC | PPC_OPCODE_EFS,
PPC_OPCODE_SPE },
+ { "spe2", PPC_OPCODE_PPC | PPC_OPCODE_EFS | PPC_OPCODE_EFS2 | PPC_OPCODE_SPE,
+ PPC_OPCODE_SPE2 },
{ "titan", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_PMR
| PPC_OPCODE_RFMCI | PPC_OPCODE_TITAN),
0 },
{ "vle", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE| PPC_OPCODE_SPE
| PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
| PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
- | PPC_OPCODE_E500 | PPC_OPCODE_LSP),
+ | PPC_OPCODE_LSP | PPC_OPCODE_EFS2 | PPC_OPCODE_SPE2),
PPC_OPCODE_VLE },
{ "vsx", PPC_OPCODE_PPC,
PPC_OPCODE_VSX },
@@ -362,6 +367,8 @@ powerpc_init_dialect (struct disassemble_info *info)
static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS+1];
#define VLE_OPCD_SEGS 32
static unsigned short vle_opcd_indices[VLE_OPCD_SEGS+1];
+#define SPE2_OPCD_SEGS 13
+static unsigned short spe2_opcd_indices[SPE2_OPCD_SEGS+1];
/* Calculate opcode table indices to speed up disassembly,
and init dialect. */
@@ -409,6 +416,24 @@ disassemble_init_powerpc (struct disassemble_info *info)
}
}
+ /* SPE2 opcodes */
+ i = spe2_num_opcodes;
+ while (--i >= 0)
+ {
+ unsigned xop = SPE2_XOP (spe2_opcodes[i].opcode);
+ unsigned seg = SPE2_XOP_TO_SEG (xop);
+
+ spe2_opcd_indices[seg] = i;
+ }
+
+ last = spe2_num_opcodes;
+ for (i = SPE2_OPCD_SEGS; i > 1; --i)
+ {
+ if (spe2_opcd_indices[i] == 0)
+ spe2_opcd_indices[i] = last;
+ last = spe2_opcd_indices[i];
+ }
+
if (info->arch == bfd_arch_powerpc)
powerpc_init_dialect (info);
}
@@ -596,6 +621,58 @@ lookup_vle (unsigned long insn)
return NULL;
}
+/* Find a match for INSN in the SPE2 opcode table. */
+
+static const struct powerpc_opcode *
+lookup_spe2 (unsigned long insn)
+{
+ const struct powerpc_opcode *opcode, *opcode_end;
+ unsigned op, xop, seg;
+
+ op = PPC_OP (insn);
+ if (op != 0x4)
+ {
+ /* This is not SPE2 insn.
+ * All SPE2 instructions have OP=4 and differs by XOP */
+ return NULL;
+ }
+ xop = SPE2_XOP (insn);
+ seg = SPE2_XOP_TO_SEG (xop);
+
+ /* Find the first match in the opcode table for this major opcode. */
+ opcode_end = spe2_opcodes + spe2_opcd_indices[seg + 1];
+ for (opcode = spe2_opcodes + spe2_opcd_indices[seg];
+ opcode < opcode_end;
+ ++opcode)
+ {
+ unsigned long table_opcd = opcode->opcode;
+ unsigned long table_mask = opcode->mask;
+ unsigned long insn2;
+ const unsigned char *opindex;
+ const struct powerpc_operand *operand;
+ int invalid;
+
+ insn2 = insn;
+ if ((insn2 & table_mask) != table_opcd)
+ continue;
+
+ /* Check validity of operands. */
+ invalid = 0;
+ for (opindex = opcode->operands; *opindex != 0; ++opindex)
+ {
+ operand = powerpc_operands + *opindex;
+ if (operand->extract)
+ (*operand->extract) (insn, (ppc_cpu_t)0, &invalid);
+ }
+ if (invalid)
+ continue;
+
+ return opcode;
+ }
+
+ return NULL;
+}
+
/* Print a PowerPC or POWER instruction. */
static int
@@ -646,6 +723,8 @@ print_insn_powerpc (bfd_vma memaddr,
if (opcode != NULL)
insn_is_short = PPC_OP_SE_VLE(opcode->mask);
}
+ if (opcode == NULL && (dialect & PPC_OPCODE_SPE2) != 0)
+ opcode = lookup_spe2 (insn);
if (opcode == NULL)
opcode = lookup_powerpc (insn, dialect & ~PPC_OPCODE_ANY);
if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)