diff options
-rw-r--r-- | bfd/ChangeLog | 4 | ||||
-rw-r--r-- | bfd/elfxx-mips.c | 2 | ||||
-rw-r--r-- | binutils/ChangeLog | 5 | ||||
-rw-r--r-- | binutils/NEWS | 2 | ||||
-rw-r--r-- | binutils/readelf.c | 2 | ||||
-rw-r--r-- | gas/ChangeLog | 48 | ||||
-rw-r--r-- | gas/config/tc-mips.c | 160 | ||||
-rw-r--r-- | gas/doc/as.texinfo | 7 | ||||
-rw-r--r-- | gas/doc/c-mips.texi | 16 | ||||
-rw-r--r-- | include/ChangeLog | 10 | ||||
-rw-r--r-- | include/elf/mips.h | 3 | ||||
-rw-r--r-- | include/opcode/mips.h | 39 | ||||
-rw-r--r-- | opcodes/ChangeLog | 28 | ||||
-rw-r--r-- | opcodes/mips-dis.c | 88 | ||||
-rw-r--r-- | opcodes/mips16-opc.c | 98 |
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, ®no) + && 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 }, |