static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, int);
+struct dis_private {
+ /* Stash the result of parsing disassembler_options here. */
+ int dialect;
+};
+
/* Determine which set of machines to disassemble for. PPC403/601 or
BookE. For convenience, also disassemble instructions supported
by the AltiVec vector unit. */
-int
+static int
powerpc_dialect (struct disassemble_info *info)
{
int dialect = PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC;
dialect |= PPC_OPCODE_64;
if (info->disassembler_options
- && (strcmp (info->disassembler_options, "booke") == 0
- || strcmp (info->disassembler_options, "booke32") == 0
- || strcmp (info->disassembler_options, "booke64") == 0))
+ && strstr (info->disassembler_options, "booke") != NULL)
dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64;
- else
- if ((info->mach == bfd_mach_ppc_e500)
- || (info->disassembler_options
- && ( strcmp (info->disassembler_options, "e500") == 0
- || strcmp (info->disassembler_options, "e500x2") == 0)))
- {
- dialect |= PPC_OPCODE_BOOKE
- | PPC_OPCODE_SPE | PPC_OPCODE_ISEL
- | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
- | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
- | PPC_OPCODE_RFMCI;
- /* efs* and AltiVec conflict. */
- dialect &= ~PPC_OPCODE_ALTIVEC;
- }
- else
- if (info->disassembler_options
- && (strcmp (info->disassembler_options, "efs") == 0))
- {
- dialect |= PPC_OPCODE_EFS;
- /* efs* and AltiVec conflict. */
- dialect &= ~PPC_OPCODE_ALTIVEC;
- }
+ else if ((info->mach == bfd_mach_ppc_e500)
+ || (info->disassembler_options
+ && strstr (info->disassembler_options, "e500") != NULL))
+ {
+ dialect |= PPC_OPCODE_BOOKE
+ | PPC_OPCODE_SPE | PPC_OPCODE_ISEL
+ | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
+ | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
+ | PPC_OPCODE_RFMCI;
+ /* efs* and AltiVec conflict. */
+ dialect &= ~PPC_OPCODE_ALTIVEC;
+ }
+ else if (info->disassembler_options
+ && strstr (info->disassembler_options, "efs") != NULL)
+ {
+ dialect |= PPC_OPCODE_EFS;
+ /* efs* and AltiVec conflict. */
+ dialect &= ~PPC_OPCODE_ALTIVEC;
+ }
else
dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC
| PPC_OPCODE_COMMON);
if (info->disassembler_options
- && strcmp (info->disassembler_options, "power4") == 0)
+ && strstr (info->disassembler_options, "power4") != NULL)
dialect |= PPC_OPCODE_POWER4;
+ if (info->disassembler_options
+ && strstr (info->disassembler_options, "any") != NULL)
+ dialect |= PPC_OPCODE_ANY;
+
if (info->disassembler_options)
{
if (strstr (info->disassembler_options, "32") != NULL)
dialect |= PPC_OPCODE_64;
}
+ ((struct dis_private *) &info->private_data)->dialect = dialect;
return dialect;
}
int
print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
{
- return print_insn_powerpc (memaddr, info, 1, powerpc_dialect(info));
+ int dialect = ((struct dis_private *) &info->private_data)->dialect;
+ return print_insn_powerpc (memaddr, info, 1, dialect);
}
/* Print a little endian PowerPC instruction. */
int
print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info)
{
- return print_insn_powerpc (memaddr, info, 0, powerpc_dialect(info));
+ int dialect = ((struct dis_private *) &info->private_data)->dialect;
+ return print_insn_powerpc (memaddr, info, 0, dialect);
}
/* Print a POWER (RS/6000) instruction. */
const struct powerpc_opcode *opcode_end;
unsigned long op;
+ if (dialect == 0)
+ dialect = powerpc_dialect (info);
+
status = (*info->read_memory_func) (memaddr, buffer, 4, info);
if (status != 0)
{
/* Find the first match in the opcode table. We could speed this up
a bit by doing a binary search on the major opcode. */
opcode_end = powerpc_opcodes + powerpc_num_opcodes;
+ again:
for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
{
unsigned long table_op;
|| (opcode->flags & dialect) == 0)
continue;
- if ((dialect & PPC_OPCODE_EFS) && (opcode->flags & PPC_OPCODE_ALTIVEC))
- continue;
-
/* Make two passes over the operands. First see if any of them
have extraction functions, and, if they do, make sure the
instruction is valid. */
return 4;
}
+ if ((dialect & PPC_OPCODE_ANY) != 0)
+ {
+ dialect = ~PPC_OPCODE_ANY;
+ goto again;
+ }
+
/* We could not find a match. */
(*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
;
/* If only one bit of the FXM field is set, we can use the new form
- of the instruction, which is faster. */
+ of the instruction, which is faster. Unlike the Power4 branch hint
+ encoding, this is not backward compatible. */
else if ((dialect & PPC_OPCODE_POWER4) != 0 && (value & -value) == value)
insn |= 1 << 20;
/* Smaller names for the flags so each entry in the opcodes table will
fit on a single line. */
#undef PPC
-#define PPC PPC_OPCODE_PPC | PPC_OPCODE_ANY
-#define PPCCOM PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_ANY
+#define PPC PPC_OPCODE_PPC
+#define PPCCOM PPC_OPCODE_PPC | PPC_OPCODE_COMMON
#define NOPOWER4 PPC_OPCODE_NOPOWER4 | PPCCOM
-#define POWER4 PPC_OPCODE_POWER4 | PPCCOM
-#define PPC32 PPC_OPCODE_32 | PPC_OPCODE_PPC | PPC_OPCODE_ANY
-#define PPC64 PPC_OPCODE_64 | PPC_OPCODE_PPC | PPC_OPCODE_ANY
-#define PPCONLY PPC_OPCODE_PPC
+#define POWER4 PPC_OPCODE_POWER4
+#define PPC32 PPC_OPCODE_32 | PPC_OPCODE_PPC
+#define PPC64 PPC_OPCODE_64 | PPC_OPCODE_PPC
#define PPC403 PPC_OPCODE_403
#define PPC405 PPC403
#define PPC440 PPC_OPCODE_440
#define PPC750 PPC
#define PPC860 PPC
-#define PPCVEC PPC_OPCODE_ALTIVEC | PPC_OPCODE_ANY | PPC_OPCODE_PPC
-#define POWER PPC_OPCODE_POWER | PPC_OPCODE_ANY
-#define POWER2 PPC_OPCODE_POWER | PPC_OPCODE_POWER2 | PPC_OPCODE_ANY
-#define PPCPWR2 PPC_OPCODE_PPC | PPC_OPCODE_POWER | PPC_OPCODE_POWER2 | PPC_OPCODE_ANY
-#define POWER32 PPC_OPCODE_POWER | PPC_OPCODE_ANY | PPC_OPCODE_32
-#define COM PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_ANY
-#define COM32 PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_ANY | PPC_OPCODE_32
-#define M601 PPC_OPCODE_POWER | PPC_OPCODE_601 | PPC_OPCODE_ANY
-#define PWRCOM PPC_OPCODE_POWER | PPC_OPCODE_601 | PPC_OPCODE_COMMON | PPC_OPCODE_ANY
+#define PPCVEC PPC_OPCODE_ALTIVEC | PPC_OPCODE_PPC
+#define POWER PPC_OPCODE_POWER
+#define POWER2 PPC_OPCODE_POWER | PPC_OPCODE_POWER2
+#define PPCPWR2 PPC_OPCODE_PPC | PPC_OPCODE_POWER | PPC_OPCODE_POWER2
+#define POWER32 PPC_OPCODE_POWER | PPC_OPCODE_32
+#define COM PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON
+#define COM32 PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_32
+#define M601 PPC_OPCODE_POWER | PPC_OPCODE_601
+#define PWRCOM PPC_OPCODE_POWER | PPC_OPCODE_601 | PPC_OPCODE_COMMON
#define MFDEC1 PPC_OPCODE_POWER
#define MFDEC2 PPC_OPCODE_PPC | PPC_OPCODE_601 | PPC_OPCODE_BOOKE
#define BOOKE PPC_OPCODE_BOOKE
{ "cmplwi", OPL(10,0), OPL_MASK, PPCCOM, { OBF, RA, UI } },
{ "cmpldi", OPL(10,1), OPL_MASK, PPC64, { OBF, RA, UI } },
-{ "cmpli", OP(10), OP_MASK, PPCONLY, { BF, L, RA, UI } },
+{ "cmpli", OP(10), OP_MASK, PPC, { BF, L, RA, UI } },
{ "cmpli", OP(10), OP_MASK, PWRCOM, { BF, RA, UI } },
{ "cmpwi", OPL(11,0), OPL_MASK, PPCCOM, { OBF, RA, SI } },
{ "cmpdi", OPL(11,1), OPL_MASK, PPC64, { OBF, RA, SI } },
-{ "cmpi", OP(11), OP_MASK, PPCONLY, { BF, L, RA, SI } },
+{ "cmpi", OP(11), OP_MASK, PPC, { BF, L, RA, SI } },
{ "cmpi", OP(11), OP_MASK, PWRCOM, { BF, RA, SI } },
{ "addic", OP(12), OP_MASK, PPCCOM, { RT, RA, SI } },
{ "cmpw", XCMPL(31,0,0), XCMPL_MASK, PPCCOM, { OBF, RA, RB } },
{ "cmpd", XCMPL(31,0,1), XCMPL_MASK, PPC64, { OBF, RA, RB } },
-{ "cmp", X(31,0), XCMP_MASK, PPCONLY, { BF, L, RA, RB } },
+{ "cmp", X(31,0), XCMP_MASK, PPC, { BF, L, RA, RB } },
{ "cmp", X(31,0), XCMPL_MASK, PWRCOM, { BF, RA, RB } },
{ "twlgt", XTO(31,4,TOLGT), XTO_MASK, PPCCOM, { RA, RB } },
{ "cmplw", XCMPL(31,32,0), XCMPL_MASK, PPCCOM, { OBF, RA, RB } },
{ "cmpld", XCMPL(31,32,1), XCMPL_MASK, PPC64, { OBF, RA, RB } },
-{ "cmpl", X(31,32), XCMP_MASK, PPCONLY, { BF, L, RA, RB } },
+{ "cmpl", X(31,32), XCMP_MASK, PPC, { BF, L, RA, RB } },
{ "cmpl", X(31,32), XCMPL_MASK, PWRCOM, { BF, RA, RB } },
{ "subf", XO(31,40,0,0), XO_MASK, PPC, { RT, RA, RB } },
{ "mfsprg5", XSPR(31,339,261), XSPR_MASK, PPC405, { RT } },
{ "mfsprg6", XSPR(31,339,262), XSPR_MASK, PPC405, { RT } },
{ "mfsprg7", XSPR(31,339,263), XSPR_MASK, PPC405, { RT } },
-{ "mftb", XSPR(31,339,268), XSPR_MASK, BOOKE, { RT } },
{ "mftb", X(31,371), X_MASK, CLASSIC, { RT, TBR } },
-{ "mftbl", XSPR(31,339,268), XSPR_MASK, BOOKE, { RT } },
+{ "mftb", XSPR(31,339,268), XSPR_MASK, BOOKE, { RT } },
{ "mftbl", XSPR(31,371,268), XSPR_MASK, CLASSIC, { RT } },
-{ "mftbu", XSPR(31,339,269), XSPR_MASK, BOOKE, { RT } },
+{ "mftbl", XSPR(31,339,268), XSPR_MASK, BOOKE, { RT } },
{ "mftbu", XSPR(31,371,269), XSPR_MASK, CLASSIC, { RT } },
+{ "mftbu", XSPR(31,339,269), XSPR_MASK, BOOKE, { RT } },
{ "mfsprg", XSPR(31,339,272), XSPRG_MASK, PPC, { RT, SPRG } },
{ "mfsprg0", XSPR(31,339,272), XSPR_MASK, PPC, { RT } },
{ "mfsprg1", XSPR(31,339,273), XSPR_MASK, PPC, { RT } },
{ "lswi", X(31,597), X_MASK, PPCCOM, { RT, RA, NB } },
{ "lsi", X(31,597), X_MASK, PWRCOM, { RT, RA, NB } },
-{ "lwsync", XSYNC(31,598,1), 0xffffffff, PPCONLY, { 0 } },
+{ "lwsync", XSYNC(31,598,1), 0xffffffff, PPC, { 0 } },
{ "ptesync", XSYNC(31,598,2), 0xffffffff, PPC64, { 0 } },
{ "msync", X(31,598), 0xffffffff, BOOKE, { 0 } },
{ "sync", X(31,598), XSYNC_MASK, PPCCOM, { LS } },