MIPS16e2: Add MIPS16e2 ASE support
authorMaciej W. Rozycki <macro@imgtec.com>
Mon, 15 May 2017 12:26:01 +0000 (13:26 +0100)
committerMaciej W. Rozycki <macro@imgtec.com>
Mon, 15 May 2017 12:57:10 +0000 (13:57 +0100)
Add MIPS16e2 ASE support as per the architecture specification[1],
including in particular:

1. A new ELF ASE flag to mark MIPS16e2 binaries.

2. MIPS16e2 instruction assembly support, including a relaxation update
   to use LUI rather than an LI/SLL instruction pair for loading the
   high part of 32-bit addresses.

3. MIPS16e2 instruction disassembly support, including updated rules for
   extended forms of instructions that are now subdecoded and therefore
   do not alias to the original MIPS16 ISA revision instructions even
   for encodings that are not valid in the MIPS16e2 instruction set.

Add `-mmips16e2' and `-mno-mips16e2' GAS command-line options and their
corresponding `mips16e2' and `no-mips16e2' settings for the `.set' and
`.module' pseudo-ops.  Control the availability of the MT ASE subset of
the MIPS16e2 instruction set with a combination of these controls and
the preexisting MT ASE controls.

Parts of this change by Matthew Fortune and Andrew Bennett.

References:

[1] "MIPS32 Architecture for Programmers: MIPS16e2 Application-Specific
    Extension Technical Reference Manual", Imagination Technologies
    Ltd., Document Number: MD01172, Revision 01.00, April 26, 2016

include/
* elf/mips.h (AFL_ASE_MIPS16E2): New macro.
(AFL_ASE_MASK): Adjust accordingly.
* opcode/mips.h: Document new operand codes defined.
(mips_operand_type): Add OP_REG28 enum value.
(INSN2_SHORT_ONLY): Update description.
(ASE_MIPS16E2, ASE_MIPS16E2_MT): New macros.

bfd/
* elfxx-mips.c (print_mips_ases): Handle MIPS16e2 ASE.

opcodes/
* mips-dis.c (mips_arch_choices): Add ASE_MIPS16E2 and
ASE_MIPS16E2_MT flags to the unnamed MIPS16 entry.
(mips_convert_abiflags_ases): Handle the AFL_ASE_MIPS16E2 flag.
(print_insn_arg) <OP_REG28>: Add handler.
(validate_insn_args) <OP_REG28>: Handle.
(print_mips16_insn_arg): Handle MIPS16 instructions that require
32-bit encoding and 9-bit immediates.
(print_insn_mips16): Handle MIPS16 instructions that require
32-bit encoding and MFC0/MTC0 operand decoding.
* mips16-opc.c (decode_mips16_operand) <'>', '9', 'G', 'N', 'O'>
<'Q', 'T', 'b', 'c', 'd', 'r', 'u'>: Add handlers.
(RD_C0, WR_C0, E2, E2MT): New macros.
(mips16_opcodes): Add entries for MIPS16e2 instructions:
GP-relative "addiu" and its "addu" spelling, "andi", "cache",
"di", "ehb", "ei", "ext", "ins", GP-relative "lb", "lbu", "lh",
"lhu", and "lw" instructions, "ll", "lui", "lwl", "lwr", "mfc0",
"movn", "movtn", "movtz", "movz", "mtc0", "ori", "pause",
"pref", "rdhwr", "sc", GP-relative "sb", "sh" and "sw"
instructions, "swl", "swr", "sync" and its "sync_acquire",
"sync_mb", "sync_release", "sync_rmb" and "sync_wmb" aliases,
"xori", "dmt", "dvpe", "emt" and "evpe".  Add split
regular/extended entries for original MIPS16 ISA revision
instructions whose extended forms are subdecoded in the MIPS16e2
ISA revision: "li", "sll" and "srl".

binutils/
* readelf.c (print_mips_ases): Handle MIPS16e2 ASE.
* NEWS: Mention MIPS16e2 ASE support.

gas/
* config/tc-mips.c (RELAX_MIPS16_ENCODE): Add `e2' flag.
(RELAX_MIPS16_E2): New macro.
(RELAX_MIPS16_PIC, RELAX_MIPS16_SYM32, RELAX_MIPS16_NOMACRO)
(RELAX_MIPS16_USER_SMALL, RELAX_MIPS16_USER_EXT)
(RELAX_MIPS16_DSLOT, RELAX_MIPS16_JAL_DSLOT)
(RELAX_MIPS16_EXTENDED, RELAX_MIPS16_MARK_EXTENDED)
(RELAX_MIPS16_CLEAR_EXTENDED, RELAX_MIPS16_ALWAYS_EXTENDED)
(RELAX_MIPS16_MARK_ALWAYS_EXTENDED)
(RELAX_MIPS16_CLEAR_ALWAYS_EXTENDED, RELAX_MIPS16_MACRO)
(RELAX_MIPS16_MARK_MACRO, RELAX_MIPS16_CLEAR_MACRO): Shift bits.
(mips16_immed_extend): New prototype.
(options): Add OPTION_MIPS16E2 and OPTION_NO_MIPS16E2 enum
values.
(md_longopts): Add "mmips16e2" and "mno-mips16e2" options.
(mips_ases): Add "mips16e2" entry.
(mips_set_ase): Handle MIPS16e2 ASE.
(insn_insert_operand): Explicitly handle immediates with MIPS16
instructions that require 32-bit encoding.
(is_opcode_valid_16): Pass enabled ASE bitmask on to
`opcode_is_member'.
(validate_mips_insn): Explicitly handle immediates with MIPS16
instructions that require 32-bit encoding.
(operand_reg_mask) <OP_REG28>: Add handler.
(match_reg28_operand): New function.
(match_operand) <OP_REG28>: Add handler.
(append_insn): Pass ASE_MIPS16E2 setting to RELAX_MIPS16_ENCODE.
(match_mips16_insn): Handle MIPS16 instructions that require
32-bit encoding and `V' and `u' operand codes.
(mips16_ip): Allow any characters except from `.' in opcodes.
(mips16_immed_extend): Handle 9-bit immediates.  Do not shuffle
immediates whose width is not one of these listed.
(md_estimate_size_before_relax): Handle MIPS16e2 relaxation.
(mips_relax_frag): Likewise.
(md_convert_frag): Likewise.
(mips_convert_ase_flags): Handle MIPS16e2 ASE.

* doc/as.texinfo (Target MIPS options): Add `-mmips16e2' and
`-mno-mips16e2' options.
(-mmips16e2, -mno-mips16e2): New options.
* doc/c-mips.texi (MIPS Options): Add `-mmips16e2' and
`-mno-mips16e2' options.
(MIPS ASE Instruction Generation Overrides): Add `.set mips16e2'
and `.set nomips16e2'.

15 files changed:
bfd/ChangeLog
bfd/elfxx-mips.c
binutils/ChangeLog
binutils/NEWS
binutils/readelf.c
gas/ChangeLog
gas/config/tc-mips.c
gas/doc/as.texinfo
gas/doc/c-mips.texi
include/ChangeLog
include/elf/mips.h
include/opcode/mips.h
opcodes/ChangeLog
opcodes/mips-dis.c
opcodes/mips16-opc.c

index bd7356cc6a53f675b611d79403499d2a92334aba..52c192d4bbdb391e0c706f2cb10ba6d0ef76c199 100644 (file)
@@ -1,3 +1,7 @@
+2017-05-15  Maciej W. Rozycki  <macro@imgtec.com>
+
+       * elfxx-mips.c (print_mips_ases): Handle MIPS16e2 ASE.
+
 2017-05-12  H.J. Lu  <hongjiu.lu@intel.com>
 
        * elf32-i386.c (elf_i386_parse_gnu_properties): Merge
index 70c7f1cc3dde66d6ef6c5b4827f7609c5da87092..61e1adb1ff16677a3f7700847f501c8c175df9ff 100644 (file)
@@ -15648,6 +15648,8 @@ print_mips_ases (FILE *file, unsigned int mask)
     fputs ("\n\tMICROMIPS ASE", file);
   if (mask & AFL_ASE_XPA)
     fputs ("\n\tXPA ASE", file);
+  if (mask & AFL_ASE_MIPS16E2)
+    fputs ("\n\tMIPS16e2 ASE", file);
   if (mask == 0)
     fprintf (file, "\n\t%s", _("None"));
   else if ((mask & ~AFL_ASE_MASK) != 0)
index 5e51572b465abb154bc5d2b2a20721abf755d56d..8a977d1959b0027c163665621771d884e4fc584f 100644 (file)
@@ -1,3 +1,8 @@
+2017-05-15  Maciej W. Rozycki  <macro@imgtec.com>
+
+       * readelf.c (print_mips_ases): Handle MIPS16e2 ASE.
+       * NEWS: Mention MIPS16e2 ASE support.
+
 2017-05-12  Maciej W. Rozycki  <macro@imgtec.com>
 
        * testsuite/binutils-all/mips/mips16-extend-insn.d: Adjust BREAK
index c03539d26838cf5ebcbd23729c9295b013a44aff..1bbd19f5bf2ed19e834fe716c51f029f639ba3eb 100644 (file)
@@ -1,5 +1,7 @@
 -*- text -*-
 
+* The MIPS port now supports the MIPS16e2 ASE for assembly and disassembly.
+
 * Add support for ELF SHF_GNU_MBIND and PT_GNU_MBIND_XXX.
 
 * Add support for the wasm32 ELF conversion of the WebAssembly file format.
index 16eb866f5c93e288779f81fcdfbfe01c1ec336cc..7ff29bc8ba162d14147098dc8b231b7bf053a5ea 100644 (file)
@@ -15043,6 +15043,8 @@ print_mips_ases (unsigned int mask)
     fputs ("\n\tMICROMIPS ASE", stdout);
   if (mask & AFL_ASE_XPA)
     fputs ("\n\tXPA ASE", stdout);
+  if (mask & AFL_ASE_MIPS16E2)
+    fputs ("\n\tMIPS16e2 ASE", stdout);
   if (mask == 0)
     fprintf (stdout, "\n\t%s", _("None"));
   else if ((mask & ~AFL_ASE_MASK) != 0)
index c9ed98b9989e48c3260e38ea9414bb18e5e20470..00b4742449bc782ff443d886d79957b79f288bdd 100644 (file)
@@ -1,3 +1,51 @@
+2017-05-15  Maciej W. Rozycki  <macro@imgtec.com>
+           Matthew Fortune  <matthew.fortune@imgtec.com>
+           Andrew Bennett  <andrew.bennett@imgtec.com>
+
+       * config/tc-mips.c (RELAX_MIPS16_ENCODE): Add `e2' flag.
+       (RELAX_MIPS16_E2): New macro.
+       (RELAX_MIPS16_PIC, RELAX_MIPS16_SYM32, RELAX_MIPS16_NOMACRO)
+       (RELAX_MIPS16_USER_SMALL, RELAX_MIPS16_USER_EXT)
+       (RELAX_MIPS16_DSLOT, RELAX_MIPS16_JAL_DSLOT)
+       (RELAX_MIPS16_EXTENDED, RELAX_MIPS16_MARK_EXTENDED)
+       (RELAX_MIPS16_CLEAR_EXTENDED, RELAX_MIPS16_ALWAYS_EXTENDED)
+       (RELAX_MIPS16_MARK_ALWAYS_EXTENDED)
+       (RELAX_MIPS16_CLEAR_ALWAYS_EXTENDED, RELAX_MIPS16_MACRO)
+       (RELAX_MIPS16_MARK_MACRO, RELAX_MIPS16_CLEAR_MACRO): Shift bits.
+       (mips16_immed_extend): New prototype.
+       (options): Add OPTION_MIPS16E2 and OPTION_NO_MIPS16E2 enum
+       values.
+       (md_longopts): Add "mmips16e2" and "mno-mips16e2" options.
+       (mips_ases): Add "mips16e2" entry.
+       (mips_set_ase): Handle MIPS16e2 ASE.
+       (insn_insert_operand): Explicitly handle immediates with MIPS16
+       instructions that require 32-bit encoding.
+       (is_opcode_valid_16): Pass enabled ASE bitmask on to
+       `opcode_is_member'.
+       (validate_mips_insn): Explicitly handle immediates with MIPS16
+       instructions that require 32-bit encoding.
+       (operand_reg_mask) <OP_REG28>: Add handler.
+       (match_reg28_operand): New function.
+       (match_operand) <OP_REG28>: Add handler.
+       (append_insn): Pass ASE_MIPS16E2 setting to RELAX_MIPS16_ENCODE.
+       (match_mips16_insn): Handle MIPS16 instructions that require
+       32-bit encoding and `V' and `u' operand codes.
+       (mips16_ip): Allow any characters except from `.' in opcodes.
+       (mips16_immed_extend): Handle 9-bit immediates.  Do not shuffle
+       immediates whose width is not one of these listed.
+       (md_estimate_size_before_relax): Handle MIPS16e2 relaxation.
+       (mips_relax_frag): Likewise.
+       (md_convert_frag): Likewise.
+       (mips_convert_ase_flags): Handle MIPS16e2 ASE.
+
+       * doc/as.texinfo (Target MIPS options): Add `-mmips16e2' and
+       `-mno-mips16e2' options.
+       (-mmips16e2, -mno-mips16e2): New options.
+       * doc/c-mips.texi (MIPS Options): Add `-mmips16e2' and
+       `-mno-mips16e2' options.
+       (MIPS ASE Instruction Generation Overrides): Add `.set mips16e2'
+       and `.set nomips16e2'.
+
 2017-05-15  Maciej W. Rozycki  <macro@imgtec.com>
 
        * config/tc-mips.c (match_int_operand): Call
index beb4d4673a859cb585e552e60f142c007921f656..7e927b23fa36bddd7d2c42569ba7c61e7610cbcb 100644 (file)
@@ -1130,38 +1130,40 @@ static bfd_boolean mips_ignore_branch_isa;
    store whether this is known to be a branch to a different section,
    whether we have tried to relax this frag yet, and whether we have
    ever extended a PC relative fragment because of a shift count.  */
-#define RELAX_MIPS16_ENCODE(type, pic, sym32, nomacro,         \
+#define RELAX_MIPS16_ENCODE(type, e2, pic, sym32, nomacro,     \
                            small, ext,                         \
                            dslot, jal_dslot)                   \
   (0x80000000                                                  \
    | ((type) & 0xff)                                           \
-   | ((pic) ? 0x100 : 0)                                       \
-   | ((sym32) ? 0x200 : 0)                                     \
-   | ((nomacro) ? 0x400 : 0)                                   \
-   | ((small) ? 0x800 : 0)                                     \
-   | ((ext) ? 0x1000 : 0)                                      \
-   | ((dslot) ? 0x2000 : 0)                                    \
-   | ((jal_dslot) ? 0x4000 : 0))
+   | ((e2) ? 0x100 : 0)                                                \
+   | ((pic) ? 0x200 : 0)                                       \
+   | ((sym32) ? 0x400 : 0)                                     \
+   | ((nomacro) ? 0x800 : 0)                                   \
+   | ((small) ? 0x1000 : 0)                                    \
+   | ((ext) ? 0x2000 : 0)                                      \
+   | ((dslot) ? 0x4000 : 0)                                    \
+   | ((jal_dslot) ? 0x8000 : 0))
 
 #define RELAX_MIPS16_P(i) (((i) & 0xc0000000) == 0x80000000)
 #define RELAX_MIPS16_TYPE(i) ((i) & 0xff)
-#define RELAX_MIPS16_PIC(i) (((i) & 0x100) != 0)
-#define RELAX_MIPS16_SYM32(i) (((i) & 0x200) != 0)
-#define RELAX_MIPS16_NOMACRO(i) (((i) & 0x400) != 0)
-#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x800) != 0)
-#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x1000) != 0)
-#define RELAX_MIPS16_DSLOT(i) (((i) & 0x2000) != 0)
-#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x4000) != 0)
-
-#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x8000) != 0)
-#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x8000)
-#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) & ~0x8000)
-#define RELAX_MIPS16_ALWAYS_EXTENDED(i) (((i) & 0x10000) != 0)
-#define RELAX_MIPS16_MARK_ALWAYS_EXTENDED(i) ((i) | 0x10000)
-#define RELAX_MIPS16_CLEAR_ALWAYS_EXTENDED(i) ((i) & ~0x10000)
-#define RELAX_MIPS16_MACRO(i) (((i) & 0x20000) != 0)
-#define RELAX_MIPS16_MARK_MACRO(i) ((i) | 0x20000)
-#define RELAX_MIPS16_CLEAR_MACRO(i) ((i) & ~0x20000)
+#define RELAX_MIPS16_E2(i) (((i) & 0x100) != 0)
+#define RELAX_MIPS16_PIC(i) (((i) & 0x200) != 0)
+#define RELAX_MIPS16_SYM32(i) (((i) & 0x400) != 0)
+#define RELAX_MIPS16_NOMACRO(i) (((i) & 0x800) != 0)
+#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x1000) != 0)
+#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x2000) != 0)
+#define RELAX_MIPS16_DSLOT(i) (((i) & 0x4000) != 0)
+#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x8000) != 0)
+
+#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x10000) != 0)
+#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x10000)
+#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) & ~0x10000)
+#define RELAX_MIPS16_ALWAYS_EXTENDED(i) (((i) & 0x20000) != 0)
+#define RELAX_MIPS16_MARK_ALWAYS_EXTENDED(i) ((i) | 0x20000)
+#define RELAX_MIPS16_CLEAR_ALWAYS_EXTENDED(i) ((i) & ~0x20000)
+#define RELAX_MIPS16_MACRO(i) (((i) & 0x40000) != 0)
+#define RELAX_MIPS16_MARK_MACRO(i) ((i) | 0x40000)
+#define RELAX_MIPS16_CLEAR_MACRO(i) ((i) & ~0x40000)
 
 /* For microMIPS code, we use relaxation similar to one we use for
    MIPS16 code.  Some instructions that take immediate values support
@@ -1341,6 +1343,7 @@ static void macro (struct mips_cl_insn *ip, char *str);
 static void mips16_macro (struct mips_cl_insn * ip);
 static void mips_ip (char *str, struct mips_cl_insn * ip);
 static void mips16_ip (char *str, struct mips_cl_insn * ip);
+static unsigned long mips16_immed_extend (offsetT, unsigned int);
 static void mips16_immed
   (const char *, unsigned int, int, bfd_reloc_code_real_type, offsetT,
    unsigned int, unsigned long *);
@@ -1455,6 +1458,8 @@ enum options
     OPTION_NO_MICROMIPS,
     OPTION_MCU,
     OPTION_NO_MCU,
+    OPTION_MIPS16E2,
+    OPTION_NO_MIPS16E2,
     OPTION_COMPAT_ARCH_BASE,
     OPTION_M4650,
     OPTION_NO_M4650,
@@ -1575,6 +1580,8 @@ struct option md_longopts[] =
   {"mno-msa", no_argument, NULL, OPTION_NO_MSA},
   {"mxpa", no_argument, NULL, OPTION_XPA},
   {"mno-xpa", no_argument, NULL, OPTION_NO_XPA},
+  {"mmips16e2", no_argument, NULL, OPTION_MIPS16E2},
+  {"mno-mips16e2", no_argument, NULL, OPTION_NO_MIPS16E2},
 
   /* Old-style architecture options.  Don't add more of these.  */
   {"m4650", no_argument, NULL, OPTION_M4650},
@@ -1757,6 +1764,11 @@ static const struct mips_ase mips_ases[] = {
     OPTION_XPA, OPTION_NO_XPA,
      2,  2, -1, -1,
     -1 },
+
+  { "mips16e2", ASE_MIPS16E2, 0,
+    OPTION_MIPS16E2, OPTION_NO_MIPS16E2,
+    2,  2, -1, -1,
+    6 },
 };
 
 /* The set of ASEs that require -mfp64.  */
@@ -2120,6 +2132,13 @@ mips_set_ase (const struct mips_ase *ase, struct mips_set_options *opts,
   opts->ase &= ~mask;
   if (enabled_p)
     opts->ase |= ase->flags;
+
+  if ((opts->ase & (ASE_MIPS16E2 | ASE_MT)) == (ASE_MIPS16E2 | ASE_MT))
+    {
+      opts->ase |= ASE_MIPS16E2_MT;
+      mask |= ASE_MIPS16E2_MT;
+    }
+
   return mask;
 }
 
@@ -2226,7 +2245,12 @@ static inline void
 insn_insert_operand (struct mips_cl_insn *insn,
                     const struct mips_operand *operand, unsigned int uval)
 {
-  insn->insn_opcode = mips_insert_operand (operand, insn->insn_opcode, uval);
+  if (mips_opts.mips16
+      && operand->type == OP_INT && operand->lsb == 0
+      && mips_opcode_32bit_p (insn->insn_mo))
+    insn->insn_opcode |= mips16_immed_extend (uval, operand->size);
+  else
+    insn->insn_opcode = mips_insert_operand (operand, insn->insn_opcode, uval);
 }
 
 /* Extract the value of OPERAND from INSN.  */
@@ -3286,7 +3310,16 @@ is_opcode_valid (const struct mips_opcode *mo)
 static bfd_boolean
 is_opcode_valid_16 (const struct mips_opcode *mo)
 {
-  return opcode_is_member (mo, mips_opts.isa, 0, mips_opts.arch);
+  int isa = mips_opts.isa;
+  int ase = mips_opts.ase;
+  unsigned int i;
+
+  if (ISA_HAS_64BIT_REGS (isa))
+    for (i = 0; i < ARRAY_SIZE (mips_ases); i++)
+      if ((ase & mips_ases[i].flags) == mips_ases[i].flags)
+       ase |= mips_ases[i].flags64;
+
+  return opcode_is_member (mo, isa, ase, mips_opts.arch);
 }
 
 /* Return TRUE if the size of the microMIPS opcode MO matches one
@@ -3417,7 +3450,11 @@ validate_mips_insn (const struct mips_opcode *opcode,
          }
        gas_assert (opno < MAX_OPERANDS);
        operands->operand[opno] = operand;
-       if (operand && operand->type != OP_VU0_MATCH_SUFFIX)
+       if (!decode_operand && operand
+           && operand->type == OP_INT && operand->lsb == 0
+           && mips_opcode_32bit_p (opcode))
+         used_bits |= mips16_immed_extend (-1, operand->size);
+       else if (operand && operand->type != OP_VU0_MATCH_SUFFIX)
          {
            used_bits = mips_insert_operand (operand, used_bits, -1);
            if (operand->type == OP_MDMX_IMM_REG)
@@ -4501,6 +4538,9 @@ operand_reg_mask (const struct mips_cl_insn *insn,
     case OP_IMM_INDEX:
       abort ();
 
+    case OP_REG28:
+      return 1 << 28;
+
     case OP_REG:
     case OP_OPTIONAL_REG:
       {
@@ -5795,6 +5835,23 @@ match_pc_operand (struct mips_arg_info *arg)
   return FALSE;
 }
 
+/* OP_REG28 matcher.  */
+
+static bfd_boolean
+match_reg28_operand (struct mips_arg_info *arg)
+{
+  unsigned int regno;
+
+  if (arg->token->type == OT_REG
+      && match_regno (arg, OP_REG_GP, arg->token->u.regno, &regno)
+      && regno == GP)
+    {
+      ++arg->token;
+      return TRUE;
+    }
+  return FALSE;
+}
+
 /* OP_NON_ZERO_REG matcher.  */
 
 static bfd_boolean
@@ -6079,6 +6136,9 @@ match_operand (struct mips_arg_info *arg,
     case OP_PC:
       return match_pc_operand (arg);
 
+    case OP_REG28:
+      return match_reg28_operand (arg);
+
     case OP_VU0_SUFFIX:
       return match_vu0_suffix_operand (arg, operand, FALSE);
 
@@ -7452,6 +7512,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
       add_relaxed_insn (ip, 12, 0,
                        RELAX_MIPS16_ENCODE
                        (*reloc_type - BFD_RELOC_UNUSED,
+                        mips_opts.ase & ASE_MIPS16E2,
                         mips_pic != NO_PIC,
                         HAVE_32BIT_SYMBOLS,
                         mips_opts.warn_about_macros,
@@ -8194,7 +8255,7 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
            {
              if (required_insn_length == 2)
                set_insn_error (0, _("invalid unextended operand value"));
-             else
+             else if (!mips_opcode_32bit_p (opcode))
                {
                  forced_insn_length = 4;
                  insn->insn_opcode |= MIPS16_EXTEND;
@@ -8228,6 +8289,8 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
        case 'A':
        case 'B':
        case 'E':
+       case 'V':
+       case 'u':
          relax_char = c;
          break;
 
@@ -13923,7 +13986,7 @@ mips16_ip (char *str, struct mips_cl_insn *insn)
   struct mips_operand_token *tokens;
   unsigned int l;
 
-  for (s = str; ISLOWER (*s); ++s)
+  for (s = str; *s != '\0' && *s != '.' && *s != ' '; ++s)
     ;
   end = s;
   c = *end;
@@ -13954,8 +14017,6 @@ mips16_ip (char *str, struct mips_cl_insn *insn)
        break;
       else if (*s++ == ' ')
        break;
-      /* Fall through.  */
-    default:
       set_insn_error (0, _("unrecognized opcode"));
       return;
     }
@@ -13988,7 +14049,10 @@ static unsigned long
 mips16_immed_extend (offsetT val, unsigned int nbits)
 {
   int extval;
-  if (nbits == 16)
+
+  extval = 0;
+  val &= (1U << nbits) - 1;
+  if (nbits == 16 || nbits == 9)
     {
       extval = ((val >> 11) & 0x1f) | (val & 0x7e0);
       val &= 0x1f;
@@ -13998,7 +14062,7 @@ mips16_immed_extend (offsetT val, unsigned int nbits)
       extval = ((val >> 11) & 0xf) | (val & 0x7f0);
       val &= 0xf;
     }
-  else
+  else if (nbits == 6)
     {
       extval = ((val & 0x1f) << 6) | (val & 0x20);
       val = 0;
@@ -17703,7 +17767,7 @@ md_estimate_size_before_relax (fragS *fragp, asection *segtype)
       /* We don't want to modify the EXTENDED bit here; it might get us
         into infinite loops.  We change it only in mips_relax_frag().  */
       if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
-       return 12;
+       return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 8 : 12;
       else
        return RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2;
     }
@@ -17961,7 +18025,7 @@ mips_relax_frag (asection *sec, fragS *fragp, long stretch)
       if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
        {
          fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype);
-         return -10;
+         return RELAX_MIPS16_E2 (fragp->fr_subtype) ? -6 : -10;
        }
       else if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
        {
@@ -17977,7 +18041,7 @@ mips_relax_frag (asection *sec, fragS *fragp, long stretch)
        {
          fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype);
          fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype);
-         return -8;
+         return RELAX_MIPS16_E2 (fragp->fr_subtype) ? -4 : -8;
        }
       else if (!RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
        {
@@ -17995,12 +18059,12 @@ mips_relax_frag (asection *sec, fragS *fragp, long stretch)
        {
          fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype);
          fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype);
-         return 8;
+         return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 4 : 8;
        }
       else
        {
          fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype);
-         return 10;
+         return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 6 : 10;
        }
     }
 
@@ -18575,10 +18639,13 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          unsigned long reg;
          unsigned long new;
          unsigned long op;
+         bfd_boolean e2;
 
          gas_assert (type == 'A' || type == 'B' || type == 'E');
          gas_assert (RELAX_MIPS16_SYM32 (fragp->fr_subtype));
 
+         e2 = RELAX_MIPS16_E2 (fragp->fr_subtype);
+
          if (need_reloc)
            {
              fixS *fixp;
@@ -18591,7 +18658,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              fixp->fx_file = fragp->fr_file;
              fixp->fx_line = fragp->fr_line;
 
-             fixp = fix_new (fragp, buf - fragp->fr_literal + 8, 4,
+             fixp = fix_new (fragp, buf - fragp->fr_literal + (e2 ? 4 : 8), 4,
                              fragp->fr_symbol, fragp->fr_offset,
                              FALSE, BFD_RELOC_MIPS16_LO16);
              fixp->fx_file = fragp->fr_file;
@@ -18628,15 +18695,18 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              abort ();
            }
 
-         new = 0xf0006800 | (reg << 8);                        /* LI */
+         new = (e2 ? 0xf0006820 : 0xf0006800) | (reg << 8);    /* LUI/LI */
          new |= mips16_immed_extend ((val + 0x8000) >> 16, 16);
          buf = write_compressed_insn (buf, new, 4);
-         new = 0xf4003000 | (reg << 8) | (reg << 5);           /* SLL */
-         buf = write_compressed_insn (buf, new, 4);
+         if (!e2)
+           {
+             new = 0xf4003000 | (reg << 8) | (reg << 5);       /* SLL */
+             buf = write_compressed_insn (buf, new, 4);
+           }
          op |= mips16_immed_extend (val, 16);
          buf = write_compressed_insn (buf, op, 4);
 
-         fragp->fr_fix += 12;
+         fragp->fr_fix += e2 ? 8 : 12;
        }
       else
        {
@@ -18866,6 +18936,8 @@ mips_convert_ase_flags (int ase)
     ext_ases |= AFL_ASE_MSA;
   if (ase & ASE_XPA)
     ext_ases |= AFL_ASE_XPA;
+  if (ase & ASE_MIPS16E2)
+    ext_ases |= file_ase_mips16 ? AFL_ASE_MIPS16E2 : 0;
 
   return ext_ases;
 }
index 27d0c689d275a71f980a649587213b5625a2785c..e0637c71491fc5b307a2a95d82fa7bdde5f11039 100644 (file)
@@ -420,6 +420,7 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}.
    [@b{-mnan=@var{encoding}}]
    [@b{-trap}] [@b{-no-break}] [@b{-break}] [@b{-no-trap}]
    [@b{-mips16}] [@b{-no-mips16}]
+   [@b{-mmips16e2}] [@b{-mno-mips16e2}]
    [@b{-mmicromips}] [@b{-mno-micromips}]
    [@b{-msmartmips}] [@b{-mno-smartmips}]
    [@b{-mips3d}] [@b{-no-mips3d}]
@@ -1455,6 +1456,12 @@ Generate code for the MIPS 16 processor.  This is equivalent to putting
 @code{.module mips16} at the start of the assembly file.  @samp{-no-mips16}
 turns off this option.
 
+@item -mmips16e2
+@itemx -mno-mips16e2
+Enable the use of MIPS16e2 instructions in MIPS16 mode.  This is equivalent
+to putting @code{.module mips16e2} at the start of the assembly file.
+@samp{-mno-mips16e2} turns off this option.
+
 @item -mmicromips
 @itemx -mno-micromips
 Generate code for the microMIPS processor.  This is equivalent to putting
index e5d00b26027f1fc47e1196d86b3d5a8db4818907..c2d9b7ae5b5d63fa2fe324f66b34a7fe5548780e 100644 (file)
@@ -151,6 +151,12 @@ Generate code for the MIPS 16 processor.  This is equivalent to putting
 @code{.module mips16} at the start of the assembly file.  @samp{-no-mips16}
 turns off this option.
 
+@item -mmips16e2
+@itemx -mno-mips16e2
+Enable the use of MIPS16e2 instructions in MIPS16 mode.  This is equivalent
+to putting @code{.module mips16e2} at the start of the assembly file.
+@samp{-mno-mips16e2} turns off this option.
+
 @item -mmicromips
 @itemx -mno-micromips
 Generate code for the microMIPS processor.  This is equivalent to putting
@@ -1094,6 +1100,16 @@ The directive @code{.set xpa} makes the assembler accept instructions
 from the XPA Extension from that point on in the assembly.  The 
 @code{.set noxpa} directive prevents XPA instructions from being accepted.
 
+@cindex MIPS16e2 instruction generation override
+@kindex @code{.set mips16e2}
+@kindex @code{.set nomips16e2}
+The directive @code{.set mips16e2} makes the assembler accept instructions
+from the MIPS16e2 Application Specific Extension from that point on in the
+assembly, whenever in MIPS16 mode.  The @code{.set nomips16e2} prevents
+MIPS16e2 instructions from being accepted, in MIPS16 mode.  Neither
+directive affects the state of MIPS16 mode being active itself which has
+separate controls.
+
 Traditional MIPS assemblers do not support these directives.
 
 @node MIPS Floating-Point
index 5641957a6bc1583afb29e32254adee22c3560da8..67bf02fbe76d99a118fabf1ef650e22a3be64c33 100644 (file)
@@ -1,3 +1,13 @@
+2017-05-15  Maciej W. Rozycki  <macro@imgtec.com>
+           Matthew Fortune  <matthew.fortune@imgtec.com>
+
+       * elf/mips.h (AFL_ASE_MIPS16E2): New macro.
+       (AFL_ASE_MASK): Adjust accordingly.
+       * opcode/mips.h: Document new operand codes defined.
+       (mips_operand_type): Add OP_REG28 enum value.
+       (INSN2_SHORT_ONLY): Update description.
+       (ASE_MIPS16E2, ASE_MIPS16E2_MT): New macros.
+
 2017-05-14  John David Anglin  <danglin@gcc.gnu.org>
 
        * opcode/hppa.h: Fix match and mask for 64-bit bb opcode.
index 3e27b05122c8a29d5e3ba1438e7924f0edd772d2..b8786364f12ffe63a8519c32366bf8199efad037 100644 (file)
@@ -1233,7 +1233,8 @@ extern void bfd_mips_elf_swap_abiflags_v0_out
 #define AFL_ASE_MICROMIPS    0x00000800 /* MICROMIPS ASE.  */
 #define AFL_ASE_XPA          0x00001000 /* XPA ASE.  */
 #define AFL_ASE_DSPR3        0x00002000 /* DSP R3 ASE.  */
-#define AFL_ASE_MASK         0x00003fff /* All ASEs.  */
+#define AFL_ASE_MIPS16E2     0x00004000 /* MIPS16e2 ASE.  */
+#define AFL_ASE_MASK         0x00007fff /* All ASEs.  */
 
 /* Values for the isa_ext word of an ABI flags structure.  */
 
index 0d043d9520d7b85eba55c4dd9cde798c517fc196..c71a33a1a3519f01521bb169df5ceaf20dafd7c0 100644 (file)
@@ -409,6 +409,9 @@ enum mips_operand_type {
   /* $pc, which has no encoding in the architectural instruction.  */
   OP_PC,
 
+  /* $28, which has no encoding in the MIPS16e architectural instruction.  */
+  OP_REG28,
+
   /* A 4-bit XYZW channel mask or 2-bit XYZW index; the size determines
      which.  */
   OP_VU0_SUFFIX,
@@ -1116,7 +1119,12 @@ mips_opcode_32bit_p (const struct mips_opcode *mo)
 #define INSN2_FORBIDDEN_SLOT        0x00008000
 /* Opcode table entry is for a short MIPS16 form only.  An extended
    encoding may still exist, but with a separate opcode table entry
-   required.  */
+   required.  In disassembly the presence of this flag in an otherwise
+   successful match against an extended instruction encoding inhibits
+   matching against any subsequent short table entry even if it does
+   not have this flag set.  A table entry matching the full extended
+   encoding is needed or otherwise the final EXTEND entry will apply,
+   for the disassembly of the prefix only.  */
 #define INSN2_SHORT_ONLY           0x00010000
 
 /* Masks used to mark instructions to indicate which MIPS ISA level
@@ -1274,6 +1282,10 @@ static const unsigned int mips_isa_table[] = {
 #define ASE_XPA                        0x00002000
 /* DSP R3 Module.  */
 #define ASE_DSPR3              0x00004000
+/* MIPS16e2 ASE.  */
+#define ASE_MIPS16E2           0x00008000
+/* MIPS16e2 MT ASE instructions.  */
+#define ASE_MIPS16E2_MT                0x00010000
 
 /* MIPS ISA defines, use instead of hardcoding ISA level.  */
 
@@ -1820,7 +1832,24 @@ extern int bfd_mips_num_opcodes;
    "e" 11 bit extension value
    "l" register list for entry instruction
    "L" register list for exit instruction
+   ">" 5-bit SYNC code
+   "9" 9-bit signed immediate
+   "G" global pointer ($gp or $28)
+   "N" 5-bit coprocessor register
+   "O" 3-bit sel field for MFC0/MTC0
+   "Q" 5-bit hardware register
+   "T" 5-bit CACHE opcode or PREF hint
+   "b" 5-bit INS/EXT position, which becomes LSB
+       Enforces: 0 <= pos < 32.
+   "c" 5-bit INS size, which becomes MSB
+       Requires that "b" occurs first to set position.
+       Enforces: 0 < (pos+size) <= 32.
+   "d" 5-bit EXT size, which becomes MSBD
+       Requires that "b" occurs first to set position.
+       Enforces: 0 < (pos+size) <= 32.
+   "r" 3-bit register
    "s" 3-bit ASMACRO select immediate
+   "u" 16-bit unsigned immediate
 
    "I" an immediate value used for macros
 
@@ -1850,10 +1879,10 @@ extern int bfd_mips_num_opcodes;
    "M" 7 bit register list for restore instruction (18 bit extended)
 
    Characters used so far, for quick reference when adding more:
-   "0123456 8 "
-   ".[]<"
-   "ABCDEF HI KLM  P RS UVWXYZ"
-   "a   e   ijklm  pq s  vwxyz"
+   "0123456 89"
+   ".[]<>"
+   "ABCDEFGHI KLMNOPQRSTUVWXYZ"
+   "abcde   ijklm  pqrs uvwxyz"
   */
 
 /* Save/restore encoding for the args field when all 4 registers are
index 4816a4e3c963814bd20bb5b288c50a8a668ff500..7c819d35ada15ca72528d973c30a6f24f383d6be 100644 (file)
@@ -1,3 +1,31 @@
+2017-05-15  Maciej W. Rozycki  <macro@imgtec.com>
+           Matthew Fortune  <matthew.fortune@imgtec.com>
+
+       * mips-dis.c (mips_arch_choices): Add ASE_MIPS16E2 and
+       ASE_MIPS16E2_MT flags to the unnamed MIPS16 entry.
+       (mips_convert_abiflags_ases): Handle the AFL_ASE_MIPS16E2 flag.
+       (print_insn_arg) <OP_REG28>: Add handler.
+       (validate_insn_args) <OP_REG28>: Handle.
+       (print_mips16_insn_arg): Handle MIPS16 instructions that require
+       32-bit encoding and 9-bit immediates.
+       (print_insn_mips16): Handle MIPS16 instructions that require
+       32-bit encoding and MFC0/MTC0 operand decoding.
+       * mips16-opc.c (decode_mips16_operand) <'>', '9', 'G', 'N', 'O'>
+       <'Q', 'T', 'b', 'c', 'd', 'r', 'u'>: Add handlers.
+       (RD_C0, WR_C0, E2, E2MT): New macros.
+       (mips16_opcodes): Add entries for MIPS16e2 instructions:
+       GP-relative "addiu" and its "addu" spelling, "andi", "cache",
+       "di", "ehb", "ei", "ext", "ins", GP-relative "lb", "lbu", "lh",
+       "lhu", and "lw" instructions, "ll", "lui", "lwl", "lwr", "mfc0",
+       "movn", "movtn", "movtz", "movz", "mtc0", "ori", "pause",
+       "pref", "rdhwr", "sc", GP-relative "sb", "sh" and "sw"
+       instructions, "swl", "swr", "sync" and its "sync_acquire",
+       "sync_mb", "sync_release", "sync_rmb" and "sync_wmb" aliases,
+       "xori", "dmt", "dvpe", "emt" and "evpe".  Add split
+       regular/extended entries for original MIPS16 ISA revision
+       instructions whose extended forms are subdecoded in the MIPS16e2
+       ISA revision: "li", "sll" and "srl".
+
 2017-05-15  Maciej W. Rozycki  <macro@imgtec.com>
 
        * mips-dis.c (print_insn_args) <default>: Remove an MT ASE
index ab92add7a46590fd4a867b5671d8bba16fbda581..8caae81edf56d5d347fa843fe0d27e78de183198 100644 (file)
@@ -658,7 +658,8 @@ const struct mips_arch_choice mips_arch_choices[] =
 
   /* This entry, mips16, is here only for ISA/processor selection; do
      not print its name.  */
-  { "",                1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS64, 0,
+  { "",                1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS64,
+    ASE_MIPS16E2 | ASE_MIPS16E2_MT,
     mips_cp0_names_numeric, NULL, 0, mips_cp1_names_numeric,
     mips_hwr_names_numeric },
 };
@@ -795,6 +796,11 @@ mips_convert_abiflags_ases (unsigned long afl_ases)
     opcode_ases |= ASE_XPA;
   if (afl_ases & AFL_ASE_DSPR3)
     opcode_ases |= ASE_DSPR3;
+  if (afl_ases & AFL_ASE_MIPS16E2)
+    opcode_ases |= ASE_MIPS16E2;
+  if ((afl_ases & (AFL_ASE_MIPS16E2 | AFL_ASE_MT))
+      == (AFL_ASE_MIPS16E2 | AFL_ASE_MT))
+    opcode_ases |= ASE_MIPS16E2_MT;
   return opcode_ases;
 }
 
@@ -1462,6 +1468,10 @@ print_insn_arg (struct disassemble_info *info,
       infprintf (is, "$pc");
       break;
 
+    case OP_REG28:
+      print_reg (info, opcode, OP_REG_GP, 28);
+      break;
+
     case OP_VU0_SUFFIX:
     case OP_VU0_MATCH_SUFFIX:
       print_vu0_channel (info, operand, uval);
@@ -1575,6 +1585,7 @@ validate_insn_args (const struct mips_opcode *opcode,
                case OP_REPEAT_PREV_REG:
                case OP_REPEAT_DEST_REG:
                case OP_PC:
+               case OP_REG28:
                case OP_VU0_SUFFIX:
                case OP_VU0_MATCH_SUFFIX:
                case OP_IMM_INDEX:
@@ -1933,7 +1944,9 @@ print_mips16_insn_arg (struct disassemble_info *info,
       if (use_extend)
        {
          ext_operand = decode_mips16_operand (type, TRUE);
-         if (ext_operand != operand)
+         if (ext_operand != operand
+             || (operand->type == OP_INT && operand->lsb == 0
+                 && mips_opcode_32bit_p (opcode)))
            {
              ext_size = ext_operand->size;
              operand = ext_operand;
@@ -1941,7 +1954,7 @@ print_mips16_insn_arg (struct disassemble_info *info,
        }
       if (operand->size == 26)
        uval = ((extend & 0x1f) << 21) | ((extend & 0x3e0) << 11) | insn;
-      else if (ext_size == 16)
+      else if (ext_size == 16 || ext_size == 9)
        uval = ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f);
       else if (ext_size == 15)
        uval = ((extend & 0xf) << 11) | (extend & 0x7f0) | (insn & 0xf);
@@ -1949,6 +1962,8 @@ print_mips16_insn_arg (struct disassemble_info *info,
        uval = ((extend >> 6) & 0x1f) | (extend & 0x20);
       else
        uval = mips_extract_operand (operand, (extend << 16) | insn);
+      if (ext_size == 9)
+       uval &= (1U << ext_size) - 1;
 
       baseaddr = memaddr + 2;
       if (operand->type == OP_PCREL)
@@ -2034,6 +2049,7 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
   struct mips_print_arg_state state;
   void *is = info->stream;
   bfd_boolean have_second;
+  bfd_boolean extend_only;
   unsigned int second;
   unsigned int first;
   unsigned int full;
@@ -2077,6 +2093,8 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
       return -1;
     }
 
+  extend_only = FALSE;
+
   if (info->endian == BFD_ENDIAN_BIG)
     first = bfd_getb16 (buffer);
   else
@@ -2128,9 +2146,17 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
        }
       else if ((first & 0xf800) == 0xf000
               && have_second
-              && !(op->pinfo2 & INSN2_SHORT_ONLY)
+              && !extend_only
               && (second & op->mask) == op->match)
-       match = MATCH_FULL;
+       {
+         if (op->pinfo2 & INSN2_SHORT_ONLY)
+           {
+             match = MATCH_NONE;
+             extend_only = TRUE;
+           }
+         else
+           match = MATCH_FULL;
+       }
       else
        match = MATCH_NONE;
 
@@ -2161,19 +2187,49 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
                  ++s;
                  continue;
                }
-             switch (match)
+             if (s[0] == 'N'
+                 && s[1] == ','
+                 && s[2] == 'O'
+                 && op->name[strlen (op->name) - 1] == '0')
                {
-                 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;
+                 /* Coprocessor register 0 with sel field.  */
+                 const struct mips_cp0sel_name *n;
+                 const struct mips_operand *operand;
+                 unsigned int reg, sel;
+
+                 operand = decode_mips16_operand (*s, TRUE);
+                 reg = mips_extract_operand (operand, (first << 16) | second);
+                 s += 2;
+                 operand = decode_mips16_operand (*s, TRUE);
+                 sel = mips_extract_operand (operand, (first << 16) | second);
+
+                 /* CP0 register including 'sel' code for mftc0, to be
+                    printed textually if known.  If not known, print both
+                    CP0 register name and sel numerically since CP0 register
+                    with sel 0 may have a name unrelated to register being
+                    printed.  */
+                 n = lookup_mips_cp0sel_name (mips_cp0sel_names,
+                                              mips_cp0sel_names_len,
+                                              reg, sel);
+                 if (n != NULL)
+                   infprintf (is, "%s", n->name);
+                 else
+                   infprintf (is, "$%d,%d", reg, sel);
                }
+             else
+               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.  */
index 29e9d9d312eca88b9496d86a9bfdbc87fac30953..83663adc838a1ba579fadfdcd0d54c4eb8576956 100644 (file)
@@ -50,6 +50,7 @@ decode_mips16_operand (char type, bfd_boolean extended_p)
   switch (type)
     {
     case '.': MAPPED_REG (0, 0, GP, reg_0_map);
+    case '>': HINT (5, 22);
 
     case '0': HINT (5, 0);
     case '1': HINT (3, 5);
@@ -57,22 +58,33 @@ decode_mips16_operand (char type, bfd_boolean extended_p)
     case '3': HINT (5, 16);
     case '4': HINT (3, 21);
     case '6': HINT (6, 5);
+    case '9': SINT (9, 0);
 
+    case 'G': SPECIAL (0, 0, REG28);
     case 'L': SPECIAL (6, 5, ENTRY_EXIT_LIST);
     case 'M': SPECIAL (7, 0, SAVE_RESTORE_LIST);
+    case 'N': REG (5, 0, COPRO);
+    case 'O': UINT (3, 21);
+    case 'Q': REG (5, 16, HW);
     case 'P': SPECIAL (0, 0, PC);
     case 'R': MAPPED_REG (0, 0, GP, reg_31_map);
     case 'S': MAPPED_REG (0, 0, GP, reg_29_map);
+    case 'T': HINT (5, 16);
     case 'X': REG (5, 0, GP);
     case 'Y': MAPPED_REG (5, 3, GP, reg32r_map);
     case 'Z': MAPPED_REG (3, 0, GP, reg_m16_map);
 
     case 'a': JUMP (26, 0, 2);
+    case 'b': BIT (5, 22, 0);                  /* (0 .. 31) */
+    case 'c': MSB (5, 16, 1, TRUE, 32);                /* (1 .. 32) */
+    case 'd': MSB (5, 16, 1, FALSE, 32);       /* (1 .. 32) */
     case 'e': HINT (11, 0);
     case 'i': JALX (26, 0, 2);
     case 'l': SPECIAL (6, 5, ENTRY_EXIT_LIST);
     case 'm': SPECIAL (7, 0, SAVE_RESTORE_LIST);
+    case 'r': MAPPED_REG (3, 16, GP, reg_m16_map);
     case 's': HINT (3, 24);
+    case 'u': HINT (16, 0);
     case 'v': OPTIONAL_MAPPED_REG (3, 8, GP, reg_m16_map);
     case 'w': OPTIONAL_MAPPED_REG (3, 5, GP, reg_m16_map);
     case 'x': MAPPED_REG (3, 8, GP, reg_m16_map);
@@ -162,6 +174,9 @@ decode_mips16_operand (char type, bfd_boolean extended_p)
 #define WR_T   INSN_WRITE_GPR_24
 #define WR_31  INSN_WRITE_GPR_31
 
+#define RD_C0  INSN_COP
+#define WR_C0  INSN_COP
+
 #define WR_HI  INSN_WRITE_HI
 #define WR_LO  INSN_WRITE_LO
 #define RD_HI  INSN_READ_HI
@@ -187,6 +202,9 @@ decode_mips16_operand (char type, bfd_boolean extended_p)
 #define I64    INSN_ISA64
 #define T3     INSN_3900
 
+#define E2     ASE_MIPS16E2
+#define E2MT   ASE_MIPS16E2_MT
+
 const struct mips_opcode mips16_opcodes[] =
 {
 /* name,    args,      match,  mask,           pinfo,                  pinfo2, membership,     ase,    exclusions */
@@ -198,15 +216,22 @@ const struct mips_opcode mips16_opcodes[] =
 {"addiu",   "S,K",     0x6300, 0xff00,         0,                      MOD_SP,         I1,     0,      0 },
 {"addiu",   "S,S,K",   0x6300, 0xff00,         0,                      MOD_SP,         I1,     0,      0 },
 {"addiu",   "x,P,V",   0x0800, 0xf800,         WR_1,                   RD_PC,          I1,     0,      0 },
+{"addiu",   "x,S,V",   0x0000, 0xf800,         WR_1,                   SH|RD_SP,       0,      E2,     0 },
 {"addiu",   "x,S,V",   0x0000, 0xf800,         WR_1,                   RD_SP,          I1,     0,      0 },
+{"addiu",   "x,S,V",   0xf0000000, 0xf800f8e0, WR_1,                   RD_SP,          0,      E2,     0 },
+{"addiu",   "x,G,V",   0xf0000020, 0xf800f8e0, WR_1|RD_2,              0,              0,      E2,     0 },
 {"addu",    "z,v,y",   0xe001, 0xf803,         WR_1|RD_2|RD_3,         SH,             I1,     0,      0 },
 {"addu",    "y,x,F",   0x4000, 0xf810,         WR_1|RD_2,              0,              I1,     0,      0 },
 {"addu",    "x,k",     0x4800, 0xf800,         MOD_1,                  0,              I1,     0,      0 },
 {"addu",    "S,K",     0x6300, 0xff00,         0,                      MOD_SP,         I1,     0,      0 },
 {"addu",    "S,S,K",   0x6300, 0xff00,         0,                      MOD_SP,         I1,     0,      0 },
 {"addu",    "x,P,V",   0x0800, 0xf800,         WR_1,                   RD_PC,          I1,     0,      0 },
+{"addu",    "x,S,V",   0x0000, 0xf800,         WR_1,                   SH|RD_SP,       0,      E2,     0 },
 {"addu",    "x,S,V",   0x0000, 0xf800,         WR_1,                   RD_SP,          I1,     0,      0 },
+{"addu",    "x,S,V",   0xf0000000, 0xf800f8e0, WR_1,                   RD_SP,          0,      E2,     0 },
+{"addu",    "x,G,V",   0xf0000020, 0xf800f8e0, WR_1|RD_2,              0,              0,      E2,     0 },
 {"and",            "x,y",      0xe80c, 0xf81f,         MOD_1|RD_2,             SH,             I1,     0,      0 },
+{"andi",    "x,u",     0xf0006860, 0xf800f8e0, WR_1,                   0,              0,      E2,     0 },
 {"b",      "q",        0x1000, 0xf800,         0,                      UBR,            I1,     0,      0 },
 {"beq",            "x,y,p",    0, (int) M_BEQ,         INSN_MACRO,             0,              I1,     0,      0 },
 {"beq",     "x,I,p",   0, (int) M_BEQ_I,       INSN_MACRO,             0,              I1,     0,      0 },
@@ -234,6 +259,7 @@ const struct mips_opcode mips16_opcodes[] =
 {"break",   "6",       0xe805, 0xf81f,         TRAP,                   SH,             I1,     0,      0 },
 {"bteqz",   "p",       0x6000, 0xff00,         RD_T,                   CBR,            I1,     0,      0 },
 {"btnez",   "p",       0x6100, 0xff00,         RD_T,                   CBR,            I1,     0,      0 },
+{"cache",   "T,9(x)",  0xf000d0a0, 0xfe00f8e0, RD_3,                   0,              0,      E2,     0 },
 {"cmpi",    "x,U",     0x7000, 0xf800,         RD_1|WR_T,              0,              I1,     0,      0 },
 {"cmp",            "x,y",      0xe80a, 0xf81f,         RD_1|RD_2|WR_T,         SH,             I1,     0,      0 },
 {"cmp",     "x,U",     0x7000, 0xf800,         RD_1|WR_T,              0,              I1,     0,      0 },
@@ -255,6 +281,9 @@ const struct mips_opcode mips16_opcodes[] =
 {"ddiv",    "z,v,y",   0, (int) M_DDIV_3,      INSN_MACRO,             0,              I3,     0,      0 },
 {"ddivu",   ".,x,y",   0xe81f, 0xf81f,         RD_2|RD_3|WR_HI|WR_LO,  SH,             I3,     0,      0 },
 {"ddivu",   "z,v,y",   0, (int) M_DDIVU_3,     INSN_MACRO,             0,              I3,     0,      0 },
+{"di",     "",         0xf006670c, 0xffffffff, WR_C0,                  0,              0,      E2,     0 },
+{"di",     ".",        0xf006670c, 0xffffffff, WR_C0,                  0,              0,      E2,     0 },
+{"di",     "y",        0xf002670c, 0xffffff1f, WR_1|WR_C0,             0,              0,      E2,     0 },
 {"div",            ".,x,y",    0xe81a, 0xf81f,         RD_2|RD_3|WR_HI|WR_LO,  SH,             I1,     0,      0 },
 {"div",     "z,v,y",   0, (int) M_DIV_3,       INSN_MACRO,             0,              I1,     0,      0 },
 {"divu",    ".,x,y",   0xe81b, 0xf81f,         RD_2|RD_3|WR_HI|WR_LO,  SH,             I1,     0,      0 },
@@ -278,12 +307,19 @@ const struct mips_opcode mips16_opcodes[] =
 {"dsubu",   "z,v,y",   0xe002, 0xf803,         WR_1|RD_2|RD_3,         SH,             I3,     0,      0 },
 {"dsubu",   "y,x,I",   0, (int) M_DSUBU_I,     INSN_MACRO,             0,              I3,     0,      0 },
 {"dsubu",   "y,I",     0, (int) M_DSUBU_I_2,   INSN_MACRO,             0,              I3,     0,      0 },
+{"ehb",            "",         0xf0c03010, 0xffffffff, 0,                      0,              0,      E2,     0 },
+{"ei",     "",         0xf007670c, 0xffffffff, WR_C0,                  0,              0,      E2,     0 },
+{"ei",     ".",        0xf007670c, 0xffffffff, WR_C0,                  0,              0,      E2,     0 },
+{"ei",     "y",        0xf003670c, 0xffffff1f, WR_1|WR_C0,             0,              0,      E2,     0 },
 {"exit",    "L",       0xed09, 0xff1f,         TRAP,                   SH,             I1,     0,      0 },
 {"exit",    "L",       0xee09, 0xff1f,         TRAP,                   SH,             I1,     0,      0 },
 {"exit",    "",                0xef09, 0xffff,         TRAP,                   SH,             I1,     0,      0 },
 {"exit",    "L",       0xef09, 0xff1f,         TRAP,                   SH,             I1,     0,      0 },
 {"entry",   "",                0xe809, 0xffff,         TRAP,                   SH,             I1,     0,      0 },
 {"entry",   "l",       0xe809, 0xf81f,         TRAP,                   SH,             I1,     0,      0 },
+{"ext",            "y,x,b,d",  0xf0203008, 0xf820f81f, WR_1|RD_2,              0,              0,      E2,     0 },
+{"ins",            "y,.,b,c",  0xf0003004, 0xf820ff1f, WR_1,                   0,              0,      E2,     0 },
+{"ins",            "y,x,b,c",  0xf0203004, 0xf820f81f, WR_1|RD_2,              0,              0,      E2,     0 },
 {"jalr",    "x",       0xe840, 0xf8ff,         RD_1|WR_31|UBD,         SH,             I1,     0,      0 },
 {"jalr",    "R,x",     0xe840, 0xf8ff,         RD_2|WR_31|UBD,         SH,             I1,     0,      0 },
 {"jal",            "x",        0xe840, 0xf8ff,         RD_1|WR_31|UBD,         SH,             I1,     0,      0 },
@@ -302,40 +338,74 @@ const struct mips_opcode mips16_opcodes[] =
 {"jrc",            "x",        0xe880, 0xf8ff,         RD_1|NODS,              SH|UBR,         I32,    0,      0 },
 {"jrc",            "R",        0xe8a0, 0xffff,         NODS,                   SH|RD_31|UBR,   I32,    0,      0 },
 {"lb",     "y,5(x)",   0x8000, 0xf800,         WR_1|RD_3,              0,              I1,     0,      0 },
+{"lb",     "x,V(G)",   0xf0009060, 0xf800f8e0, WR_1|RD_3,              0,              0,      E2,     0 },
 {"lbu",            "y,5(x)",   0xa000, 0xf800,         WR_1|RD_3,              0,              I1,     0,      0 },
+{"lbu",            "x,V(G)",   0xf00090a0, 0xf800f8e0, WR_1|RD_3,              0,              0,      E2,     0 },
 {"ld",     "y,D(x)",   0x3800, 0xf800,         WR_1|RD_3,              0,              I3,     0,      0 },
 {"ld",     "y,B",      0xfc00, 0xff00,         WR_1,                   RD_PC|AL,       I3,     0,      0 },
 {"ld",     "y,D(P)",   0xfc00, 0xff00,         WR_1,                   RD_PC,          I3,     0,      0 },
 {"ld",     "y,D(S)",   0xf800, 0xff00,         WR_1,                   RD_SP,          I3,     0,      0 },
 {"lh",     "y,H(x)",   0x8800, 0xf800,         WR_1|RD_3,              0,              I1,     0,      0 },
+{"lh",     "x,V(G)",   0xf0009040, 0xf800f8e0, WR_1|RD_3,              0,              0,      E2,     0 },
 {"lhu",            "y,H(x)",   0xa800, 0xf800,         WR_1|RD_3,              0,              I1,     0,      0 },
+{"lhu",            "x,V(G)",   0xf0009080, 0xf800f8e0, WR_1|RD_3,              0,              0,      E2,     0 },
+{"li",     "x,U",      0x6800, 0xf800,         WR_1,                   SH,             0,      E2,     0 },
 {"li",     "x,U",      0x6800, 0xf800,         WR_1,                   0,              I1,     0,      0 },
+{"li",     "x,U",      0xf0006800, 0xf800f8e0, WR_1,                   0,              0,      E2,     0 },
+{"ll",     "x,9(r)",   0xf00090c0, 0xfe18f8e0, WR_1|RD_3,              0,              0,      E2,     0 },
+{"lui",            "x,u",      0xf0006820, 0xf800f8e0, WR_1,                   0,              0,      E2,     0 },
 {"lw",     "y,W(x)",   0x9800, 0xf800,         WR_1|RD_3,              0,              I1,     0,      0 },
 {"lw",     "x,A",      0xb000, 0xf800,         WR_1,                   RD_PC|AL,       I1,     0,      0 },
 {"lw",     "x,V(P)",   0xb000, 0xf800,         WR_1,                   RD_PC,          I1,     0,      0 },
+{"lw",     "x,V(S)",   0x9000, 0xf800,         WR_1,                   SH|RD_SP,       0,      E2,     0 },
 {"lw",     "x,V(S)",   0x9000, 0xf800,         WR_1,                   RD_SP,          I1,     0,      0 },
+{"lw",     "x,V(S)",   0xf0009000, 0xf800f8e0, WR_1,                   RD_SP,          0,      E2,     0 },
+{"lw",     "x,V(G)",   0xf0009020, 0xf800f8e0, WR_1|RD_3,              0,              0,      E2,     0 },
+{"lwl",            "x,9(r)",   0xf00090e0, 0xfe18f8e0, WR_1|RD_3,              0,              0,      E2,     0 },
+{"lwr",            "x,9(r)",   0xf01090e0, 0xfe18f8e0, WR_1|RD_3,              0,              0,      E2,     0 },
 {"lwu",     "y,W(x)",  0xb800, 0xf800,         WR_1|RD_3,              0,              I3,     0,      0 },
+{"mfc0",    "y,N",     0xf0006700, 0xffffff00, WR_1|RD_C0,             0,              0,      E2,     0 },
+{"mfc0",    "y,N,O",   0xf0006700, 0xff1fff00, WR_1|RD_C0,             0,              0,      E2,     0 },
 {"mfhi",    "x",       0xe810, 0xf8ff,         WR_1|RD_HI,             SH,             I1,     0,      0 },
 {"mflo",    "x",       0xe812, 0xf8ff,         WR_1|RD_LO,             SH,             I1,     0,      0 },
 {"move",    "y,X",     0x6700, 0xff00,         WR_1|RD_2,              SH,             I1,     0,      0 },
 {"move",    "Y,Z",     0x6500, 0xff00,         WR_1|RD_2,              SH,             I1,     0,      0 },
+{"movn",    "x,.,w",   0xf000300a, 0xfffff81f, WR_1|RD_2|RD_3,         0,              0,      E2,     0 },
+{"movn",    "x,r,w",   0xf020300a, 0xfff8f81f, WR_1|RD_2|RD_3,         0,              0,      E2,     0 },
+{"movtn",   "x,.",     0xf000301a, 0xfffff8ff, WR_1|RD_2|RD_T,         0,              0,      E2,     0 },
+{"movtn",   "x,r",     0xf020301a, 0xfff8f8ff, WR_1|RD_2|RD_T,         0,              0,      E2,     0 },
+{"movtz",   "x,.",     0xf0003016, 0xfffff8ff, WR_1|RD_2|RD_T,         0,              0,      E2,     0 },
+{"movtz",   "x,r",     0xf0203016, 0xfff8f8ff, WR_1|RD_2|RD_T,         0,              0,      E2,     0 },
+{"movz",    "x,.,w",   0xf0003006, 0xfffff81f, WR_1|RD_2|RD_3,         0,              0,      E2,     0 },
+{"movz",    "x,r,w",   0xf0203006, 0xfff8f81f, WR_1|RD_2|RD_3,         0,              0,      E2,     0 },
+{"mtc0",    "y,N",     0xf0016700, 0xffffff00, RD_1|WR_C0,             0,              0,      E2,     0 },
+{"mtc0",    "y,N,O",   0xf0016700, 0xff1fff00, RD_1|WR_C0,             0,              0,      E2,     0 },
 {"mul",     "z,v,y",   0, (int) M_MUL,         INSN_MACRO,             0,              I1,     0,      0 },
 {"mult",    "x,y",     0xe818, 0xf81f,         RD_1|RD_2|WR_HI|WR_LO,  SH,             I1,     0,      0 },
 {"multu",   "x,y",     0xe819, 0xf81f,         RD_1|RD_2|WR_HI|WR_LO,  SH,             I1,     0,      0 },
 {"neg",            "x,w",      0xe80b, 0xf81f,         WR_1|RD_2,              SH,             I1,     0,      0 },
 {"not",            "x,w",      0xe80f, 0xf81f,         WR_1|RD_2,              SH,             I1,     0,      0 },
 {"or",     "x,y",      0xe80d, 0xf81f,         MOD_1|RD_2,             SH,             I1,     0,      0 },
+{"ori",            "x,u",      0xf0006840, 0xf800f8e0, WR_1,                   0,              0,      E2,     0 },
+{"pause",   "",                0xf1403018, 0xffffffff, 0,                      0,              0,      E2,     0 },
+{"pref",    "T,9(x)",  0xf000d080, 0xfe00f8e0, RD_3,                   0,              0,      E2,     0 },
+{"rdhwr",   "y,Q",     0xf000300c, 0xffe0ff1f, WR_1,                   0,              0,      E2,     0 },
 {"rem",            ".,x,y",    0xe81a, 0xf81f,         RD_2|RD_3|WR_HI|WR_LO,  SH,             I1,     0,      0 },
 {"rem",     "z,v,y",   0, (int) M_REM_3,       INSN_MACRO,             0,              I1,     0,      0 },
 {"remu",    ".,x,y",   0xe81b, 0xf81f,         RD_2|RD_3|WR_HI|WR_LO,  SH,             I1,     0,      0 },
 {"remu",    "z,v,y",   0, (int) M_REMU_3,      INSN_MACRO,             0,              I1,     0,      0 },
 {"sb",     "y,5(x)",   0xc000, 0xf800,         RD_1|RD_3,              0,              I1,     0,      0 },
+{"sb",     "x,V(G)",   0xf000d060, 0xf800f8e0, RD_1|RD_3,              0,              0,      E2,     0 },
+{"sc",     "x,9(r)",   0xf000d0c0, 0xfe18f8e0, RD_1|RD_3,              0,              0,      E2,     0 },
 {"sd",     "y,D(x)",   0x7800, 0xf800,         RD_1|RD_3,              0,              I3,     0,      0 },
 {"sd",     "y,D(S)",   0xf900, 0xff00,         RD_1,                   RD_SP,          I3,     0,      0 },
 {"sd",     "R,C(S)",   0xfa00, 0xff00,         0,                      RD_31|RD_SP,    I3,     0,      0 },
 {"sh",     "y,H(x)",   0xc800, 0xf800,         RD_1|RD_3,              0,              I1,     0,      0 },
+{"sh",     "x,V(G)",   0xf000d040, 0xf800f8e0, RD_1|RD_3,              0,              0,      E2,     0 },
 {"sllv",    "y,x",     0xe804, 0xf81f,         MOD_1|RD_2,             SH,             I1,     0,      0 },
+{"sll",            "x,w,<",    0x3000, 0xf803,         WR_1|RD_2,              SH,             0,      E2,     0 },
 {"sll",            "x,w,<",    0x3000, 0xf803,         WR_1|RD_2,              0,              I1,     0,      0 },
+{"sll",            "x,w,<",    0xf0003000, 0xf83ff81f, WR_1|RD_2,              0,              0,      E2,     0 },
 {"sll",            "y,x",      0xe804, 0xf81f,         MOD_1|RD_2,             SH,             I1,     0,      0 },
 {"slti",    "x,8",     0x5000, 0xf800,         RD_1|WR_T,              0,              I1,     0,      0 },
 {"slt",            "x,y",      0xe802, 0xf81f,         RD_1|RD_2|WR_T,         SH,             I1,     0,      0 },
@@ -347,15 +417,30 @@ const struct mips_opcode mips16_opcodes[] =
 {"sra",            "x,w,<",    0x3003, 0xf803,         WR_1|RD_2,              0,              I1,     0,      0 },
 {"sra",            "y,x",      0xe807, 0xf81f,         MOD_1|RD_2,             SH,             I1,     0,      0 },
 {"srlv",    "y,x",     0xe806, 0xf81f,         MOD_1|RD_2,             SH,             I1,     0,      0 },
+{"srl",            "x,w,<",    0x3002, 0xf803,         WR_1|RD_2,              SH,             0,      E2,     0 },
 {"srl",            "x,w,<",    0x3002, 0xf803,         WR_1|RD_2,              0,              I1,     0,      0 },
+{"srl",            "x,w,<",    0xf0003002, 0xf83ff81f, WR_1|RD_2,              0,              0,      E2,     0 },
 {"srl",            "y,x",      0xe806, 0xf81f,         MOD_1|RD_2,             SH,             I1,     0,      0 },
 {"subu",    "z,v,y",   0xe003, 0xf803,         WR_1|RD_2|RD_3,         SH,             I1,     0,      0 },
 {"subu",    "y,x,I",   0, (int) M_SUBU_I,      INSN_MACRO,             0,              I1,     0,      0 },
 {"subu",    "x,I",     0, (int) M_SUBU_I_2,    INSN_MACRO,             0,              I1,     0,      0 },
 {"sw",     "y,W(x)",   0xd800, 0xf800,         RD_1|RD_3,              0,              I1,     0,      0 },
+{"sw",     "x,V(S)",   0xd000, 0xf800,         RD_1,                   SH|RD_SP,       0,      E2,     0 },
 {"sw",     "x,V(S)",   0xd000, 0xf800,         RD_1,                   RD_SP,          I1,     0,      0 },
+{"sw",     "x,V(S)",   0xf000d000, 0xf800f8e0, RD_1,                   RD_SP,          0,      E2,     0 },
 {"sw",     "R,V(S)",   0x6200, 0xff00,         0,                      RD_31|RD_SP,    I1,     0,      0 },
+{"sw",     "x,V(G)",   0xf000d020, 0xf800f8e0, RD_1|RD_3,              0,              0,      E2,     0 },
+{"swl",            "x,9(r)",   0xf000d0e0, 0xfe18f8e0, RD_1|RD_3,              0,              0,      E2,     0 },
+{"swr",            "x,9(r)",   0xf010d0e0, 0xfe18f8e0, RD_1|RD_3,              0,              0,      E2,     0 },
+{"sync_acquire", "",   0xf4403014, 0xffffffff, 0,                      AL,             0,      E2,     0 },
+{"sync_mb", "",                0xf4003014, 0xffffffff, 0,                      AL,             0,      E2,     0 },
+{"sync_release", "",   0xf4803014, 0xffffffff, 0,                      AL,             0,      E2,     0 },
+{"sync_rmb", "",       0xf4c03014, 0xffffffff, 0,                      AL,             0,      E2,     0 },
+{"sync_wmb", "",       0xf1003014, 0xffffffff, 0,                      AL,             0,      E2,     0 },
+{"sync",    "",                0xf0003014, 0xffffffff, 0,                      0,              0,      E2,     0 },
+{"sync",    ">",       0xf0003014, 0xf83fffff, 0,                      0,              0,      E2,     0 },
 {"xor",            "x,y",      0xe80e, 0xf81f,         MOD_1|RD_2,             SH,             I1,     0,      0 },
+{"xori",    "x,u",     0xf0006880, 0xf800f8e0, WR_1,                   0,              0,      E2,     0 },
   /* MIPS16e additions; see above for compact jumps.  */
 {"restore", "M",       0x6400, 0xff80,         WR_31|NODS,             MOD_SP,         I32,    0,      0 },
 {"save",    "m",       0x6480, 0xff80,         NODS,                   RD_31|MOD_SP,   I32,    0,      0 },
@@ -367,6 +452,19 @@ const struct mips_opcode mips16_opcodes[] =
 {"zeb",            "x",        0xe811, 0xf8ff,         MOD_1,                  SH,             I32,    0,      0 },
 {"zeh",            "x",        0xe831, 0xf8ff,         MOD_1,                  SH,             I32,    0,      0 },
 {"zew",            "x",        0xe851, 0xf8ff,         MOD_1,                  SH,             I64,    0,      0 },
+  /* MIPS16e2 MT ASE instructions.  */
+{"dmt",            "",         0xf0266701, 0xffffffff, WR_C0,                  0,              0,      E2MT,   0 },
+{"dmt",            ".",        0xf0266701, 0xffffffff, WR_C0,                  0,              0,      E2MT,   0 },
+{"dmt",            "y",        0xf0226701, 0xffffff1f, WR_1|WR_C0,             0,              0,      E2MT,   0 },
+{"dvpe",    "",                0xf0266700, 0xffffffff, WR_C0,                  0,              0,      E2MT,   0 },
+{"dvpe",    ".",       0xf0266700, 0xffffffff, WR_C0,                  0,              0,      E2MT,   0 },
+{"dvpe",    "y",       0xf0226700, 0xffffff1f, WR_1|WR_C0,             0,              0,      E2MT,   0 },
+{"emt",            "",         0xf0276701, 0xffffffff, WR_C0,                  0,              0,      E2MT,   0 },
+{"emt",            ".",        0xf0276701, 0xffffffff, WR_C0,                  0,              0,      E2MT,   0 },
+{"emt",            "y",        0xf0236701, 0xffffff1f, WR_1|WR_C0,             0,              0,      E2MT,   0 },
+{"evpe",    "",                0xf0276700, 0xffffffff, WR_C0,                  0,              0,      E2MT,   0 },
+{"evpe",    ".",       0xf0276700, 0xffffffff, WR_C0,                  0,              0,      E2MT,   0 },
+{"evpe",    "y",       0xf0236700, 0xffffff1f, WR_1|WR_C0,             0,              0,      E2MT,   0 },
   /* Place asmacro at the bottom so that it catches any implementation
      specific macros that didn't match anything.  */
 {"asmacro", "s,0,1,2,3,4", 0xf000e000, 0xf800f800, 0,                  0,              I32,    0,      0 },