/* Print mips instructions for GDB, the GNU debugger, or for objdump.
- Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009, 2012
- Free Software Foundation, Inc.
+ Copyright (C) 1989-2015 Free Software Foundation, Inc.
Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
This file is part of the GNU opcodes library.
"$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
};
+static const char * const mips_cp1_names_numeric[32] =
+{
+ "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
+ "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
+ "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
+ "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
+};
+
static const char * const mips_cp0_names_r3000[32] =
{
"c0_index", "c0_random", "c0_entrylo", "$3",
"c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave",
};
+static const char * const mips_cp1_names_mips3264[32] =
+{
+ "c1_fir", "c1_ufr", "$2", "$3",
+ "c1_unfr", "$5", "$6", "$7",
+ "$8", "$9", "$10", "$11",
+ "$12", "$13", "$14", "$15",
+ "$16", "$17", "$18", "$19",
+ "$20", "$21", "$22", "$23",
+ "$24", "c1_fccr", "c1_fexr", "$27",
+ "c1_fenr", "$29", "$30", "c1_fcsr"
+};
+
static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] =
{
{ 16, 1, "c0_config1" },
"$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
};
+static const char * const msa_control_names[32] =
+{
+ "msa_ir", "msa_csr", "msa_access", "msa_save",
+ "msa_modify", "msa_request", "msa_map", "msa_unmap",
+ "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
+ "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
+ "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
+};
+
struct mips_abi_choice
{
const char * name;
const char * const *cp0_names;
const struct mips_cp0sel_name *cp0sel_names;
unsigned int cp0sel_names_len;
+ const char * const *cp1_names;
const char * const *hwr_names;
};
const struct mips_arch_choice mips_arch_choices[] =
{
{ "numeric", 0, 0, 0, 0, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r3000", 1, bfd_mach_mips3000, CPU_R3000, ISA_MIPS1, 0,
- mips_cp0_names_r3000, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_r3000, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r3900", 1, bfd_mach_mips3900, CPU_R3900, ISA_MIPS1, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r4000", 1, bfd_mach_mips4000, CPU_R4000, ISA_MIPS3, 0,
- mips_cp0_names_r4000, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_r4000, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r4010", 1, bfd_mach_mips4010, CPU_R4010, ISA_MIPS2, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "vr4100", 1, bfd_mach_mips4100, CPU_VR4100, ISA_MIPS3, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "vr4111", 1, bfd_mach_mips4111, CPU_R4111, ISA_MIPS3, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "vr4120", 1, bfd_mach_mips4120, CPU_VR4120, ISA_MIPS3, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r4300", 1, bfd_mach_mips4300, CPU_R4300, ISA_MIPS3, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r4400", 1, bfd_mach_mips4400, CPU_R4400, ISA_MIPS3, 0,
- mips_cp0_names_r4000, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_r4000, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r4600", 1, bfd_mach_mips4600, CPU_R4600, ISA_MIPS3, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r4650", 1, bfd_mach_mips4650, CPU_R4650, ISA_MIPS3, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r5000", 1, bfd_mach_mips5000, CPU_R5000, ISA_MIPS4, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "vr5400", 1, bfd_mach_mips5400, CPU_VR5400, ISA_MIPS4, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "vr5500", 1, bfd_mach_mips5500, CPU_VR5500, ISA_MIPS4, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r5900", 1, bfd_mach_mips5900, CPU_R5900, ISA_MIPS3, 0,
- mips_cp0_names_r5900, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_r5900, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r6000", 1, bfd_mach_mips6000, CPU_R6000, ISA_MIPS2, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "rm7000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "rm9000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r8000", 1, bfd_mach_mips8000, CPU_R8000, ISA_MIPS4, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r10000", 1, bfd_mach_mips10000, CPU_R10000, ISA_MIPS4, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r12000", 1, bfd_mach_mips12000, CPU_R12000, ISA_MIPS4, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r14000", 1, bfd_mach_mips14000, CPU_R14000, ISA_MIPS4, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "r16000", 1, bfd_mach_mips16000, CPU_R16000, ISA_MIPS4, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
{ "mips5", 1, bfd_mach_mips5, CPU_MIPS5, ISA_MIPS5, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
/* For stock MIPS32, disassemble all applicable MIPS-specified ASEs.
Note that MIPS-3D and MDMX are not applicable to MIPS32. (See
ISA_MIPS32, ASE_SMARTMIPS,
mips_cp0_names_mips3264,
mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
- mips_hwr_names_numeric },
+ mips_cp1_names_mips3264, mips_hwr_names_numeric },
{ "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
ISA_MIPS32R2,
(ASE_SMARTMIPS | ASE_DSP | ASE_DSPR2 | ASE_EVA | ASE_MIPS3D
- | ASE_MT | ASE_MCU | ASE_VIRT),
+ | ASE_MT | ASE_MCU | ASE_VIRT | ASE_MSA | ASE_XPA),
mips_cp0_names_mips3264r2,
mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
- mips_hwr_names_mips3264r2 },
+ mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
+
+ { "mips32r3", 1, bfd_mach_mipsisa32r3, CPU_MIPS32R3,
+ ISA_MIPS32R3,
+ (ASE_SMARTMIPS | ASE_DSP | ASE_DSPR2 | ASE_EVA | ASE_MIPS3D
+ | ASE_MT | ASE_MCU | ASE_VIRT | ASE_MSA | ASE_XPA),
+ mips_cp0_names_mips3264r2,
+ mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
+ mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
+
+ { "mips32r5", 1, bfd_mach_mipsisa32r5, CPU_MIPS32R5,
+ ISA_MIPS32R5,
+ (ASE_SMARTMIPS | ASE_DSP | ASE_DSPR2 | ASE_EVA | ASE_MIPS3D
+ | ASE_MT | ASE_MCU | ASE_VIRT | ASE_MSA | ASE_XPA),
+ mips_cp0_names_mips3264r2,
+ mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
+ mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
+
+ { "mips32r6", 1, bfd_mach_mipsisa32r6, CPU_MIPS32R6,
+ ISA_MIPS32R6,
+ (ASE_EVA | ASE_MSA | ASE_VIRT | ASE_XPA | ASE_MCU | ASE_MT | ASE_DSP
+ | ASE_DSPR2),
+ mips_cp0_names_mips3264r2,
+ mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
+ mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
/* For stock MIPS64, disassemble all applicable MIPS-specified ASEs. */
{ "mips64", 1, bfd_mach_mipsisa64, CPU_MIPS64,
ISA_MIPS64, ASE_MIPS3D | ASE_MDMX,
mips_cp0_names_mips3264,
mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
- mips_hwr_names_numeric },
+ mips_cp1_names_mips3264, mips_hwr_names_numeric },
{ "mips64r2", 1, bfd_mach_mipsisa64r2, CPU_MIPS64R2,
ISA_MIPS64R2,
(ASE_MIPS3D | ASE_DSP | ASE_DSPR2 | ASE_DSP64 | ASE_EVA | ASE_MT
- | ASE_MDMX | ASE_MCU | ASE_VIRT | ASE_VIRT64),
+ | ASE_MCU | ASE_VIRT | ASE_VIRT64 | ASE_MSA | ASE_MSA64 | ASE_XPA),
mips_cp0_names_mips3264r2,
mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
- mips_hwr_names_mips3264r2 },
+ mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
+
+ { "mips64r3", 1, bfd_mach_mipsisa64r3, CPU_MIPS64R3,
+ ISA_MIPS64R3,
+ (ASE_MIPS3D | ASE_DSP | ASE_DSPR2 | ASE_DSP64 | ASE_EVA | ASE_MT
+ | ASE_MCU | ASE_VIRT | ASE_VIRT64 | ASE_MSA | ASE_MSA64 | ASE_XPA),
+ mips_cp0_names_mips3264r2,
+ mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
+ mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
+
+ { "mips64r5", 1, bfd_mach_mipsisa64r5, CPU_MIPS64R5,
+ ISA_MIPS64R5,
+ (ASE_MIPS3D | ASE_DSP | ASE_DSPR2 | ASE_DSP64 | ASE_EVA | ASE_MT
+ | ASE_MCU | ASE_VIRT | ASE_VIRT64 | ASE_MSA | ASE_MSA64 | ASE_XPA),
+ mips_cp0_names_mips3264r2,
+ mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
+ mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
+
+ { "mips64r6", 1, bfd_mach_mipsisa64r6, CPU_MIPS64R6,
+ ISA_MIPS64R6,
+ (ASE_EVA | ASE_MSA | ASE_MSA64 | ASE_XPA | ASE_VIRT | ASE_VIRT64
+ | ASE_MCU | ASE_MT | ASE_DSP | ASE_DSPR2),
+ mips_cp0_names_mips3264r2,
+ mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
+ mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 },
{ "sb1", 1, bfd_mach_mips_sb1, CPU_SB1,
ISA_MIPS64 | INSN_SB1, ASE_MIPS3D,
mips_cp0_names_sb1,
mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1),
- mips_hwr_names_numeric },
+ mips_cp1_names_mips3264, mips_hwr_names_numeric },
{ "loongson2e", 1, bfd_mach_mips_loongson_2e, CPU_LOONGSON_2E,
ISA_MIPS3 | INSN_LOONGSON_2E, 0, mips_cp0_names_numeric,
- NULL, 0, mips_hwr_names_numeric },
+ NULL, 0, mips_cp1_names_numeric, mips_hwr_names_numeric },
{ "loongson2f", 1, bfd_mach_mips_loongson_2f, CPU_LOONGSON_2F,
ISA_MIPS3 | INSN_LOONGSON_2F, 0, mips_cp0_names_numeric,
- NULL, 0, mips_hwr_names_numeric },
+ NULL, 0, mips_cp1_names_numeric, mips_hwr_names_numeric },
{ "loongson3a", 1, bfd_mach_mips_loongson_3a, CPU_LOONGSON_3A,
- ISA_MIPS64 | INSN_LOONGSON_3A, 0, mips_cp0_names_numeric,
- NULL, 0, mips_hwr_names_numeric },
+ ISA_MIPS64R2 | INSN_LOONGSON_3A, 0, mips_cp0_names_numeric,
+ NULL, 0, mips_cp1_names_mips3264, mips_hwr_names_numeric },
{ "octeon", 1, bfd_mach_mips_octeon, CPU_OCTEON,
ISA_MIPS64R2 | INSN_OCTEON, 0, mips_cp0_names_numeric, NULL, 0,
- mips_hwr_names_numeric },
+ mips_cp1_names_mips3264, mips_hwr_names_numeric },
{ "octeon+", 1, bfd_mach_mips_octeonp, CPU_OCTEONP,
ISA_MIPS64R2 | INSN_OCTEONP, 0, mips_cp0_names_numeric,
- NULL, 0, mips_hwr_names_numeric },
+ NULL, 0, mips_cp1_names_mips3264, mips_hwr_names_numeric },
{ "octeon2", 1, bfd_mach_mips_octeon2, CPU_OCTEON2,
ISA_MIPS64R2 | INSN_OCTEON2, 0, mips_cp0_names_numeric,
- NULL, 0, mips_hwr_names_numeric },
+ NULL, 0, mips_cp1_names_mips3264, mips_hwr_names_numeric },
+
+ { "octeon3", 1, bfd_mach_mips_octeon3, CPU_OCTEON3,
+ ISA_MIPS64R5 | INSN_OCTEON3, ASE_VIRT | ASE_VIRT64,
+ mips_cp0_names_numeric,
+ NULL, 0, mips_cp1_names_mips3264, mips_hwr_names_numeric },
{ "xlr", 1, bfd_mach_mips_xlr, CPU_XLR,
ISA_MIPS64 | INSN_XLR, 0,
mips_cp0_names_xlr,
mips_cp0sel_names_xlr, ARRAY_SIZE (mips_cp0sel_names_xlr),
- mips_hwr_names_numeric },
+ mips_cp1_names_mips3264, mips_hwr_names_numeric },
/* XLP is mostly like XLR, with the prominent exception it is being
MIPS64R2. */
ISA_MIPS64R2 | INSN_XLR, 0,
mips_cp0_names_xlr,
mips_cp0sel_names_xlr, ARRAY_SIZE (mips_cp0sel_names_xlr),
- mips_hwr_names_numeric },
+ mips_cp1_names_mips3264, mips_hwr_names_numeric },
/* This entry, mips16, is here only for ISA/processor selection; do
not print its name. */
{ "", 1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+ mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
+ mips_hwr_names_numeric },
};
/* ISA and processor type to disassemble for, and register names to use.
static const char * const *mips_cp0_names;
static const struct mips_cp0sel_name *mips_cp0sel_names;
static int mips_cp0sel_names_len;
+static const char * const *mips_cp1_names;
static const char * const *mips_hwr_names;
/* Other options */
mips_cp0_names = mips_cp0_names_numeric;
mips_cp0sel_names = NULL;
mips_cp0sel_names_len = 0;
+ mips_cp1_names = mips_cp1_names_numeric;
mips_hwr_names = mips_hwr_names_numeric;
no_aliases = 0;
mips_cp0_names = chosen_arch->cp0_names;
mips_cp0sel_names = chosen_arch->cp0sel_names;
mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
+ mips_cp1_names = chosen_arch->cp1_names;
mips_hwr_names = chosen_arch->hwr_names;
}
#endif
return;
}
+ if (CONST_STRNEQ (option, "msa"))
+ {
+ mips_ase |= ASE_MSA;
+ if ((mips_isa & INSN_ISA_MASK) == ISA_MIPS64R2
+ || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R3
+ || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R5
+ || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R6)
+ mips_ase |= ASE_MSA64;
+ return;
+ }
+
if (CONST_STRNEQ (option, "virt"))
{
mips_ase |= ASE_VIRT;
- if (mips_isa & ISA_MIPS64R2)
+ if (mips_isa & ISA_MIPS64R2
+ || mips_isa & ISA_MIPS64R3
+ || mips_isa & ISA_MIPS64R5
+ || mips_isa & ISA_MIPS64R6)
mips_ase |= ASE_VIRT64;
return;
}
+
+ if (CONST_STRNEQ (option, "xpa"))
+ {
+ mips_ase |= ASE_XPA;
+ return;
+ }
+
/* Look for the = that delimits the end of the option name. */
for (i = 0; i < len; i++)
return;
}
+ if (strncmp ("cp1-names", option, optionlen) == 0
+ && strlen ("cp1-names") == optionlen)
+ {
+ chosen_arch = choose_arch_by_name (val, vallen);
+ if (chosen_arch != NULL)
+ mips_cp1_names = chosen_arch->cp1_names;
+ return;
+ }
+
if (strncmp ("hwr-names", option, optionlen) == 0
&& strlen ("hwr-names") == optionlen)
{
mips_cp0_names = chosen_arch->cp0_names;
mips_cp0sel_names = chosen_arch->cp0sel_names;
mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
+ mips_cp1_names = chosen_arch->cp1_names;
mips_hwr_names = chosen_arch->hwr_names;
}
return;
case OP_REG_COPRO:
if (opcode->name[strlen (opcode->name) - 1] == '0')
info->fprintf_func (info->stream, "%s", mips_cp0_names[regno]);
+ else if (opcode->name[strlen (opcode->name) - 1] == '1')
+ info->fprintf_func (info->stream, "%s", mips_cp1_names[regno]);
else
info->fprintf_func (info->stream, "$%d", regno);
break;
case OP_REG_HW:
info->fprintf_func (info->stream, "%s", mips_hwr_names[regno]);
break;
+
+ case OP_REG_VF:
+ info->fprintf_func (info->stream, "$vf%d", regno);
+ break;
+
+ case OP_REG_VI:
+ info->fprintf_func (info->stream, "$vi%d", regno);
+ break;
+
+ case OP_REG_R5900_I:
+ info->fprintf_func (info->stream, "$I");
+ break;
+
+ case OP_REG_R5900_Q:
+ info->fprintf_func (info->stream, "$Q");
+ break;
+
+ case OP_REG_R5900_R:
+ info->fprintf_func (info->stream, "$R");
+ break;
+
+ case OP_REG_R5900_ACC:
+ info->fprintf_func (info->stream, "$ACC");
+ break;
+
+ case OP_REG_MSA:
+ info->fprintf_func (info->stream, "$w%d", regno);
+ break;
+
+ case OP_REG_MSA_CTRL:
+ info->fprintf_func (info->stream, "%s", msa_control_names[regno]);
+ break;
+
}
}
\f
OP_REPEAT_DEST_REG and OP_REPEAT_PREV_REG. */
enum mips_reg_operand_type last_reg_type;
unsigned int last_regno;
+ unsigned int dest_regno;
+ unsigned int seen_dest;
};
/* Initialize STATE for the start of an instruction. */
memset (state, 0, sizeof (*state));
}
+/* Print OP_VU0_SUFFIX or OP_VU0_MATCH_SUFFIX operand OPERAND,
+ whose value is given by UVAL. */
+
+static void
+print_vu0_channel (struct disassemble_info *info,
+ const struct mips_operand *operand, unsigned int uval)
+{
+ if (operand->size == 4)
+ info->fprintf_func (info->stream, "%s%s%s%s",
+ uval & 8 ? "x" : "",
+ uval & 4 ? "y" : "",
+ uval & 2 ? "z" : "",
+ uval & 1 ? "w" : "");
+ else if (operand->size == 2)
+ info->fprintf_func (info->stream, "%c", "xyzw"[uval]);
+ else
+ abort ();
+}
+
+/* Record information about a register operand. */
+
+static void
+mips_seen_register (struct mips_print_arg_state *state,
+ unsigned int regno,
+ enum mips_reg_operand_type reg_type)
+{
+ state->last_reg_type = reg_type;
+ state->last_regno = regno;
+
+ if (!state->seen_dest)
+ {
+ state->seen_dest = 1;
+ state->dest_regno = regno;
+ }
+}
+
/* Print operand OPERAND of OPCODE, using STATE to track inter-operand state.
UVAL is the encoding of the operand (shifted into bit 0) and BASE_PC is
the base address for OP_PCREL operands. */
break;
case OP_REG:
+ case OP_OPTIONAL_REG:
{
const struct mips_reg_operand *reg_op;
reg_op = (const struct mips_reg_operand *) operand;
- if (reg_op->reg_map)
- uval = reg_op->reg_map[uval];
+ uval = mips_decode_reg_operand (reg_op, uval);
print_reg (info, opcode, reg_op->reg_type, uval);
- state->last_reg_type = reg_op->reg_type;
- state->last_regno = uval;
+ mips_seen_register (state, uval, reg_op->reg_type);
}
break;
}
break;
+ case OP_SAME_RS_RT:
+ case OP_CHECK_PREV:
+ case OP_NON_ZERO_REG:
+ {
+ print_reg (info, opcode, OP_REG_GP, uval & 31);
+ mips_seen_register (state, uval, OP_REG_GP);
+ }
+ break;
+
case OP_LWM_SWM_LIST:
if (operand->size == 2)
{
break;
case OP_REPEAT_DEST_REG:
- /* Should always match OP_REPEAT_PREV_REG first. */
- abort ();
+ print_reg (info, opcode, state->last_reg_type, state->dest_regno);
+ break;
case OP_PC:
infprintf (is, "$pc");
break;
+
+ case OP_VU0_SUFFIX:
+ case OP_VU0_MATCH_SUFFIX:
+ print_vu0_channel (info, operand, uval);
+ break;
+
+ case OP_IMM_INDEX:
+ infprintf (is, "[%d]", uval);
+ break;
+
+ case OP_REG_INDEX:
+ infprintf (is, "[");
+ print_reg (info, opcode, OP_REG_GP, uval);
+ infprintf (is, "]");
+ break;
+ }
+}
+
+/* Validate the arguments for INSN, which is described by OPCODE.
+ Use DECODE_OPERAND to get the encoding of each operand. */
+
+static bfd_boolean
+validate_insn_args (const struct mips_opcode *opcode,
+ const struct mips_operand *(*decode_operand) (const char *),
+ unsigned int insn)
+{
+ struct mips_print_arg_state state;
+ const struct mips_operand *operand;
+ const char *s;
+ unsigned int uval;
+
+ init_print_arg_state (&state);
+ for (s = opcode->args; *s; ++s)
+ {
+ switch (*s)
+ {
+ case ',':
+ case '(':
+ case ')':
+ break;
+
+ case '#':
+ ++s;
+ break;
+
+ default:
+ operand = decode_operand (s);
+
+ if (operand)
+ {
+ uval = mips_extract_operand (operand, insn);
+ switch (operand->type)
+ {
+ case OP_REG:
+ case OP_OPTIONAL_REG:
+ {
+ const struct mips_reg_operand *reg_op;
+
+ reg_op = (const struct mips_reg_operand *) operand;
+ uval = mips_decode_reg_operand (reg_op, uval);
+ mips_seen_register (&state, uval, reg_op->reg_type);
+ }
+ break;
+
+ case OP_SAME_RS_RT:
+ {
+ unsigned int reg1, reg2;
+
+ reg1 = uval & 31;
+ reg2 = uval >> 5;
+
+ if (reg1 != reg2 || reg1 == 0)
+ return FALSE;
+ }
+ break;
+
+ case OP_CHECK_PREV:
+ {
+ const struct mips_check_prev_operand *prev_op;
+
+ prev_op = (const struct mips_check_prev_operand *) operand;
+
+ if (!prev_op->zero_ok && uval == 0)
+ return FALSE;
+
+ if (((prev_op->less_than_ok && uval < state.last_regno)
+ || (prev_op->greater_than_ok && uval > state.last_regno)
+ || (prev_op->equal_ok && uval == state.last_regno)))
+ break;
+
+ return FALSE;
+ }
+
+ case OP_NON_ZERO_REG:
+ {
+ if (uval == 0)
+ return FALSE;
+ }
+ break;
+
+ case OP_INT:
+ case OP_MAPPED_INT:
+ case OP_MSB:
+ case OP_REG_PAIR:
+ case OP_PCREL:
+ case OP_PERF_REG:
+ case OP_ADDIUSP_INT:
+ case OP_CLO_CLZ_DEST:
+ case OP_LWM_SWM_LIST:
+ case OP_ENTRY_EXIT_LIST:
+ case OP_MDMX_IMM_REG:
+ case OP_REPEAT_PREV_REG:
+ case OP_REPEAT_DEST_REG:
+ case OP_PC:
+ case OP_VU0_SUFFIX:
+ case OP_VU0_MATCH_SUFFIX:
+ case OP_IMM_INDEX:
+ case OP_REG_INDEX:
+ break;
+
+ case OP_SAVE_RESTORE_LIST:
+ /* Should be handled by the caller due to extend behavior. */
+ abort ();
+ }
+ }
+ if (*s == 'm' || *s == '+' || *s == '-')
+ ++s;
+ }
}
+ return TRUE;
}
/* Print the arguments for INSN, which is described by OPCODE.
Use DECODE_OPERAND to get the encoding of each operand. Use BASE_PC
- as the base of OP_PCREL operands. */
+ as the base of OP_PCREL operands, adjusting by LENGTH if the OP_PCREL
+ operand is for a branch or jump. */
static void
print_insn_args (struct disassemble_info *info,
const struct mips_opcode *opcode,
const struct mips_operand *(*decode_operand) (const char *),
- unsigned int insn, bfd_vma base_pc)
+ unsigned int insn, bfd_vma insn_pc, unsigned int length)
{
const fprintf_ftype infprintf = info->fprintf_func;
void *is = info->stream;
infprintf (is, "%c", *s);
break;
+ case '#':
+ ++s;
+ infprintf (is, "%c%c", *s, *s);
+ break;
+
default:
operand = decode_operand (s);
if (!operand)
infprintf (is, "$%d,%d", reg, sel);
}
else
- print_insn_arg (info, &state, opcode, operand, base_pc,
- mips_extract_operand (operand, insn));
- if (*s == 'm' || *s == '+')
+ {
+ bfd_vma base_pc = insn_pc;
+
+ /* Adjust the PC relative base so that branch/jump insns use
+ the following PC as the base but genuinely PC relative
+ operands use the current PC. */
+ if (operand->type == OP_PCREL)
+ {
+ const struct mips_pcrel_operand *pcrel_op;
+
+ pcrel_op = (const struct mips_pcrel_operand *) operand;
+ /* The include_isa_bit flag is sufficient to distinguish
+ branch/jump from other PC relative operands. */
+ if (pcrel_op->include_isa_bit)
+ base_pc += length;
+ }
+
+ print_insn_arg (info, &state, opcode, operand, base_pc,
+ mips_extract_operand (operand, insn));
+ }
+ if (*s == 'm' || *s == '+' || *s == '-')
++s;
break;
}
&& !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
&& (word & op->mask) == op->match)
{
- /* We always allow to disassemble the jalx instruction. */
+ /* We always disassemble the jalx instruction, except for MIPS r6. */
if (!opcode_is_member (op, mips_isa, mips_ase, mips_processor)
- && strcmp (op->name, "jalx"))
+ && (strcmp (op->name, "jalx")
+ || (mips_isa & INSN_ISA_MASK) == ISA_MIPS32R6
+ || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R6))
continue;
/* Figure out instruction type and branch delay information. */
if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
{
- if ((op->pinfo & (INSN_WRITE_GPR_31
- | INSN_WRITE_GPR_D)) != 0)
+ if ((op->pinfo & (INSN_WRITE_GPR_31 | INSN_WRITE_1)) != 0)
info->insn_type = dis_jsr;
else
info->insn_type = dis_branch;
info->branch_delay_insns = 1;
}
else if ((op->pinfo & (INSN_STORE_MEMORY
- | INSN_LOAD_MEMORY_DELAY)) != 0)
+ | INSN_LOAD_MEMORY)) != 0)
info->insn_type = dis_dref;
+ if (!validate_insn_args (op, decode_mips_operand, word))
+ continue;
+
infprintf (is, "%s", op->name);
+ if (op->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX)
+ {
+ unsigned int uval;
+
+ infprintf (is, ".");
+ uval = mips_extract_operand (&mips_vu0_channel_mask, word);
+ print_vu0_channel (info, &mips_vu0_channel_mask, uval);
+ }
if (op->args[0])
{
infprintf (is, "\t");
print_insn_args (info, op, decode_mips_operand, word,
- memaddr + 4);
+ memaddr, 4);
}
return INSNLEN;
&& ((length == 2 && (op->mask & 0xffff0000) == 0)
|| (length == 4 && (op->mask & 0xffff0000) != 0)))
{
+ if (!validate_insn_args (op, decode_micromips_operand, insn))
+ continue;
+
infprintf (is, "%s", op->name);
if (op->args[0])
{
infprintf (is, "\t");
print_insn_args (info, op, decode_micromips_operand, insn,
- memaddr + length + 1);
+ memaddr + 1, length);
}
/* Figure out instruction type and branch delay information. */
if (((op->pinfo & INSN_UNCOND_BRANCH_DELAY)
| (op->pinfo2 & INSN2_UNCOND_BRANCH)) != 0)
{
- if ((op->pinfo & (INSN_WRITE_GPR_31 | INSN_WRITE_GPR_T)) != 0)
+ if ((op->pinfo & (INSN_WRITE_GPR_31 | INSN_WRITE_1)) != 0)
info->insn_type = dis_jsr;
else
info->insn_type = dis_branch;
info->insn_type = dis_condbranch;
}
else if ((op->pinfo
- & (INSN_STORE_MEMORY | INSN_LOAD_MEMORY_DELAY)) != 0)
+ & (INSN_STORE_MEMORY | INSN_LOAD_MEMORY)) != 0)
info->insn_type = dis_dref;
return length;
The following MIPS specific disassembler options are supported for use\n\
with the -M switch (multiple options should be separated by commas):\n"));
+ fprintf (stream, _("\n\
+ msa Recognize MSA instructions.\n"));
+
fprintf (stream, _("\n\
virt Recognize the virtualization ASE instructions.\n"));
+ fprintf (stream, _("\n\
+ xpa Recognize the eXtended Physical Address (XPA) ASE instructions.\n"));
+
fprintf (stream, _("\n\
gpr-names=ABI Print GPR names according to specified ABI.\n\
Default: based on binary being disassembled.\n"));