/* This entry, mips16, is here only for ISA/processor selection; do
not print its name. */
- { "", 1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3, 0,
+ { "", 1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS64, 0,
mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
mips_hwr_names_numeric },
};
return 0;
}
+/* Convert ASE flags from .MIPS.abiflags to internal values. */
+
+static unsigned long
+mips_convert_abiflags_ases (unsigned long afl_ases)
+{
+ unsigned long opcode_ases = 0;
+
+ if (afl_ases & AFL_ASE_DSP)
+ opcode_ases |= ASE_DSP;
+ if (afl_ases & AFL_ASE_DSPR2)
+ opcode_ases |= ASE_DSPR2;
+ if (afl_ases & AFL_ASE_EVA)
+ opcode_ases |= ASE_EVA;
+ if (afl_ases & AFL_ASE_MCU)
+ opcode_ases |= ASE_MCU;
+ if (afl_ases & AFL_ASE_MDMX)
+ opcode_ases |= ASE_MDMX;
+ if (afl_ases & AFL_ASE_MIPS3D)
+ opcode_ases |= ASE_MIPS3D;
+ if (afl_ases & AFL_ASE_MT)
+ opcode_ases |= ASE_MT;
+ if (afl_ases & AFL_ASE_SMARTMIPS)
+ opcode_ases |= ASE_SMARTMIPS;
+ if (afl_ases & AFL_ASE_VIRT)
+ opcode_ases |= ASE_VIRT;
+ if (afl_ases & AFL_ASE_MSA)
+ opcode_ases |= ASE_MSA;
+ if (afl_ases & AFL_ASE_XPA)
+ opcode_ases |= ASE_XPA;
+ if (afl_ases & AFL_ASE_DSPR3)
+ opcode_ases |= ASE_DSPR3;
+ return opcode_ases;
+}
+
static void
set_default_mips_dis_options (struct disassemble_info *info)
{
mips_hwr_names = mips_hwr_names_numeric;
no_aliases = 0;
- /* Update settings according to the ELF file header flags. */
- if (info->flavour == bfd_target_elf_flavour && info->section != NULL)
- {
- Elf_Internal_Ehdr *header;
-
- header = elf_elfheader (info->section->owner);
- /* If an ELF "newabi" binary, use the n32/(n)64 GPR names. */
- if (is_newabi (header))
- mips_gpr_names = mips_gpr_names_newabi;
- /* If a microMIPS binary, then don't use MIPS16 bindings. */
- micromips_ase = is_micromips (header);
- }
-
/* Set ISA, architecture, and cp0 register names as best we can. */
#if ! SYMTAB_AVAILABLE
/* This is running out on a target machine, not in a host tool.
mips_cp1_names = chosen_arch->cp1_names;
mips_hwr_names = chosen_arch->hwr_names;
}
+
+ /* Update settings according to the ELF file header flags. */
+ if (info->flavour == bfd_target_elf_flavour && info->section != NULL)
+ {
+ struct bfd *abfd = info->section->owner;
+ Elf_Internal_Ehdr *header = elf_elfheader (abfd);
+ Elf_Internal_ABIFlags_v0 *abiflags = NULL;
+
+ /* We won't ever get here if !HAVE_BFD_MIPS_ELF_GET_ABIFLAGS,
+ because we won't then have a MIPS/ELF BFD, however we need
+ to guard against a link error in a `--enable-targets=...'
+ configuration with a 32-bit host where the MIPS target is
+ a secondary, or with MIPS/ECOFF configurations. */
+#ifdef HAVE_BFD_MIPS_ELF_GET_ABIFLAGS
+ abiflags = bfd_mips_elf_get_abiflags (abfd);
+#endif
+ /* If an ELF "newabi" binary, use the n32/(n)64 GPR names. */
+ if (is_newabi (header))
+ mips_gpr_names = mips_gpr_names_newabi;
+ /* If a microMIPS binary, then don't use MIPS16 bindings. */
+ micromips_ase = is_micromips (header);
+ /* OR in any extra ASE flags set in ELF file structures. */
+ if (abiflags)
+ mips_ase |= mips_convert_abiflags_ases (abiflags->ases);
+ else if (header->e_flags & EF_MIPS_ARCH_ASE_MDMX)
+ mips_ase |= ASE_MDMX;
+ }
#endif
}
const fprintf_ftype infprintf = info->fprintf_func;
void *is = info->stream;
const struct mips_operand *operand, *ext_operand;
+ unsigned short ext_size;
unsigned int uval;
bfd_vma baseaddr;
info->data_size = 1 << int_op->shift;
}
- if (operand->size == 26)
- /* In this case INSN is the first two bytes of the instruction
- and EXTEND is the second two bytes. */
- uval = ((insn & 0x1f) << 21) | ((insn & 0x3e0) << 11) | extend;
- else
+ ext_size = 0;
+ if (use_extend)
{
- /* Calculate the full field value. */
- uval = mips_extract_operand (operand, insn);
- if (use_extend)
+ ext_operand = decode_mips16_operand (type, TRUE);
+ if (ext_operand != operand)
{
- ext_operand = decode_mips16_operand (type, TRUE);
- if (ext_operand != operand)
- {
- operand = ext_operand;
- if (operand->size == 16)
- uval = (((extend & 0x1f) << 11) | (extend & 0x7e0)
- | (uval & 0x1f));
- else if (operand->size == 15)
- uval |= ((extend & 0xf) << 11) | (extend & 0x7f0);
- else
- uval = ((((extend >> 6) & 0x1f) | (extend & 0x20))
- & ((1U << operand->size) - 1));
- }
+ ext_size = ext_operand->size;
+ operand = ext_operand;
}
}
+ if (operand->size == 26)
+ uval = ((extend & 0x1f) << 21) | ((extend & 0x3e0) << 11) | insn;
+ else if (ext_size == 16)
+ uval = ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f);
+ else if (ext_size == 15)
+ uval = ((extend & 0xf) << 11) | (extend & 0x7f0) | (insn & 0xf);
+ else if (ext_size == 6)
+ uval = ((extend >> 6) & 0x1f) | (extend & 0x20);
+ else
+ uval = mips_extract_operand (operand, (extend << 16) | insn);
baseaddr = memaddr + 2;
if (operand->type == OP_PCREL)
if (!pcrel_op->include_isa_bit && use_extend)
baseaddr = memaddr - 2;
else if (!pcrel_op->include_isa_bit)
- {
- bfd_byte buffer[2];
-
- /* If this instruction is in the delay slot of a JAL/JALX
- instruction, the base address is the address of the
- JAL/JALX instruction. If it is in the delay slot of
- a JR/JALR instruction, the base address is the address
- of the JR/JALR instruction. This test is unreliable:
- we have no way of knowing whether the previous word is
- instruction or data. */
- if (info->read_memory_func (memaddr - 4, buffer, 2, info) == 0
- && (((info->endian == BFD_ENDIAN_BIG
- ? bfd_getb16 (buffer)
- : bfd_getl16 (buffer))
- & 0xf800) == 0x1800))
- baseaddr = memaddr - 4;
- else if (info->read_memory_func (memaddr - 2, buffer, 2,
- info) == 0
- && (((info->endian == BFD_ENDIAN_BIG
- ? bfd_getb16 (buffer)
- : bfd_getl16 (buffer))
- & 0xf89f) == 0xe800)
- && (((info->endian == BFD_ENDIAN_BIG
- ? bfd_getb16 (buffer)
- : bfd_getl16 (buffer))
- & 0x0060) != 0x0060))
- baseaddr = memaddr - 2;
- else
- baseaddr = memaddr;
- }
+ {
+ bfd_byte buffer[2];
+
+ /* If this instruction is in the delay slot of a JAL/JALX
+ instruction, the base address is the address of the
+ JAL/JALX instruction. If it is in the delay slot of
+ a JR/JALR instruction, the base address is the address
+ of the JR/JALR instruction. This test is unreliable:
+ we have no way of knowing whether the previous word is
+ instruction or data. */
+ if (info->read_memory_func (memaddr - 4, buffer, 2, info) == 0
+ && (((info->endian == BFD_ENDIAN_BIG
+ ? bfd_getb16 (buffer)
+ : bfd_getl16 (buffer))
+ & 0xf800) == 0x1800))
+ baseaddr = memaddr - 4;
+ else if (info->read_memory_func (memaddr - 2, buffer, 2,
+ info) == 0
+ && (((info->endian == BFD_ENDIAN_BIG
+ ? bfd_getb16 (buffer)
+ : bfd_getl16 (buffer))
+ & 0xf89f) == 0xe800)
+ && (((info->endian == BFD_ENDIAN_BIG
+ ? bfd_getb16 (buffer)
+ : bfd_getl16 (buffer))
+ & 0x0060) != 0x0060))
+ baseaddr = memaddr - 2;
+ else
+ baseaddr = memaddr;
+ }
}
print_insn_arg (info, state, opcode, operand, baseaddr + 1, uval);
return FALSE;
}
+/* Whether none, a 32-bit or a 16-bit instruction match has been done. */
+
+enum match_kind
+{
+ MATCH_NONE,
+ MATCH_FULL,
+ MATCH_SHORT
+};
+
/* Disassemble mips16 instructions. */
static int
const fprintf_ftype infprintf = info->fprintf_func;
int status;
bfd_byte buffer[4];
- int length;
- int insn;
- bfd_boolean use_extend;
- int extend = 0;
const struct mips_opcode *op, *opend;
struct mips_print_arg_state state;
void *is = info->stream;
+ bfd_boolean have_second;
+ unsigned int second;
+ unsigned int first;
+ unsigned int full;
info->bytes_per_chunk = 2;
info->display_endian = info->endian;
return -1;
}
- length = 2;
-
if (info->endian == BFD_ENDIAN_BIG)
- insn = bfd_getb16 (buffer);
+ first = bfd_getb16 (buffer);
else
- insn = bfd_getl16 (buffer);
+ first = bfd_getl16 (buffer);
- /* Handle the extend opcode specially. */
- use_extend = FALSE;
- if ((insn & 0xf800) == 0xf000)
+ status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
+ if (status == 0)
{
- use_extend = TRUE;
- extend = insn & 0x7ff;
-
- memaddr += 2;
-
- status = (*info->read_memory_func) (memaddr, buffer, 2, info);
- if (status != 0)
- {
- infprintf (is, "extend 0x%x", (unsigned int) extend);
- (*info->memory_error_func) (status, memaddr, info);
- return -1;
- }
-
+ have_second = TRUE;
if (info->endian == BFD_ENDIAN_BIG)
- insn = bfd_getb16 (buffer);
+ second = bfd_getb16 (buffer);
else
- insn = bfd_getl16 (buffer);
-
- /* Check for an extend opcode followed by an extend opcode. */
- if ((insn & 0xf800) == 0xf000)
- {
- infprintf (is, "extend 0x%x", (unsigned int) extend);
- info->insn_type = dis_noninsn;
- return length;
- }
-
- length += 2;
+ second = bfd_getl16 (buffer);
+ full = (first << 16) | second;
+ }
+ else
+ {
+ have_second = FALSE;
+ second = 0;
+ full = first;
}
/* FIXME: Should probably use a hash table on the major opcode here. */
opend = mips16_opcodes + bfd_mips16_num_opcodes;
for (op = mips16_opcodes; op < opend; op++)
{
- if (op->pinfo != INSN_MACRO
- && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
- && (insn & op->mask) == op->match)
- {
- const char *s;
-
- if (op->args[0] == 'a' || op->args[0] == 'i')
- {
- if (use_extend)
- {
- infprintf (is, "extend 0x%x", (unsigned int) extend);
- info->insn_type = dis_noninsn;
- return length - 2;
- }
+ enum match_kind match;
- use_extend = FALSE;
+ if (!opcode_is_member (op, mips_isa, mips_ase, mips_processor))
+ continue;
- memaddr += 2;
+ if (op->pinfo == INSN_MACRO
+ || (no_aliases && (op->pinfo2 & INSN2_ALIAS)))
+ match = MATCH_NONE;
+ else if (mips_opcode_32bit_p (op))
+ {
+ if (have_second
+ && (full & op->mask) == op->match)
+ match = MATCH_FULL;
+ else
+ match = MATCH_NONE;
+ }
+ else if ((first & op->mask) == op->match)
+ {
+ match = MATCH_SHORT;
+ second = 0;
+ full = first;
+ }
+ else if ((first & 0xf800) == 0xf000
+ && have_second
+ && !(op->pinfo2 & INSN2_SHORT_ONLY)
+ && (second & op->mask) == op->match)
+ match = MATCH_FULL;
+ else
+ match = MATCH_NONE;
- status = (*info->read_memory_func) (memaddr, buffer, 2,
- info);
- if (status == 0)
- {
- use_extend = TRUE;
- if (info->endian == BFD_ENDIAN_BIG)
- extend = bfd_getb16 (buffer);
- else
- extend = bfd_getl16 (buffer);
- length += 2;
- }
- }
+ if (match != MATCH_NONE)
+ {
+ const char *s;
infprintf (is, "%s", op->name);
if (op->args[0] != '\0')
{
if (*s == ','
&& s[1] == 'w'
- && GET_OP (insn, RX) == GET_OP (insn, RY))
+ && GET_OP (full, RX) == GET_OP (full, RY))
{
/* Skip the register and the comma. */
++s;
}
if (*s == ','
&& s[1] == 'v'
- && GET_OP (insn, RZ) == GET_OP (insn, RX))
+ && GET_OP (full, RZ) == GET_OP (full, RX))
{
/* Skip the register and the comma. */
++s;
continue;
}
- print_mips16_insn_arg (info, &state, op, *s, memaddr, insn,
- use_extend, extend, s[1] == '(');
+ switch (match)
+ {
+ case MATCH_FULL:
+ print_mips16_insn_arg (info, &state, op, *s, memaddr + 2,
+ second, TRUE, first, s[1] == '(');
+ break;
+ case MATCH_SHORT:
+ print_mips16_insn_arg (info, &state, op, *s, memaddr,
+ first, FALSE, 0, s[1] == '(');
+ break;
+ case MATCH_NONE: /* Stop the compiler complaining. */
+ break;
+ }
}
/* Figure out branch instruction type and delay slot information. */
else if ((op->pinfo2 & INSN2_COND_BRANCH) != 0)
info->insn_type = dis_condbranch;
- return length;
+ return match == MATCH_FULL ? 4 : 2;
}
}
#undef GET_OP
- if (use_extend)
- infprintf (is, "0x%x", extend | 0xf000);
- infprintf (is, "0x%x", insn);
+ infprintf (is, "0x%x", first);
info->insn_type = dis_noninsn;
- return length;
+ return 2;
}
/* Disassemble microMIPS instructions. */