aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog4
-rw-r--r--bfd/elfxx-mips.c2
-rw-r--r--binutils/ChangeLog5
-rw-r--r--binutils/NEWS2
-rw-r--r--binutils/readelf.c2
-rw-r--r--gas/ChangeLog48
-rw-r--r--gas/config/tc-mips.c160
-rw-r--r--gas/doc/as.texinfo7
-rw-r--r--gas/doc/c-mips.texi16
-rw-r--r--include/ChangeLog10
-rw-r--r--include/elf/mips.h3
-rw-r--r--include/opcode/mips.h39
-rw-r--r--opcodes/ChangeLog28
-rw-r--r--opcodes/mips-dis.c88
-rw-r--r--opcodes/mips16-opc.c98
15 files changed, 446 insertions, 66 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index bd7356c..52c192d 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index 70c7f1c..61e1adb 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -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)
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 5e51572..8a977d1 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -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
diff --git a/binutils/NEWS b/binutils/NEWS
index c03539d..1bbd19f 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -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.
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 16eb866..7ff29bc 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -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)
diff --git a/gas/ChangeLog b/gas/ChangeLog
index c9ed98b..00b4742 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,4 +1,52 @@
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
`match_out_of_range' before returning failure for 0x8000-0xffff
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index beb4d46..7e927b2 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -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;
}
diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo
index 27d0c68..e0637c7 100644
--- a/gas/doc/as.texinfo
+++ b/gas/doc/as.texinfo
@@ -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
diff --git a/gas/doc/c-mips.texi b/gas/doc/c-mips.texi
index e5d00b2..c2d9b7a 100644
--- a/gas/doc/c-mips.texi
+++ b/gas/doc/c-mips.texi
@@ -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
diff --git a/include/ChangeLog b/include/ChangeLog
index 5641957..67bf02f 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -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.
diff --git a/include/elf/mips.h b/include/elf/mips.h
index 3e27b05..b878636 100644
--- a/include/elf/mips.h
+++ b/include/elf/mips.h
@@ -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. */
diff --git a/include/opcode/mips.h b/include/opcode/mips.h
index 0d043d9..c71a33a 100644
--- a/include/opcode/mips.h
+++ b/include/opcode/mips.h
@@ -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
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 4816a4e..7c819d3 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,4 +1,32 @@
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
reference in CP0 move operand decoding.
diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c
index ab92add..8caae81 100644
--- a/opcodes/mips-dis.c
+++ b/opcodes/mips-dis.c
@@ -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. */
diff --git a/opcodes/mips16-opc.c b/opcodes/mips16-opc.c
index 29e9d9d..83663ad 100644
--- a/opcodes/mips16-opc.c
+++ b/opcodes/mips16-opc.c
@@ -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 },