diff options
Diffstat (limited to 'opcodes/ppc-dis.c')
-rw-r--r-- | opcodes/ppc-dis.c | 83 |
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) |