MIPS/LD/testsuite: mips-elf-flags: Add MIPS ABI Flags handling
[deliverable/binutils-gdb.git] / opcodes / mips-dis.c
index 609e0ba489d6ba0b366fe14a861aefb6399a5268..b541e03b8522dcabbe8c3102fb68a1f23ea87f73 100644 (file)
@@ -1,5 +1,5 @@
 /* Print mips instructions for GDB, the GNU debugger, or for objdump.
-   Copyright (C) 1989-2016 Free Software Foundation, Inc.
+   Copyright (C) 1989-2017 Free Software Foundation, Inc.
    Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
 
    This file is part of the GNU opcodes library.
@@ -20,7 +20,7 @@
    MA 02110-1301, USA.  */
 
 #include "sysdep.h"
-#include "dis-asm.h"
+#include "disassemble.h"
 #include "libiberty.h"
 #include "opcode/mips.h"
 #include "opintl.h"
@@ -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_MIPS3, 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;
 }
 
@@ -847,11 +853,12 @@ set_default_mips_dis_options (struct disassemble_info *info)
       Elf_Internal_Ehdr *header = elf_elfheader (abfd);
       Elf_Internal_ABIFlags_v0 *abiflags = NULL;
 
-      /* We won't ever get here if !BFD64, because we won't then have
-        a MIPS/ELF BFD, however we need to guard against a link error
-        in a `--enable-targets=...' configuration with a 32-bit host,
-        where the MIPS target is a secondary.  */
-#ifdef BFD64
+      /* We won't ever get here if !HAVE_BFD_MIPS_ELF_GET_ABIFLAGS,
+        because we won't then have a MIPS/ELF BFD, however we need
+        to guard against a link error in a `--enable-targets=...'
+        configuration with a 32-bit host where the MIPS target is
+        a secondary, or with MIPS/ECOFF configurations.  */
+#ifdef HAVE_BFD_MIPS_ELF_GET_ABIFLAGS
       abiflags = bfd_mips_elf_get_abiflags (abfd);
 #endif
       /* If an ELF "newabi" binary, use the n32/(n)64 GPR names.  */
@@ -1280,9 +1287,10 @@ print_insn_arg (struct disassemble_info *info,
        pcrel_op = (const struct mips_pcrel_operand *) operand;
        info->target = mips_decode_pcrel_operand (pcrel_op, base_pc, uval);
 
-       /* Preserve the ISA bit for the GDB disassembler,
-          otherwise clear it.  */
-       if (info->flavour != bfd_target_unknown_flavour)
+       /* For jumps and branches clear the ISA bit except for
+          the GDB disassembler.  */
+       if (pcrel_op->include_isa_bit
+           && info->flavour != bfd_target_unknown_flavour)
          info->target &= -2;
 
        (*info->print_address_func) (info->target, info);
@@ -1460,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);
@@ -1573,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:
@@ -1639,7 +1652,7 @@ print_insn_args (struct disassemble_info *info,
              && s[2] == 'H'
              && opcode->name[strlen (opcode->name) - 1] == '0')
            {
-             /* Coprocessor register 0 with sel field (MT ASE).  */
+             /* Coprocessor register 0 with sel field.  */
              const struct mips_cp0sel_name *n;
              unsigned int reg, sel;
 
@@ -1822,6 +1835,7 @@ print_mips16_insn_arg (struct disassemble_info *info,
   const fprintf_ftype infprintf = info->fprintf_func;
   void *is = info->stream;
   const struct mips_operand *operand, *ext_operand;
+  unsigned short ext_size;
   unsigned int uval;
   bfd_vma baseaddr;
 
@@ -1926,29 +1940,30 @@ print_mips16_insn_arg (struct disassemble_info *info,
          info->data_size = 1 << int_op->shift;
        }
 
-      if (operand->size == 26)
-       uval = ((extend & 0x1f) << 21) | ((extend & 0x3e0) << 11) | insn;
-      else
+      ext_size = 0;
+      if (use_extend)
        {
-         /* Calculate the full field value.  */
-         uval = mips_extract_operand (operand, (extend << 16) | insn);
-         if (use_extend)
+         ext_operand = decode_mips16_operand (type, TRUE);
+         if (ext_operand != operand
+             || (operand->type == OP_INT && operand->lsb == 0
+                 && mips_opcode_32bit_p (opcode)))
            {
-             ext_operand = decode_mips16_operand (type, TRUE);
-             if (ext_operand != operand)
-               {
-                 operand = ext_operand;
-                 if (operand->size == 16)
-                   uval = (((extend & 0x1f) << 11) | (extend & 0x7e0)
-                           | (uval & 0x1f));
-                 else if (operand->size == 15)
-                   uval |= ((extend & 0xf) << 11) | (extend & 0x7f0);
-                 else
-                   uval = ((((extend >> 6) & 0x1f) | (extend & 0x20))
-                           & ((1U << operand->size) - 1));
-               }
+             ext_size = ext_operand->size;
+             operand = ext_operand;
            }
        }
+      if (operand->size == 26)
+       uval = ((extend & 0x1f) << 21) | ((extend & 0x3e0) << 11) | insn;
+      else if (ext_size == 16 || ext_size == 9)
+       uval = ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f);
+      else if (ext_size == 15)
+       uval = ((extend & 0xf) << 11) | (extend & 0x7f0) | (insn & 0xf);
+      else if (ext_size == 6)
+       uval = ((extend >> 6) & 0x1f) | (extend & 0x20);
+      else
+       uval = mips_extract_operand (operand, (extend << 16) | insn);
+      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
@@ -2106,6 +2124,9 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
     {
       enum match_kind match;
 
+      if (!opcode_is_member (op, mips_isa, mips_ase, mips_processor))
+       continue;
+
       if (op->pinfo == INSN_MACRO
          || (no_aliases && (op->pinfo2 & INSN2_ALIAS)))
        match = MATCH_NONE;
@@ -2125,8 +2146,17 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
        }
       else if ((first & 0xf800) == 0xf000
               && have_second
+              && !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;
 
@@ -2157,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.  */
@@ -2430,6 +2490,9 @@ print_mips_disassembler_options (FILE *stream)
 The following MIPS specific disassembler options are supported for use\n\
 with the -M switch (multiple options should be separated by commas):\n"));
 
+  fprintf (stream, _("\n\
+  no-aliases               Use canonical instruction forms.\n"));
+
   fprintf (stream, _("\n\
   msa                      Recognize MSA instructions.\n"));
 
This page took 0.029024 seconds and 4 git commands to generate.